diff options
Diffstat (limited to 'src')
117 files changed, 3153 insertions, 3301 deletions
diff --git a/src/etc/vim/after/syntax/rust.vim b/src/etc/vim/after/syntax/rust.vim index 75afe3d0368..1ab8394e565 100644 --- a/src/etc/vim/after/syntax/rust.vim +++ b/src/etc/vim/after/syntax/rust.vim @@ -11,10 +11,6 @@ syn match rustRightArrowHead contained ">" conceal cchar= syn match rustRightArrowTail contained "-" conceal cchar=⟶ syn match rustNiceOperator "->" contains=rustRightArrowHead,rustRightArrowTail -syn match rustLeftRightArrowHead contained ">" conceal cchar= -syn match rustLeftRightArrowTail contained "<-" conceal cchar=⟷ -syn match rustNiceOperator "<->" contains=rustLeftRightArrowHead,rustLeftRightArrowTail - syn match rustFatRightArrowHead contained ">" conceal cchar= syn match rustFatRightArrowTail contained "=" conceal cchar=⟹ syn match rustNiceOperator "=>" contains=rustFatRightArrowHead,rustFatRightArrowTail diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 3b5324f5cce..cd794df0a8d 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -15,7 +15,7 @@ syn keyword rustOperator as syn keyword rustKeyword break copy do drop extern syn keyword rustKeyword for if impl let log -syn keyword rustKeyword copy do drop extern +syn keyword rustKeyword copy do extern syn keyword rustKeyword for impl let log syn keyword rustKeyword loop mod once priv pub syn keyword rustKeyword return @@ -28,8 +28,8 @@ syn keyword rustStorage const mut ref static syn match rustIdentifier contains=rustIdentifierPrime "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained syn match rustFuncName "\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" display contained -" Reserved words -"syn keyword rustKeyword m32 m64 m128 f80 f16 f128 be " These are obsolete +" reserved +syn keyword rustKeyword be syn keyword rustType int uint float char bool u8 u16 u32 u64 f32 syn keyword rustType f64 i8 i16 i32 i64 str Self diff --git a/src/libcore/at_vec.rs b/src/libcore/at_vec.rs index d0f9a4ff90f..93bbf8fb662 100644 --- a/src/libcore/at_vec.rs +++ b/src/libcore/at_vec.rs @@ -149,7 +149,7 @@ pub fn from_elem<T:Copy>(n_elts: uint, t: T) -> @[T] { * Creates and initializes an immutable managed vector by moving all the * elements from an owned vector. */ -pub fn from_owned<T>(v: ~[T]) -> @[T] { +pub fn to_managed_consume<T>(v: ~[T]) -> @[T] { let mut av = @[]; unsafe { raw::reserve(&mut av, v.len()); @@ -164,7 +164,7 @@ pub fn from_owned<T>(v: ~[T]) -> @[T] { * Creates and initializes an immutable managed vector by copying all the * elements of a slice. */ -pub fn from_slice<T:Copy>(v: &[T]) -> @[T] { +pub fn to_managed<T:Copy>(v: &[T]) -> @[T] { from_fn(v.len(), |i| v[i]) } @@ -304,20 +304,20 @@ mod test { } #[test] - fn test_from_owned() { - assert!(from_owned::<int>(~[]) == @[]); - assert!(from_owned(~[true]) == @[true]); - assert!(from_owned(~[1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]); - assert!(from_owned(~[~"abc", ~"123"]) == @[~"abc", ~"123"]); - assert!(from_owned(~[~[42]]) == @[~[42]]); + fn test_to_managed_consume() { + assert!(to_managed_consume::<int>(~[]) == @[]); + assert!(to_managed_consume(~[true]) == @[true]); + assert!(to_managed_consume(~[1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]); + assert!(to_managed_consume(~[~"abc", ~"123"]) == @[~"abc", ~"123"]); + assert!(to_managed_consume(~[~[42]]) == @[~[42]]); } #[test] - fn test_from_slice() { - assert!(from_slice::<int>([]) == @[]); - assert!(from_slice([true]) == @[true]); - assert!(from_slice([1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]); - assert!(from_slice([@"abc", @"123"]) == @[@"abc", @"123"]); - assert!(from_slice([@[42]]) == @[@[42]]); + fn test_to_managed() { + assert!(to_managed::<int>([]) == @[]); + assert!(to_managed([true]) == @[true]); + assert!(to_managed([1, 2, 3, 4, 5]) == @[1, 2, 3, 4, 5]); + assert!(to_managed([@"abc", @"123"]) == @[@"abc", @"123"]); + assert!(to_managed([@[42]]) == @[@[42]]); } } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index cacde5535db..87e8d0525e5 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -21,10 +21,17 @@ Similar to a mutable option type, but friendlier. */ #[mutable] +#[deriving(Clone)] pub struct Cell<T> { priv value: Option<T> } +impl<T: DeepClone> DeepClone for Cell<T> { + fn deep_clone(&self) -> Cell<T> { + Cell{value: self.value.deep_clone()} + } +} + impl<T:cmp::Eq> cmp::Eq for Cell<T> { fn eq(&self, other: &Cell<T>) -> bool { (self.value) == (other.value) diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 9da970918b0..4d2b5998b44 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -22,18 +22,15 @@ by convention implementing the `Clone` trait and calling the */ +use core::kinds::Const; + pub trait Clone { - /// Return a deep copy of the owned object tree. Managed boxes are cloned with a shallow copy. + /// Return a deep copy of the owned object tree. Types with shared ownership like managed boxes + /// are cloned with a shallow copy. fn clone(&self) -> Self; } -impl Clone for () { - /// Return a copy of the value. - #[inline(always)] - fn clone(&self) -> () { () } -} - -impl<T:Clone> Clone for ~T { +impl<T: Clone> Clone for ~T { /// Return a deep copy of the owned box. #[inline(always)] fn clone(&self) -> ~T { ~(**self).clone() } @@ -51,10 +48,16 @@ impl<T> Clone for @mut T { fn clone(&self) -> @mut T { *self } } +impl<'self, T> Clone for &'self T { + /// Return a shallow copy of the borrowed pointer. + #[inline(always)] + fn clone(&self) -> &'self T { *self } +} + macro_rules! clone_impl( ($t:ty) => { impl Clone for $t { - /// Return a copy of the value. + /// Return a deep copy of the value. #[inline(always)] fn clone(&self) -> $t { *self } } @@ -77,28 +80,103 @@ clone_impl!(float) clone_impl!(f32) clone_impl!(f64) +clone_impl!(()) clone_impl!(bool) clone_impl!(char) +pub trait DeepClone { + /// Return a deep copy of the object tree. Types with shared ownership are also copied via a + /// deep copy, unlike `Clone`. + fn deep_clone(&self) -> Self; +} + +impl<T: DeepClone> DeepClone for ~T { + /// Return a deep copy of the owned box. + #[inline(always)] + fn deep_clone(&self) -> ~T { ~(**self).deep_clone() } +} + +// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` +impl<T: Const + DeepClone> DeepClone for @T { + /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing + /// a deep clone of a potentially cyclical type. + #[inline(always)] + fn deep_clone(&self) -> @T { @(**self).deep_clone() } +} + +// FIXME: #6525: should also be implemented for `T: Owned + DeepClone` +impl<T: Const + DeepClone> DeepClone for @mut T { + /// Return a deep copy of the managed box. The `Const` trait is required to prevent performing + /// a deep clone of a potentially cyclical type. + #[inline(always)] + fn deep_clone(&self) -> @mut T { @mut (**self).deep_clone() } +} + +macro_rules! deep_clone_impl( + ($t:ty) => { + impl DeepClone for $t { + /// Return a deep copy of the value. + #[inline(always)] + fn deep_clone(&self) -> $t { *self } + } + } +) + +deep_clone_impl!(int) +deep_clone_impl!(i8) +deep_clone_impl!(i16) +deep_clone_impl!(i32) +deep_clone_impl!(i64) + +deep_clone_impl!(uint) +deep_clone_impl!(u8) +deep_clone_impl!(u16) +deep_clone_impl!(u32) +deep_clone_impl!(u64) + +deep_clone_impl!(float) +deep_clone_impl!(f32) +deep_clone_impl!(f64) + +deep_clone_impl!(()) +deep_clone_impl!(bool) +deep_clone_impl!(char) + #[test] fn test_owned_clone() { - let a: ~int = ~5i; + let a = ~5i; let b: ~int = a.clone(); assert!(a == b); } #[test] fn test_managed_clone() { - let a: @int = @5i; + let a = @5i; let b: @int = a.clone(); assert!(a == b); } #[test] +fn test_managed_mut_deep_clone() { + let x = @mut 5i; + let y: @mut int = x.deep_clone(); + *x = 20; + assert_eq!(*y, 5); +} + +#[test] fn test_managed_mut_clone() { - let a: @mut int = @mut 5i; + let a = @mut 5i; let b: @mut int = a.clone(); assert!(a == b); *b = 10; assert!(a == b); } + +#[test] +fn test_borrowed_clone() { + let x = 5i; + let y: &int = &x; + let z: &int = (&y).clone(); + assert_eq!(*z, 5); +} diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 264b2a78965..d9912813cf9 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -17,7 +17,6 @@ use container::{Container, Mutable, Map, Set}; use cmp::{Eq, Equiv}; use hash::Hash; use old_iter::BaseIter; -use hash::Hash; use old_iter; use option::{None, Option, Some}; use rand::RngUtil; @@ -825,6 +824,10 @@ pub impl <T:Hash + Eq> HashSet<T> { fn consume(&mut self, f: &fn(T)) { self.map.consume(|k, _| f(k)) } + + fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool { + self.map.contains_key_equiv(value) + } } #[cfg(test)] diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index cfc9afb737c..ae4af3812d2 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -43,6 +43,8 @@ much easier to implement. #[cfg(not(stage0))] use cmp::Ord; #[cfg(not(stage0))] use option::{Option, Some, None}; #[cfg(not(stage0))] use vec::OwnedVector; +#[cfg(not(stage0))] use num::{One, Zero}; +#[cfg(not(stage0))] use ops::{Add, Mul}; #[cfg(stage0)] pub trait Times { @@ -212,6 +214,81 @@ pub fn min<T: Ord>(iter: &fn(f: &fn(T) -> bool) -> bool) -> Option<T> { result } +/** + * Reduce an iterator to an accumulated value. + * + * # Example: + * + * ~~~~ + * assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); + * ~~~~ + */ +#[cfg(not(stage0))] +#[inline] +pub fn fold<T, U>(start: T, iter: &fn(f: &fn(U) -> bool) -> bool, f: &fn(&mut T, U)) -> T { + let mut result = start; + for iter |x| { + f(&mut result, x); + } + result +} + +/** + * Reduce an iterator to an accumulated value. + * + * `fold_ref` is usable in some generic functions where `fold` is too lenient to type-check, but it + * forces the iterator to yield borrowed pointers. + * + * # Example: + * + * ~~~~ + * fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { + * fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x)) + * } + * ~~~~ + */ +#[cfg(not(stage0))] +#[inline] +pub fn fold_ref<T, U>(start: T, iter: &fn(f: &fn(&U) -> bool) -> bool, f: &fn(&mut T, &U)) -> T { + let mut result = start; + for iter |x| { + f(&mut result, x); + } + result +} + +/** + * Return the sum of the items yielding by an iterator. + * + * # Example: + * + * ~~~~ + * let xs: ~[int] = ~[1, 2, 3, 4]; + * assert_eq!(do sum |f| { xs.each(f) }, 10); + * ~~~~ + */ +#[cfg(not(stage0))] +#[inline(always)] +pub fn sum<T: Zero + Add<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { + fold_ref(Zero::zero::<T>(), iter, |a, x| *a = a.add(x)) +} + +/** + * Return the product of the items yielded by an iterator. + * + * # Example: + * + * ~~~~ + * let xs: ~[int] = ~[1, 2, 3, 4]; + * assert_eq!(do product |f| { xs.each(f) }, 24); + * ~~~~ + */ +#[cfg(not(stage0))] +#[inline(always)] +pub fn product<T: One + Mul<T, T>>(iter: &fn(f: &fn(&T) -> bool) -> bool) -> T { + fold_ref(One::one::<T>(), iter, |a, x| *a = a.mul(x)) +} + #[cfg(test)] mod tests { use super::*; @@ -254,4 +331,33 @@ mod tests { let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; assert_eq!(min(|f| xs.each(f)).unwrap(), &-5); } + + #[test] + fn test_fold() { + assert_eq!(fold(0i, |f| int::range(1, 5, f), |a, x| *a += x), 10); + } + + #[test] + fn test_sum() { + let xs: ~[int] = ~[1, 2, 3, 4]; + assert_eq!(do sum |f| { xs.each(f) }, 10); + } + + #[test] + fn test_empty_sum() { + let xs: ~[int] = ~[]; + assert_eq!(do sum |f| { xs.each(f) }, 0); + } + + #[test] + fn test_product() { + let xs: ~[int] = ~[1, 2, 3, 4]; + assert_eq!(do product |f| { xs.each(f) }, 24); + } + + #[test] + fn test_empty_product() { + let xs: ~[int] = ~[]; + assert_eq!(do product |f| { xs.each(f) }, 1); + } } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index af30e87bb0c..4a3ec3528f2 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -414,6 +414,12 @@ impl Trigonometric for f32 { #[inline(always)] fn atan2(&self, other: f32) -> f32 { atan2(*self, other) } + + /// Simultaneously computes the sine and cosine of the number + #[inline(always)] + fn sin_cos(&self) -> (f32, f32) { + (self.sin(), self.cos()) + } } impl Exponential for f32 { diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 240d84b8403..e370f43a003 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -426,6 +426,12 @@ impl Trigonometric for f64 { #[inline(always)] fn atan2(&self, other: f64) -> f64 { atan2(*self, other) } + + /// Simultaneously computes the sine and cosine of the number + #[inline(always)] + fn sin_cos(&self) -> (f64, f64) { + (self.sin(), self.cos()) + } } impl Exponential for f64 { diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 8b3c7b1e79e..681aafaab88 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -530,6 +530,14 @@ impl Trigonometric for float { fn atan2(&self, other: float) -> float { (*self as f64).atan2(other as f64) as float } + + /// Simultaneously computes the sine and cosine of the number + #[inline(always)] + fn sin_cos(&self) -> (float, float) { + match (*self as f64).sin_cos() { + (s, c) => (s as float, c as float) + } + } } impl Exponential for float { diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index a15a8f1a215..96b302d3174 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -118,6 +118,7 @@ pub trait Trigonometric { fn acos(&self) -> Self; fn atan(&self) -> Self; fn atan2(&self, other: Self) -> Self; + fn sin_cos(&self) -> (Self, Self); } pub trait Exponential { @@ -395,8 +396,7 @@ pub trait FromStrRadix { /// - If code written to use this function doesn't care about it, it's /// probably assuming that `x^0` always equals `1`. /// -pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>( - radix: uint, pow: uint) -> T { +pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>(radix: uint, pow: uint) -> T { let _0: T = Zero::zero(); let _1: T = One::one(); @@ -404,7 +404,7 @@ pub fn pow_with_uint<T:NumCast+One+Zero+Copy+Div<T,T>+Mul<T,T>>( if radix == 0u { return _0; } let mut my_pow = pow; let mut total = _1; - let mut multiplier = cast(radix as int); + let mut multiplier = cast(radix); while (my_pow > 0u) { if my_pow % 2u == 1u { total *= multiplier; @@ -421,13 +421,13 @@ pub fn test_num<T:Num + NumCast>(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.div(&two), cast(5)); + assert_eq!(ten.div(&two), cast(5)); assert_eq!(ten.rem(&two), cast(0)); assert_eq!(ten.add(&two), ten + two); assert_eq!(ten.sub(&two), ten - two); assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); + assert_eq!(ten.div(&two), ten / two); assert_eq!(ten.rem(&two), ten % two); } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 9aaa2921fe7..5aee3077e48 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -49,6 +49,7 @@ use num::Zero; use old_iter::{BaseIter, MutableIter, ExtendedIter}; use old_iter; use str::StrSlice; +use clone::DeepClone; #[cfg(test)] use str; @@ -59,6 +60,15 @@ pub enum Option<T> { Some(T), } +impl<T: DeepClone> DeepClone for Option<T> { + fn deep_clone(&self) -> Option<T> { + match *self { + Some(ref x) => Some(x.deep_clone()), + None => None + } + } +} + impl<T:Ord> Ord for Option<T> { fn lt(&self, other: &Option<T>) -> bool { match (self, other) { diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 61c80c89894..72e62c80392 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -291,6 +291,33 @@ pub fn setenv(n: &str, v: &str) { } } +/// Remove a variable from the environment entirely +pub fn unsetenv(n: &str) { + #[cfg(unix)] + fn _unsetenv(n: &str) { + unsafe { + do with_env_lock { + do str::as_c_str(n) |nbuf| { + libc::funcs::posix01::unistd::unsetenv(nbuf); + } + } + } + } + #[cfg(windows)] + fn _unsetenv(n: &str) { + unsafe { + do with_env_lock { + use os::win32::as_utf16_p; + do as_utf16_p(n) |nbuf| { + libc::SetEnvironmentVariableW(nbuf, ptr::null()); + } + } + } + } + + _unsetenv(n); +} + pub fn fdopen(fd: c_int) -> *FILE { unsafe { return do as_c_charp("r") |modebuf| { @@ -1414,7 +1441,7 @@ mod tests { use option::Some; use option; use os::{as_c_charp, env, getcwd, getenv, make_absolute, real_args}; - use os::{remove_file, setenv}; + use os::{remove_file, setenv, unsetenv}; use os; use path::Path; use rand::RngUtil; @@ -1451,6 +1478,14 @@ mod tests { } #[test] + fn test_unsetenv() { + let n = make_rand_name(); + setenv(n, ~"VALUE"); + unsetenv(n); + assert!(getenv(n) == option::None); + } + + #[test] #[ignore(cfg(windows))] #[ignore] fn test_setenv_overwrite() { diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 22172db9302..4ed648161fc 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -27,7 +27,7 @@ pub use io::{print, println}; /* Reexported types and traits */ -pub use clone::Clone; +pub use clone::{Clone, DeepClone}; pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; diff --git a/src/libcore/rt/stack.rs b/src/libcore/rt/stack.rs index 019540ce76b..cab9c3390b2 100644 --- a/src/libcore/rt/stack.rs +++ b/src/libcore/rt/stack.rs @@ -46,9 +46,7 @@ pub impl StackSegment { /// Point one word beyond the high end of the allocated stack fn end(&self) -> *uint { - unsafe { - vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint - } + vec::raw::to_ptr(self.buf).offset(self.buf.len()) as *uint } } diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs index 93cafb83588..99a5252c88a 100644 --- a/src/libcore/rt/uv/mod.rs +++ b/src/libcore/rt/uv/mod.rs @@ -309,7 +309,7 @@ pub type Buf = uvll::uv_buf_t; /// Borrow a slice to a Buf pub fn slice_to_uv_buf(v: &[u8]) -> Buf { - let data = unsafe { vec::raw::to_ptr(v) }; + let data = vec::raw::to_ptr(v); unsafe { uvll::buf_init(data, v.len()) } } diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs index b8c0c4e4a92..1636abedf7a 100644 --- a/src/libcore/unstable/intrinsics.rs +++ b/src/libcore/unstable/intrinsics.rs @@ -8,62 +8,119 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -An attempt to move all intrinsic declarations to a single place, -as mentioned in #3369 -The intrinsics are defined in librustc/middle/trans/foreign.rs. +/*! rustc compiler intrinsics. + +The corresponding definitions are in librustc/middle/trans/foreign.rs. + +# Atomics + +The atomic intrinsics provide common atomic operations on machine +words, with multiple possible memory orderings. They obey the same +semantics as C++0x. See the LLVM documentation on [[atomics]]. + +[atomics]: http://llvm.org/docs/Atomics.html + +A quick refresher on memory ordering: + +* Acquire - a barrier for aquiring a lock. Subsequent reads and writes + take place after the barrier. +* Release - a barrier for releasing a lock. Preceding reads and writes + take place before the barrier. +* Sequentially consistent - sequentially consistent operations are + guaranteed to happen in order. This is the standard mode for working + with atomic types and is equivalent to Java's `volatile`. + */ #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { + + /// Atomic compare and exchange, sequentially consistent. pub fn atomic_cxchg(dst: &mut int, old: int, src: int) -> int; + /// Atomic compare and exchange, acquire ordering. pub fn atomic_cxchg_acq(dst: &mut int, old: int, src: int) -> int; + /// Atomic compare and exchange, release ordering. pub fn atomic_cxchg_rel(dst: &mut int, old: int, src: int) -> int; + /// Atomic load, sequentially consistent. #[cfg(not(stage0))] pub fn atomic_load(src: &int) -> int; + /// Atomic load, acquire ordering. #[cfg(not(stage0))] pub fn atomic_load_acq(src: &int) -> int; + /// Atomic store, sequentially consistent. #[cfg(not(stage0))] pub fn atomic_store(dst: &mut int, val: int); + /// Atomic store, release ordering. #[cfg(not(stage0))] pub fn atomic_store_rel(dst: &mut int, val: int); + /// Atomic exchange, sequentially consistent. pub fn atomic_xchg(dst: &mut int, src: int) -> int; + /// Atomic exchange, acquire ordering. pub fn atomic_xchg_acq(dst: &mut int, src: int) -> int; + /// Atomic exchange, release ordering. pub fn atomic_xchg_rel(dst: &mut int, src: int) -> int; + /// Atomic addition, sequentially consistent. pub fn atomic_xadd(dst: &mut int, src: int) -> int; + /// Atomic addition, acquire ordering. pub fn atomic_xadd_acq(dst: &mut int, src: int) -> int; + /// Atomic addition, release ordering. pub fn atomic_xadd_rel(dst: &mut int, src: int) -> int; + /// Atomic subtraction, sequentially consistent. pub fn atomic_xsub(dst: &mut int, src: int) -> int; + /// Atomic subtraction, acquire ordering. pub fn atomic_xsub_acq(dst: &mut int, src: int) -> int; + /// Atomic subtraction, release ordering. pub fn atomic_xsub_rel(dst: &mut int, src: int) -> int; + /// The size of a type in bytes. + /// + /// This is the exact number of bytes in memory taken up by a + /// value of the given type. In other words, a memset of this size + /// would *exactly* overwrite a value. When laid out in vectors + /// and structures there may be additional padding between + /// elements. pub fn size_of<T>() -> uint; + /// Move a value to a memory location containing a value. + /// + /// Drop glue is run on the destination, which must contain a + /// valid Rust value. pub fn move_val<T>(dst: &mut T, src: T); + + /// Move a value to an uninitialized memory location. + /// + /// Drop glue is not run on the destination. pub fn move_val_init<T>(dst: &mut T, src: T); pub fn min_align_of<T>() -> uint; pub fn pref_align_of<T>() -> uint; + /// Get a static pointer to a type descriptor. pub fn get_tydesc<T>() -> *(); - /// init is unsafe because it returns a zeroed-out datum, + /// Create a value initialized to zero. + /// + /// `init` is unsafe because it returns a zeroed-out datum, /// which is unsafe unless T is POD. We don't have a POD - /// kind yet. (See #4074) + /// kind yet. (See #4074). pub unsafe fn init<T>() -> T; + /// Create an uninitialized value. #[cfg(not(stage0))] pub unsafe fn uninit<T>() -> T; - /// forget is unsafe because the caller is responsible for - /// ensuring the argument is deallocated already + /// Move a value out of scope without running drop glue. + /// + /// `forget` is unsafe because the caller is responsible for + /// ensuring the argument is deallocated already. pub unsafe fn forget<T>(_: T) -> (); + /// Returns `true` if a type requires drop glue. pub fn needs_drop<T>() -> bool; // XXX: intrinsic uses legacy modes and has reference to TyDesc @@ -72,9 +129,12 @@ pub extern "rust-intrinsic" { // XXX: intrinsic uses legacy modes //fn frame_address(f: &once fn(*u8)); + /// Get the address of the `__morestack` stack growth function. pub fn morestack_addr() -> *(); + /// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic. pub fn memmove32(dst: *mut u8, src: *u8, size: u32); + /// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic. pub fn memmove64(dst: *mut u8, src: *u8, size: u64); pub fn sqrtf32(x: f32) -> f32; diff --git a/src/libcore/util.rs b/src/libcore/util.rs index d270fb23aaa..e5067fb90bc 100644 --- a/src/libcore/util.rs +++ b/src/libcore/util.rs @@ -138,8 +138,8 @@ pub enum Void { } pub impl Void { /// A utility function for ignoring this uninhabited type - fn uninhabited(&self) -> ! { - match *self { + fn uninhabited(self) -> ! { + match self { // Nothing to match on } } @@ -177,7 +177,8 @@ pub fn unreachable() -> ! { #[cfg(test)] mod tests { use option::{None, Some}; - use util::{NonCopyable, id, replace, swap}; + use util::{Void, NonCopyable, id, replace, swap}; + use either::{Either, Left, Right}; #[test] pub fn identity_crisis() { @@ -202,4 +203,12 @@ mod tests { assert!(x.is_none()); assert!(y.is_some()); } + #[test] + pub fn test_uninhabited() { + let could_only_be_coin : Either <Void, ()> = Right (()); + match could_only_be_coin { + Right (coin) => coin, + Left (is_void) => is_void.uninhabited () + } + } } diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 0fb697b686f..4c6e0791ba2 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -1445,6 +1445,46 @@ pub fn reverse<T>(v: &mut [T]) { } } +/** + * Reverse part of a vector in place. + * + * Reverse the elements in the vector between `start` and `end - 1`. + * + * If either start or end do not represent valid positions in the vector, the + * vector is returned unchanged. + * + * # Arguments + * + * * `v` - The mutable vector to be modified + * + * * `start` - Index of the first element of the slice + * + * * `end` - Index one past the final element to be reversed. + * + * # Example + * + * Assume a mutable vector `v` contains `[1,2,3,4,5]`. After the call: + * + * ~~~ + * + * reverse_part(v, 1, 4); + * + * ~~~ + * + * `v` now contains `[1,4,3,2,5]`. + */ +pub fn reverse_part<T>(v: &mut [T], start: uint, end : uint) { + let sz = v.len(); + if start >= sz || end > sz { return; } + let mut i = start; + let mut j = end - 1; + while i < j { + vec::swap(v, i, j); + i += 1; + j -= 1; + } +} + /// Returns a vector with the order of elements reversed pub fn reversed<T:Copy>(v: &const [T]) -> ~[T] { let mut rs: ~[T] = ~[]; @@ -1739,29 +1779,49 @@ pub fn each2_mut<U, T>(v1: &mut [U], v2: &mut [T], f: &fn(u: &mut U, t: &mut T) * * The total number of permutations produced is `len(v)!`. If `v` contains * repeated elements, then some permutations are repeated. + * + * See [Algorithms to generate + * permutations](http://en.wikipedia.org/wiki/Permutation). + * + * # Arguments + * + * * `values` - A vector of values from which the permutations are + * chosen + * + * * `fun` - The function to iterate over the combinations */ -#[cfg(not(stage0))] -pub fn each_permutation<T:Copy>(v: &[T], put: &fn(ts: &[T]) -> bool) -> bool { - let ln = len(v); - if ln <= 1 { - put(v); - } else { - // This does not seem like the most efficient implementation. You - // could make far fewer copies if you put your mind to it. - let mut i = 0u; - while i < ln { - let elt = v[i]; - let mut rest = slice(v, 0u, i).to_vec(); - rest.push_all(const_slice(v, i+1u, ln)); - for each_permutation(rest) |permutation| { - if !put(append(~[elt], permutation)) { - return false; - } - } - i += 1u; +pub fn each_permutation<T:Copy>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> bool { + let length = values.len(); + let mut permutation = vec::from_fn(length, |i| values[i]); + if length <= 1 { + fun(permutation); + return true; + } + let mut indices = vec::from_fn(length, |i| i); + loop { + if !fun(permutation) { return true; } + // find largest k such that indices[k] < indices[k+1] + // if no such k exists, all permutations have been generated + let mut k = length - 2; + while k > 0 && indices[k] >= indices[k+1] { + k -= 1; + } + if k == 0 && indices[0] > indices[1] { return true; } + // find largest l such that indices[k] < indices[l] + // k+1 is guaranteed to be such + let mut l = length - 1; + while indices[k] >= indices[l] { + l -= 1; + } + // swap indices[k] and indices[l]; sort indices[k+1..] + // (they're just reversed) + vec::swap(indices, k, l); + reverse_part(indices, k+1, length); + // fixup permutation based on indices + for uint::range(k, length) |i| { + permutation[i] = values[indices[i]]; } } - return true; } /** @@ -2546,23 +2606,29 @@ pub mod raw { * would also make any pointers to it invalid. */ #[inline(always)] - pub unsafe fn to_ptr<T>(v: &[T]) -> *T { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) + pub fn to_ptr<T>(v: &[T]) -> *T { + unsafe { + let repr: **SliceRepr = transmute(&v); + transmute(&((**repr).data)) + } } /** see `to_ptr()` */ #[inline(always)] - pub unsafe fn to_const_ptr<T>(v: &const [T]) -> *const T { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) + pub fn to_const_ptr<T>(v: &const [T]) -> *const T { + unsafe { + let repr: **SliceRepr = transmute(&v); + transmute(&((**repr).data)) + } } /** see `to_ptr()` */ #[inline(always)] - pub unsafe fn to_mut_ptr<T>(v: &mut [T]) -> *mut T { - let repr: **SliceRepr = transmute(&v); - transmute(&((**repr).data)) + pub fn to_mut_ptr<T>(v: &mut [T]) -> *mut T { + unsafe { + let repr: **SliceRepr = transmute(&v); + transmute(&((**repr).data)) + } } /** @@ -4725,6 +4791,53 @@ mod tests { } #[test] + fn test_reverse_part() { + let mut values = [1,2,3,4,5]; + reverse_part(values,1,4); + assert_eq!(values, [1,4,3,2,5]); + } + + #[test] + fn test_permutations0() { + let values = []; + let mut v : ~[~[int]] = ~[]; + for each_permutation(values) |p| { + v.push(p.to_owned()); + } + assert_eq!(v, ~[~[]]); + } + + #[test] + fn test_permutations1() { + let values = [1]; + let mut v : ~[~[int]] = ~[]; + for each_permutation(values) |p| { + v.push(p.to_owned()); + } + assert_eq!(v, ~[~[1]]); + } + + #[test] + fn test_permutations2() { + let values = [1,2]; + let mut v : ~[~[int]] = ~[]; + for each_permutation(values) |p| { + v.push(p.to_owned()); + } + assert_eq!(v, ~[~[1,2],~[2,1]]); + } + + #[test] + fn test_permutations3() { + let values = [1,2,3]; + let mut v : ~[~[int]] = ~[]; + for each_permutation(values) |p| { + v.push(p.to_owned()); + } + assert_eq!(v, ~[~[1,2,3],~[1,3,2],~[2,1,3],~[2,3,1],~[3,1,2],~[3,2,1]]); + } + + #[test] fn test_each_val() { use old_iter::CopyableNonstrictIter; let mut i = 0; diff --git a/src/librustc/README.txt b/src/librustc/README.txt index 487a7927d27..6d4a8157f11 100644 --- a/src/librustc/README.txt +++ b/src/librustc/README.txt @@ -35,19 +35,19 @@ ASTs -- are in a separate crate called "syntax", whose files are in ./../libsyntax, where . is the current directory (that is, the parent directory of front/, middle/, back/, and so on). -The entry-point for the compiler is main() in driver/rustc.rs, and +The entry-point for the compiler is main() in rustc.rc, and this file sequences the various parts together. The 3 central data structures: ------------------------------ -#1: ../libsyntax/ast.rs defines the AST. The AST is treated as immutable +#1: ./../libsyntax/ast.rs defines the AST. The AST is treated as immutable after parsing, but it depends on mutable context data structures (mainly hash maps) to give it meaning. - Many -- though not all -- nodes within this data structure are - wrapped in the type spanned<T>, meaning that the front-end has + wrapped in the type `spanned<T>`, meaning that the front-end has marked the input coordinates of that node. The member .node is the data itself, the member .span is the input location (file, line, column; both low and high). @@ -78,7 +78,7 @@ Control and information flow within the compiler: - main() in rustc.rc assumes control on startup. Options are parsed, platform is detected, etc. -- libsyntax/parse/parser.rs parses the input files and produces an AST +- ./../libsyntax/parse/parser.rs parses the input files and produces an AST that represents the input crate. - Multiple middle-end passes (middle/resolve.rs, middle/typeck.rs) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 0e2739e40a9..92d3a451559 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -171,7 +171,6 @@ pub mod write { use back::link::{output_type_assembly, output_type_bitcode}; use back::link::{output_type_exe, output_type_llvm_assembly}; use back::link::{output_type_object}; - use back::link::output_type; use driver::session::Session; use driver::session; use lib::llvm::llvm; diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 0e37653e5c4..99ffa8cc94a 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -22,6 +22,7 @@ use middle; use util::common::time; use util::ppaux; +use core::hashmap::HashMap; use core::int; use core::io; use core::os; @@ -200,9 +201,6 @@ pub fn compile_rest(sess: Session, crate = time(time_passes, ~"core injection", || front::core_inject::maybe_inject_libcore_ref(sess, crate)); - time(time_passes, ~"building lint settings table", || - lint::build_settings_crate(sess, crate)); - let ast_map = time(time_passes, ~"ast indexing", || syntax::ast_map::map_crate(sess.diagnostic(), crate)); @@ -709,7 +707,6 @@ pub fn build_session_(sopts: @session::options, &sopts.maybe_sysroot, sopts.target_triple, /*bad*/copy sopts.addl_lib_search_paths); - let lint_settings = lint::mk_lint_settings(); @Session_ { targ_cfg: target_cfg, opts: sopts, @@ -723,7 +720,7 @@ pub fn build_session_(sopts: @session::options, filesearch: filesearch, building_library: @mut false, working_dir: os::getcwd(), - lint_settings: lint_settings + lints: @mut HashMap::new(), } } diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 16eec0b10de..6fba5ec8d3a 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -26,6 +26,8 @@ use syntax::{ast, codemap}; use syntax::abi; use syntax; +use core::hashmap::HashMap; + #[deriving(Eq)] pub enum os { os_win32, os_macos, os_linux, os_android, os_freebsd, } @@ -170,7 +172,7 @@ pub struct Session_ { filesearch: @filesearch::FileSearch, building_library: @mut bool, working_dir: Path, - lint_settings: lint::LintSettings + lints: @mut HashMap<ast::node_id, ~[(lint::lint, codemap::span, ~str)]>, } pub type Session = @Session_; @@ -221,24 +223,12 @@ pub impl Session_ { fn unimpl(@self, msg: &str) -> ! { self.span_diagnostic.handler().unimpl(msg) } - fn span_lint_level(@self, level: lint::level, sp: span, msg: &str) { - match level { - lint::allow => { }, - lint::warn => self.span_warn(sp, msg), - lint::deny | lint::forbid => { - self.span_err(sp, msg); - } + fn add_lint(@self, lint: lint::lint, id: ast::node_id, sp: span, msg: ~str) { + match self.lints.find_mut(&id) { + Some(arr) => { arr.push((lint, sp, msg)); return; } + None => {} } - } - fn span_lint(@self, lint_mode: lint::lint, - expr_id: ast::node_id, - item_id: ast::node_id, - span: span, - msg: &str) { - let level = lint::get_lint_settings_level( - self.lint_settings, lint_mode, expr_id, item_id); - let msg = fmt!("%s [-W %s]", msg, lint::get_lint_name(lint_mode)); - self.span_lint_level(level, span, msg); + self.lints.insert(id, ~[(lint, sp, msg)]); } fn next_node_id(@self) -> ast::node_id { return syntax::parse::next_node_id(self.parse_sess); diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index ad40faebe06..d06bf1480c9 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1566,6 +1566,7 @@ pub mod llvm { /* Atomic Operations */ pub unsafe fn LLVMBuildAtomicLoad(B: BuilderRef, PointerVal: ValueRef, + Name: *c_char, Order: AtomicOrdering) -> ValueRef; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index e6b8432854d..5a0820202a9 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -234,14 +234,13 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id, } } -// Given a def_id for an impl or class, return the traits it implements, -// or the empty vector if it's not for an impl or for a class that implements -// traits -pub fn get_impl_traits(tcx: ty::ctxt, - def: ast::def_id) -> ~[@ty::TraitRef] { +// Given a def_id for an impl, return the trait it implements, +// if there is one. +pub fn get_impl_trait(tcx: ty::ctxt, + def: ast::def_id) -> Option<@ty::TraitRef> { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_impl_traits(cdata, def.node, tcx) + decoder::get_impl_trait(cdata, def.node, tcx) } pub fn get_impl_method(cstore: @mut cstore::CStore, diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 2592875cd57..43073728e83 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -415,19 +415,20 @@ pub fn get_type_param_count(data: @~[u8], id: ast::node_id) -> uint { item_ty_param_count(lookup_item(id, data)) } -pub fn get_impl_traits(cdata: cmd, +pub fn get_impl_trait(cdata: cmd, id: ast::node_id, - tcx: ty::ctxt) -> ~[@ty::TraitRef] + tcx: ty::ctxt) -> Option<@ty::TraitRef> { let item_doc = lookup_item(id, cdata.data); - let mut results = ~[]; + let mut result = None; for reader::tagged_docs(item_doc, tag_item_trait_ref) |tp| { let trait_ref = @parse_trait_ref_data(tp.data, cdata.cnum, tp.start, tcx, |_, did| translate_def_id(cdata, did)); - results.push(trait_ref); + result = Some(trait_ref); + break; }; - results + result } pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 151ccad88ea..55a0755f5e3 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -470,12 +470,14 @@ fn parse_closure_ty(st: @mut PState, conv: conv_did) -> ty::ClosureTy { let purity = parse_purity(next(st)); let onceness = parse_onceness(next(st)); let region = parse_region(st); + let bounds = parse_bounds(st, conv); let sig = parse_sig(st, conv); ty::ClosureTy { purity: purity, sigil: sigil, onceness: onceness, region: region, + bounds: bounds.builtin_bounds, sig: sig } } @@ -540,10 +542,10 @@ pub fn parse_type_param_def_data(data: @~[u8], start: uint, fn parse_type_param_def(st: @mut PState, conv: conv_did) -> ty::TypeParameterDef { ty::TypeParameterDef {def_id: parse_def(st, NominalType, conv), - bounds: parse_bounds(st, conv)} + bounds: @parse_bounds(st, conv)} } -fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds { +fn parse_bounds(st: @mut PState, conv: conv_did) -> ty::ParamBounds { let mut param_bounds = ty::ParamBounds { builtin_bounds: ty::EmptyBuiltinBounds(), trait_bounds: ~[] @@ -566,7 +568,7 @@ fn parse_bounds(st: @mut PState, conv: conv_did) -> @ty::ParamBounds { param_bounds.trait_bounds.push(@parse_trait_ref(st, conv)); } '.' => { - return @param_bounds; + return param_bounds; } _ => { fail!("parse_bounds: bad bounds") diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 2cb95e1a2fc..5f799f49946 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -380,6 +380,9 @@ fn enc_closure_ty(w: @io::Writer, cx: @ctxt, ft: &ty::ClosureTy) { enc_purity(w, ft.purity); enc_onceness(w, ft.onceness); enc_region(w, cx, ft.region); + let bounds = ty::ParamBounds {builtin_bounds: ft.bounds, + trait_bounds: ~[]}; + enc_bounds(w, cx, &bounds); enc_fn_sig(w, cx, &ft.sig); } @@ -392,7 +395,7 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { enc_ty(w, cx, fsig.output); } -fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @ty::ParamBounds) { +fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: &ty::ParamBounds) { for bs.builtin_bounds.each |bound| { match bound { ty::BoundOwned => w.write_char('S'), diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2996c4c8476..209a14942e9 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1108,7 +1108,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, dcx.tcx.adjustments.insert(id, adj); } else if tag == (c::tag_table_capture_map as uint) { let cvars = - at_vec::from_owned( + at_vec::to_managed_consume( val_dsr.read_to_vec( |val_dsr| val_dsr.read_capture_var(xcx))); dcx.maps.capture_map.insert(id, cvars); diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 330d60a59d3..e377bebcc26 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -93,7 +93,7 @@ impl GuaranteeLifetimeContext { let omit_root = ( ptr_mutbl == m_imm && self.bccx.is_subregion_of(self.loan_region, base_scope) && - base.mutbl.is_immutable() && + self.is_rvalue_or_immutable(base) && !self.is_moved(base) ); @@ -168,6 +168,19 @@ impl GuaranteeLifetimeContext { } } + fn is_rvalue_or_immutable(&self, + cmt: mc::cmt) -> bool { + //! We can omit the root on an `@T` value if the location + //! that holds the box is either (1) an rvalue, in which case + //! it is in a non-user-accessible temporary, or (2) an immutable + //! lvalue. + + cmt.mutbl.is_immutable() || match cmt.guarantor().cat { + mc::cat_rvalue => true, + _ => false + } + } + fn check_root(&self, cmt_deref: mc::cmt, cmt_base: mc::cmt, diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index 41e29132155..872ad83b739 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -20,8 +20,7 @@ use syntax::{ast, ast_util, visit}; // A vector of defs representing the free variables referred to in a function. // (The def_upvar will already have been stripped). -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub struct freevar_entry { def: ast::def, //< The variable being accessed free. span: span //< First span where it is accessed (there can be multiple) diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 7ea0840880c..591b196bd6f 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use driver::session::Session; use driver::session; use middle::ty; use middle::pat_util; @@ -19,7 +18,7 @@ use std::smallintmap::SmallIntMap; use syntax::attr; use syntax::codemap::span; use syntax::codemap; -use syntax::{ast, visit}; +use syntax::{ast, visit, ast_util}; /** * A 'lint' check is a kind of miscellaneous constraint that a user _might_ @@ -28,18 +27,34 @@ use syntax::{ast, visit}; * other phases of the compiler, which are generally required to hold in order * to compile the program at all. * - * We also build up a table containing information about lint settings, in - * order to allow other passes to take advantage of the lint attribute - * infrastructure. To save space, the table is keyed by the id of /items/, not - * of every expression. When an item has the default settings, the entry will - * be omitted. If we start allowing lint attributes on expressions, we will - * start having entries for expressions that do not share their enclosing - * items settings. + * The lint checking is all consolidated into one pass which runs just before + * translation to LLVM bytecode. Throughout compilation, lint warnings can be + * added via the `add_lint` method on the Session structure. This requires a + * span and an id of the node that the lint is being added to. The lint isn't + * actually emitted at that time because it is unknown what the actual lint + * level at that location is. * - * This module then, exports two passes: one that populates the lint - * settings table in the session and is run early in the compile process, and - * one that does a variety of lint checks, and is run late in the compile - * process. + * To actually emit lint warnings/errors, a separate pass is used just before + * translation. A context keeps track of the current state of all lint levels. + * Upon entering a node of the ast which can modify the lint settings, the + * previous lint state is pushed onto a stack and the ast is then recursed upon. + * As the ast is traversed, this keeps track of the current lint level for all + * lint attributes. + * + * At each node of the ast which can modify lint attributes, all known lint + * passes are also applied. Each lint pass is a visit::vt<()> structure. These + * visitors are constructed via the lint_*() functions below. There are also + * some lint checks which operate directly on ast nodes (such as @ast::item), + * and those are organized as check_item_*(). Each visitor added to the lint + * context is modified to stop once it reaches a node which could alter the lint + * levels. This means that everything is looked at once and only once by every + * lint pass. + * + * With this all in place, to add a new lint warning, all you need to do is to + * either invoke `add_lint` on the session at the appropriate time, or write a + * lint pass in this module which is just an ast visitor. The context used when + * traversing the ast has a `span_lint` method which only needs the span of the + * item that's being warned about. */ #[deriving(Eq)] @@ -86,7 +101,20 @@ struct LintSpec { default: level } -pub type LintDict = @HashMap<~str, LintSpec>; +pub type LintDict = HashMap<~str, LintSpec>; + +enum AttributedNode<'self> { + Item(@ast::item), + Method(&'self ast::method), + Crate(@ast::crate), +} + +#[deriving(Eq)] +enum LintSource { + Node(span), + Default, + CommandLine +} static lint_table: &'static [(&'static str, LintSpec)] = &[ ("ctypes", @@ -225,82 +253,90 @@ pub fn get_lint_dict() -> LintDict { for lint_table.each|&(k, v)| { map.insert(k.to_str(), v); } - return @map; -} - -pub fn get_lint_name(lint_mode: lint) -> ~str { - for lint_table.each |&(name, spec)| { - if spec.lint == lint_mode { - return name.to_str(); - } - } - fail!(); -} -// This is a highly not-optimal set of data structure decisions. -type LintModes = @mut SmallIntMap<level>; -type LintModeMap = @mut HashMap<ast::node_id, LintModes>; - -// settings_map maps node ids of items with non-default lint settings -// to their settings; default_settings contains the settings for everything -// not in the map. -pub struct LintSettings { - default_settings: LintModes, - settings_map: LintModeMap -} - -pub fn mk_lint_settings() -> LintSettings { - LintSettings { - default_settings: @mut SmallIntMap::new(), - settings_map: @mut HashMap::new() - } -} - -pub fn get_lint_level(modes: LintModes, lint: lint) -> level { - match modes.find(&(lint as uint)) { - Some(&c) => c, - None => allow - } -} - -pub fn get_lint_settings_level(settings: LintSettings, - lint_mode: lint, - _expr_id: ast::node_id, - item_id: ast::node_id) - -> level { - match settings.settings_map.find(&item_id) { - Some(&modes) => get_lint_level(modes, lint_mode), - None => get_lint_level(settings.default_settings, lint_mode) - } -} - -// This is kind of unfortunate. It should be somewhere else, or we should use -// a persistent data structure... -fn clone_lint_modes(modes: LintModes) -> LintModes { - @mut (copy *modes) + return map; } struct Context { - dict: LintDict, - curr: LintModes, - is_default: bool, - sess: Session + // All known lint modes (string versions) + dict: @LintDict, + // Current levels of each lint warning + curr: SmallIntMap<(level, LintSource)>, + // context we're checking in (used to access fields like sess) + tcx: ty::ctxt, + // When recursing into an attributed node of the ast which modifies lint + // levels, this stack keeps track of the previous lint levels of whatever + // was modified. + lint_stack: ~[(lint, level, LintSource)], + // Each of these visitors represents a lint pass. A number of the lint + // attributes are registered by adding a visitor to iterate over the ast. + // Others operate directly on @ast::item structures (or similar). Finally, + // others still are added to the Session object via `add_lint`, and these + // are all passed with the lint_session visitor. + visitors: ~[visit::vt<()>], } -pub impl Context { +impl Context { fn get_level(&self, lint: lint) -> level { - get_lint_level(self.curr, lint) + match self.curr.find(&(lint as uint)) { + Some(&(lvl, _)) => lvl, + None => allow + } + } + + fn get_source(&self, lint: lint) -> LintSource { + match self.curr.find(&(lint as uint)) { + Some(&(_, src)) => src, + None => Default + } } - fn set_level(&self, lint: lint, level: level) { + fn set_level(&mut self, lint: lint, level: level, src: LintSource) { if level == allow { self.curr.remove(&(lint as uint)); } else { - self.curr.insert(lint as uint, level); + self.curr.insert(lint as uint, (level, src)); + } + } + + fn lint_to_str(&self, lint: lint) -> ~str { + for self.dict.each |k, v| { + if v.lint == lint { + return copy *k; + } } + fail!("unregistered lint %?", lint); } - fn span_lint(&self, level: level, span: span, msg: ~str) { - self.sess.span_lint_level(level, span, msg); + fn span_lint(&self, lint: lint, span: span, msg: &str) { + let (level, src) = match self.curr.find(&(lint as uint)) { + Some(&pair) => pair, + None => { return; } + }; + if level == allow { return; } + + let mut note = None; + let msg = match src { + Default | CommandLine => { + fmt!("%s [-%c %s%s]", msg, match level { + warn => 'W', deny => 'D', forbid => 'F', + allow => fail!() + }, str::replace(self.lint_to_str(lint), "_", "-"), + if src == Default { " (default)" } else { "" }) + }, + Node(src) => { + note = Some(src); + msg.to_str() + } + }; + match level { + warn => { self.tcx.sess.span_warn(span, msg); } + deny | forbid => { self.tcx.sess.span_err(span, msg); } + allow => fail!(), + } + + for note.each |&span| { + self.tcx.sess.span_note(span, "lint level defined here"); + } } /** @@ -308,189 +344,191 @@ pub impl Context { * current lint context, call the provided function, then reset the * lints in effect to their previous state. */ - fn with_lint_attrs(&self, attrs: ~[ast::attribute], f: &fn(Context)) { - - let mut new_ctxt = *self; - let mut triples = ~[]; - - for [allow, warn, deny, forbid].each |level| { - let level_name = level_to_str(*level); - let metas = - attr::attr_metas(attr::find_attrs_by_name(attrs, level_name)); - for metas.each |meta| { - match meta.node { - ast::meta_list(_, ref metas) => { - for metas.each |meta| { - match meta.node { - ast::meta_word(ref lintname) => { - triples.push((*meta, - *level, - /*bad*/copy *lintname)); - } - _ => { - self.sess.span_err( - meta.span, - "malformed lint attribute"); - } - } - } - } - _ => { - self.sess.span_err(meta.span, - "malformed lint attribute"); - } - } - } - } - - for triples.each |triple| { - // FIXME(#3874): it would be nicer to write this... - // let (meta, level, lintname) = /*bad*/copy *pair; - let (meta, level, lintname) = match *triple { - (ref meta, level, lintname) => (meta, level, lintname) - }; - - match self.dict.find(lintname) { + fn with_lint_attrs(@mut self, attrs: &[ast::attribute], f: &fn()) { + // Parse all of the lint attributes, and then add them all to the + // current dictionary of lint information. Along the way, keep a history + // of what we changed so we can roll everything back after invoking the + // specified closure + let mut pushed = 0u; + for each_lint(self.tcx.sess, attrs) |meta, level, lintname| { + let lint = match self.dict.find(lintname) { None => { self.span_lint( - new_ctxt.get_level(unrecognized_lint), + unrecognized_lint, meta.span, fmt!("unknown `%s` attribute: `%s`", level_to_str(level), *lintname)); + loop } - Some(lint) => { - - if new_ctxt.get_level(lint.lint) == forbid && - level != forbid { - self.span_lint( - forbid, - meta.span, - fmt!("%s(%s) overruled by outer forbid(%s)", - level_to_str(level), - *lintname, *lintname)); - } + Some(lint) => { lint.lint } + }; - // we do multiple unneeded copies of the - // map if many attributes are set, but - // this shouldn't actually be a problem... + let now = self.get_level(lint); + if now == forbid && level != forbid { + self.tcx.sess.span_err(meta.span, + fmt!("%s(%s) overruled by outer forbid(%s)", + level_to_str(level), + *lintname, *lintname)); + loop; + } - let c = clone_lint_modes(new_ctxt.curr); - new_ctxt = Context { - is_default: false, - curr: c, - .. new_ctxt - }; - new_ctxt.set_level(lint.lint, level); - } + if now != level { + let src = self.get_source(lint); + self.lint_stack.push((lint, now, src)); + pushed += 1; + self.set_level(lint, level, Node(meta.span)); } } - f(new_ctxt); - } -} + f(); -fn build_settings_item(i: @ast::item, cx: Context, v: visit::vt<Context>) { - do cx.with_lint_attrs(/*bad*/copy i.attrs) |cx| { - if !cx.is_default { - cx.sess.lint_settings.settings_map.insert(i.id, cx.curr); + // rollback + for pushed.times { + let (lint, lvl, src) = self.lint_stack.pop(); + self.set_level(lint, lvl, src); } - visit::visit_item(i, cx, v); } -} - -pub fn build_settings_crate(sess: session::Session, crate: @ast::crate) { - let cx = Context { - dict: get_lint_dict(), - curr: @mut SmallIntMap::new(), - is_default: true, - sess: sess - }; - // Install defaults. - for cx.dict.each_value |&spec| { - cx.set_level(spec.lint, spec.default); + fn add_lint(&mut self, v: visit::vt<()>) { + self.visitors.push(item_stopping_visitor(v)); } - // Install command-line options, overriding defaults. - for sess.opts.lint_opts.each |pair| { - let (lint,level) = *pair; - cx.set_level(lint, level); + fn process(&self, n: AttributedNode) { + match n { + Item(it) => { + for self.visitors.each |v| { + visit::visit_item(it, (), *v); + } + } + Crate(c) => { + for self.visitors.each |v| { + visit::visit_crate(c, (), *v); + } + } + // Can't use visit::visit_method_helper because the + // item_stopping_visitor has overridden visit_fn(&fk_method(... )) + // to be a no-op, so manually invoke visit_fn. + Method(m) => { + let fk = visit::fk_method(copy m.ident, &m.generics, m); + for self.visitors.each |v| { + visit::visit_fn(&fk, &m.decl, &m.body, m.span, m.id, + (), *v); + } + } + } } +} - do cx.with_lint_attrs(/*bad*/copy crate.node.attrs) |cx| { - // Copy out the default settings - for cx.curr.each |&k, &v| { - sess.lint_settings.default_settings.insert(k, v); +#[cfg(stage0)] +pub fn each_lint(sess: session::Session, + attrs: &[ast::attribute], + f: &fn(@ast::meta_item, level, &~str) -> bool) +{ + for [allow, warn, deny, forbid].each |&level| { + let level_name = level_to_str(level); + let attrs = attr::find_attrs_by_name(attrs, level_name); + for attrs.each |attr| { + let meta = attr.node.value; + let metas = match meta.node { + ast::meta_list(_, ref metas) => metas, + _ => { + sess.span_err(meta.span, ~"malformed lint attribute"); + loop; + } + }; + for metas.each |meta| { + match meta.node { + ast::meta_word(lintname) => { + if !f(*meta, level, lintname) { + return; + } + } + _ => { + sess.span_err(meta.span, ~"malformed lint attribute"); + } + } + } } - - let cx = Context { - is_default: true, - .. cx - }; - - let visit = visit::mk_vt(@visit::Visitor { - visit_item: build_settings_item, - .. *visit::default_visitor() - }); - visit::visit_crate(crate, cx, visit); } - - sess.abort_if_errors(); } - -fn check_item(i: @ast::item, cx: ty::ctxt) { - check_item_ctypes(cx, i); - check_item_while_true(cx, i); - check_item_path_statement(cx, i); - check_item_non_camel_case_types(cx, i); - check_item_heap(cx, i); - check_item_type_limits(cx, i); - check_item_default_methods(cx, i); - check_item_unused_unsafe(cx, i); - check_item_unused_mut(cx, i); +#[cfg(not(stage0))] +pub fn each_lint(sess: session::Session, + attrs: &[ast::attribute], + f: &fn(@ast::meta_item, level, &~str) -> bool) -> bool +{ + for [allow, warn, deny, forbid].each |&level| { + let level_name = level_to_str(level); + let attrs = attr::find_attrs_by_name(attrs, level_name); + for attrs.each |attr| { + let meta = attr.node.value; + let metas = match meta.node { + ast::meta_list(_, ref metas) => metas, + _ => { + sess.span_err(meta.span, ~"malformed lint attribute"); + loop; + } + }; + for metas.each |meta| { + match meta.node { + ast::meta_word(lintname) => { + if !f(*meta, level, lintname) { + return false; + } + } + _ => { + sess.span_err(meta.span, ~"malformed lint attribute"); + } + } + } + } + } + return true; } // Take a visitor, and modify it so that it will not proceed past subitems. // This is used to make the simple visitors used for the lint passes // not traverse into subitems, since that is handled by the outer // lint visitor. -fn item_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> { - visit::mk_vt(@visit::Visitor {visit_item: |_i, _e, _v| { }, - .. **(ty_stopping_visitor(v))}) +fn item_stopping_visitor<E: Copy>(v: visit::vt<E>) -> visit::vt<E> { + visit::mk_vt(@visit::Visitor { + visit_item: |_i, _e, _v| { }, + visit_fn: |fk, fd, b, s, id, e, v| { + match *fk { + visit::fk_method(*) => {} + _ => visit::visit_fn(fk, fd, b, s, id, e, v) + } + }, + .. **(ty_stopping_visitor(v))}) } fn ty_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> { visit::mk_vt(@visit::Visitor {visit_ty: |_t, _e, _v| { },.. **v}) } -fn check_item_while_true(cx: ty::ctxt, it: @ast::item) { - let visit = item_stopping_visitor( - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: |e: @ast::expr| { - match e.node { - ast::expr_while(cond, _) => { - match cond.node { - ast::expr_lit(@codemap::spanned { - node: ast::lit_bool(true), _}) => - { - cx.sess.span_lint( - while_true, e.id, it.id, - e.span, - "denote infinite loops \ - with loop { ... }"); - } - _ => () +fn lint_while_true(cx: @mut Context) -> visit::vt<()> { + visit::mk_simple_visitor(@visit::SimpleVisitor { + visit_expr: |e: @ast::expr| { + match e.node { + ast::expr_while(cond, _) => { + match cond.node { + ast::expr_lit(@codemap::spanned { + node: ast::lit_bool(true), _}) => + { + cx.span_lint(while_true, e.span, + "denote infinite loops with \ + loop { ... }"); } + _ => () } - _ => () } - }, - .. *visit::default_simple_visitor() - })); - visit::visit_item(it, (), visit); + _ => () + } + }, + .. *visit::default_simple_visitor() + }) } -fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { +fn lint_type_limits(cx: @mut Context) -> visit::vt<()> { fn is_valid<T:cmp::Ord>(binop: ast::binop, v: T, min: T, max: T) -> bool { match binop { @@ -513,9 +551,11 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { } } + // for int & uint, be conservative with the warnings, so that the + // warnings are consistent between 32- and 64-bit platforms fn int_ty_range(int_ty: ast::int_ty) -> (i64, i64) { match int_ty { - ast::ty_i => (int::min_value as i64, int::max_value as i64), + ast::ty_i => (i64::min_value, i64::max_value), ast::ty_char => (u32::min_value as i64, u32::max_value as i64), ast::ty_i8 => (i8::min_value as i64, i8::max_value as i64), ast::ty_i16 => (i16::min_value as i64, i16::max_value as i64), @@ -526,7 +566,7 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { fn uint_ty_range(uint_ty: ast::uint_ty) -> (u64, u64) { match uint_ty { - ast::ty_u => (uint::min_value as u64, uint::max_value as u64), + ast::ty_u => (u64::min_value, u64::max_value), ast::ty_u8 => (u8::min_value as u64, u8::max_value as u64), ast::ty_u16 => (u16::min_value as u64, u16::max_value as u64), ast::ty_u32 => (u32::min_value as u64, u32::max_value as u64), @@ -534,7 +574,7 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { } } - fn check_limits(cx: ty::ctxt, binop: ast::binop, l: &ast::expr, + fn check_limits(cx: @mut Context, binop: ast::binop, l: &ast::expr, r: &ast::expr) -> bool { let (lit, expr, swap) = match (&l.node, &r.node) { (&ast::expr_lit(_), _) => (l, r, true), @@ -543,12 +583,12 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { }; // Normalize the binop so that the literal is always on the RHS in // the comparison - let norm_binop = if (swap) { + let norm_binop = if swap { rev_binop(binop) } else { binop }; - match ty::get(ty::expr_ty(cx, @/*bad*/copy *expr)).sty { + match ty::get(ty::expr_ty(cx.tcx, @/*bad*/copy *expr)).sty { ty::ty_int(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i64 = match lit.node { @@ -592,36 +632,29 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { ast::expr_binary(ref binop, @ref l, @ref r) => { if is_comparison(*binop) && !check_limits(cx, *binop, l, r) { - cx.sess.span_lint( - type_limits, e.id, it.id, e.span, - "comparison is useless due to type limits"); + cx.span_lint(type_limits, e.span, + "comparison is useless due to type limits"); } } _ => () } }; - let visit = item_stopping_visitor( - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: visit_expr, - .. *visit::default_simple_visitor() - })); - visit::visit_item(it, (), visit); + visit::mk_simple_visitor(@visit::SimpleVisitor { + visit_expr: visit_expr, + .. *visit::default_simple_visitor() + }) } -fn check_item_default_methods(cx: ty::ctxt, item: @ast::item) { +fn check_item_default_methods(cx: @mut Context, item: @ast::item) { match item.node { ast::item_trait(_, _, ref methods) => { for methods.each |method| { match *method { ast::required(*) => {} ast::provided(*) => { - cx.sess.span_lint( - default_methods, - item.id, - item.id, - item.span, - "default methods are experimental"); + cx.span_lint(default_methods, item.span, + "default methods are experimental"); } } } @@ -630,25 +663,21 @@ fn check_item_default_methods(cx: ty::ctxt, item: @ast::item) { } } -fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { - fn check_foreign_fn(cx: ty::ctxt, fn_id: ast::node_id, - decl: &ast::fn_decl) { +fn check_item_ctypes(cx: @mut Context, it: @ast::item) { + + fn check_foreign_fn(cx: @mut Context, decl: &ast::fn_decl) { let tys = vec::map(decl.inputs, |a| a.ty ); for vec::each(vec::append_one(tys, decl.output)) |ty| { match ty.node { ast::ty_path(_, id) => { - match cx.def_map.get_copy(&id) { + match cx.tcx.def_map.get_copy(&id) { ast::def_prim_ty(ast::ty_int(ast::ty_i)) => { - cx.sess.span_lint( - ctypes, id, fn_id, - ty.span, + cx.span_lint(ctypes, ty.span, "found rust type `int` in foreign module, while \ libc::c_int or libc::c_long should be used"); } ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => { - cx.sess.span_lint( - ctypes, id, fn_id, - ty.span, + cx.span_lint(ctypes, ty.span, "found rust type `uint` in foreign module, while \ libc::c_uint or libc::c_ulong should be used"); } @@ -665,7 +694,7 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { for nmod.items.each |ni| { match ni.node { ast::foreign_item_fn(ref decl, _, _) => { - check_foreign_fn(cx, it.id, decl); + check_foreign_fn(cx, decl); } // FIXME #4622: Not implemented. ast::foreign_item_const(*) => {} @@ -676,57 +705,47 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { } } -fn check_item_heap(cx: ty::ctxt, it: @ast::item) { - - fn check_type_for_lint(cx: ty::ctxt, lint: lint, - node: ast::node_id, - item: ast::node_id, - span: span, ty: ty::t) { - - if get_lint_settings_level(cx.sess.lint_settings, - lint, node, item) != allow { - let mut n_box = 0; - let mut n_uniq = 0; - ty::fold_ty(cx, ty, |t| { - match ty::get(t).sty { - ty::ty_box(_) => n_box += 1, - ty::ty_uniq(_) => n_uniq += 1, - _ => () - }; - t - }); +fn check_type_for_lint(cx: @mut Context, lint: lint, span: span, ty: ty::t) { + if cx.get_level(lint) == allow { return } - if (n_uniq > 0 && lint != managed_heap_memory) { - let s = ty_to_str(cx, ty); - let m = ~"type uses owned (~ type) pointers: " + s; - cx.sess.span_lint(lint, node, item, span, m); - } + let mut n_box = 0; + let mut n_uniq = 0; + ty::fold_ty(cx.tcx, ty, |t| { + match ty::get(t).sty { + ty::ty_box(_) => n_box += 1, + ty::ty_uniq(_) => n_uniq += 1, + _ => () + }; + t + }); - if (n_box > 0 && lint != owned_heap_memory) { - let s = ty_to_str(cx, ty); - let m = ~"type uses managed (@ type) pointers: " + s; - cx.sess.span_lint(lint, node, item, span, m); - } - } + if n_uniq > 0 && lint != managed_heap_memory { + let s = ty_to_str(cx.tcx, ty); + let m = ~"type uses owned (~ type) pointers: " + s; + cx.span_lint(lint, span, m); } - fn check_type(cx: ty::ctxt, - node: ast::node_id, - item: ast::node_id, - span: span, ty: ty::t) { - for [managed_heap_memory, - owned_heap_memory, - heap_memory].each |lint| { - check_type_for_lint(cx, *lint, node, item, span, ty); - } + if n_box > 0 && lint != owned_heap_memory { + let s = ty_to_str(cx.tcx, ty); + let m = ~"type uses managed (@ type) pointers: " + s; + cx.span_lint(lint, span, m); } +} + +fn check_type(cx: @mut Context, span: span, ty: ty::t) { + for [managed_heap_memory, owned_heap_memory, heap_memory].each |lint| { + check_type_for_lint(cx, *lint, span, ty); + } +} +fn check_item_heap(cx: @mut Context, it: @ast::item) { match it.node { ast::item_fn(*) | ast::item_ty(*) | ast::item_enum(*) | - ast::item_struct(*) => check_type(cx, it.id, it.id, it.span, - ty::node_id_to_type(cx, it.id)), + ast::item_struct(*) => check_type(cx, it.span, + ty::node_id_to_type(cx.tcx, + it.id)), _ => () } @@ -734,48 +753,44 @@ fn check_item_heap(cx: ty::ctxt, it: @ast::item) { match it.node { ast::item_struct(struct_def, _) => { for struct_def.fields.each |struct_field| { - check_type(cx, struct_field.node.id, it.id, - struct_field.span, - ty::node_id_to_type(cx, struct_field.node.id)); + check_type(cx, struct_field.span, + ty::node_id_to_type(cx.tcx, + struct_field.node.id)); } } _ => () } +} - let visit = item_stopping_visitor( - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: |e: @ast::expr| { - let ty = ty::expr_ty(cx, e); - check_type(cx, e.id, it.id, e.span, ty); - }, - .. *visit::default_simple_visitor() - })); - visit::visit_item(it, (), visit); +fn lint_heap(cx: @mut Context) -> visit::vt<()> { + visit::mk_simple_visitor(@visit::SimpleVisitor { + visit_expr: |e| { + let ty = ty::expr_ty(cx.tcx, e); + check_type(cx, e.span, ty); + }, + .. *visit::default_simple_visitor() + }) } -fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) { - let visit = item_stopping_visitor( - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_stmt: |s: @ast::stmt| { - match s.node { - ast::stmt_semi( - @ast::expr { id: id, node: ast::expr_path(_), _ }, - _ - ) => { - cx.sess.span_lint( - path_statement, id, it.id, - s.span, - "path statement with no effect"); - } - _ => () +fn lint_path_statement(cx: @mut Context) -> visit::vt<()> { + visit::mk_simple_visitor(@visit::SimpleVisitor { + visit_stmt: |s| { + match s.node { + ast::stmt_semi( + @ast::expr { node: ast::expr_path(_), _ }, + _ + ) => { + cx.span_lint(path_statement, s.span, + "path statement with no effect"); } - }, - .. *visit::default_simple_visitor() - })); - visit::visit_item(it, (), visit); + _ => () + } + }, + .. *visit::default_simple_visitor() + }) } -fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) { +fn check_item_non_camel_case_types(cx: @mut Context, it: @ast::item) { fn is_camel_case(cx: ty::ctxt, ident: ast::ident) -> bool { let ident = cx.sess.str_of(ident); assert!(!ident.is_empty()); @@ -799,61 +814,54 @@ fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) { } } - fn check_case(cx: ty::ctxt, ident: ast::ident, - expr_id: ast::node_id, item_id: ast::node_id, - span: span) { - if !is_camel_case(cx, ident) { - cx.sess.span_lint( - non_camel_case_types, expr_id, item_id, span, - "type, variant, or trait should have \ - a camel case identifier"); + fn check_case(cx: @mut Context, ident: ast::ident, span: span) { + if !is_camel_case(cx.tcx, ident) { + cx.span_lint(non_camel_case_types, span, + "type, variant, or trait should have \ + a camel case identifier"); } } match it.node { ast::item_ty(*) | ast::item_struct(*) | ast::item_trait(*) => { - check_case(cx, it.ident, it.id, it.id, it.span) + check_case(cx, it.ident, it.span) } ast::item_enum(ref enum_definition, _) => { - check_case(cx, it.ident, it.id, it.id, it.span); + check_case(cx, it.ident, it.span); for enum_definition.variants.each |variant| { - check_case(cx, variant.node.name, - variant.node.id, it.id, variant.span); + check_case(cx, variant.node.name, variant.span); } } _ => () } } -fn check_item_unused_unsafe(cx: ty::ctxt, it: @ast::item) { +fn lint_unused_unsafe(cx: @mut Context) -> visit::vt<()> { let visit_expr: @fn(@ast::expr) = |e| { match e.node { ast::expr_block(ref blk) if blk.node.rules == ast::unsafe_blk => { - if !cx.used_unsafe.contains(&blk.node.id) { - cx.sess.span_lint(unused_unsafe, blk.node.id, it.id, - blk.span, - "unnecessary `unsafe` block"); + if !cx.tcx.used_unsafe.contains(&blk.node.id) { + cx.span_lint(unused_unsafe, blk.span, + "unnecessary `unsafe` block"); } } _ => () } }; - let visit = item_stopping_visitor( - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_expr: visit_expr, - .. *visit::default_simple_visitor() - })); - visit::visit_item(it, (), visit); + visit::mk_simple_visitor(@visit::SimpleVisitor { + visit_expr: visit_expr, + .. *visit::default_simple_visitor() + }) } -fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) { +fn lint_unused_mut(cx: @mut Context) -> visit::vt<()> { let check_pat: @fn(@ast::pat) = |p| { let mut used = false; let mut bindings = 0; - do pat_util::pat_bindings(tcx.def_map, p) |_, id, _, _| { - used = used || tcx.used_mut_nodes.contains(&id); + do pat_util::pat_bindings(cx.tcx.def_map, p) |_, id, _, _| { + used = used || cx.tcx.used_mut_nodes.contains(&id); bindings += 1; } if !used { @@ -862,7 +870,7 @@ fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) { } else { "variables do not need to be mutable" }; - tcx.sess.span_lint(unused_mut, p.id, it.id, p.span, msg); + cx.span_lint(unused_mut, p.span, msg); } }; @@ -874,45 +882,116 @@ fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) { } }; - let visit = item_stopping_visitor( - visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_local: |l| { - if l.node.is_mutbl { - check_pat(l.node.pat); - } - }, - visit_fn: |_, fd, _, _, _| visit_fn_decl(fd), - visit_ty_method: |tm| visit_fn_decl(&tm.decl), - visit_struct_method: |sm| visit_fn_decl(&sm.decl), - visit_trait_method: |tm| { - match *tm { - ast::required(ref tm) => visit_fn_decl(&tm.decl), - ast::provided(m) => visit_fn_decl(&m.decl), - } - }, - .. *visit::default_simple_visitor() - })); - visit::visit_item(it, (), visit); + visit::mk_simple_visitor(@visit::SimpleVisitor { + visit_local: |l| { + if l.node.is_mutbl { + check_pat(l.node.pat); + } + }, + visit_fn: |_, fd, _, _, _| visit_fn_decl(fd), + visit_ty_method: |tm| visit_fn_decl(&tm.decl), + visit_struct_method: |sm| visit_fn_decl(&sm.decl), + visit_trait_method: |tm| { + match *tm { + ast::required(ref tm) => visit_fn_decl(&tm.decl), + ast::provided(m) => visit_fn_decl(&m.decl), + } + }, + .. *visit::default_simple_visitor() + }) } -fn check_fn(_: ty::ctxt, - fk: &visit::fn_kind, - _: &ast::fn_decl, - _: &ast::blk, - _: span, - id: ast::node_id) { - debug!("lint check_fn fk=%? id=%?", fk, id); +fn lint_session(cx: @mut Context) -> visit::vt<()> { + ast_util::id_visitor(|id| { + match cx.tcx.sess.lints.pop(&id) { + None => {}, + Some(l) => { + do vec::consume(l) |_, (lint, span, msg)| { + cx.span_lint(lint, span, msg) + } + } + } + }) } pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) { - let v = visit::mk_simple_visitor(@visit::SimpleVisitor { - visit_item: |it| - check_item(it, tcx), - visit_fn: |fk, decl, body, span, id| - check_fn(tcx, fk, decl, body, span, id), - .. *visit::default_simple_visitor() - }); - visit::visit_crate(crate, (), v); + let cx = @mut Context { + dict: @get_lint_dict(), + curr: SmallIntMap::new(), + tcx: tcx, + lint_stack: ~[], + visitors: ~[], + }; + + // Install defaults. + for cx.dict.each_value |spec| { + cx.set_level(spec.lint, spec.default, Default); + } + + // Install command-line options, overriding defaults. + for tcx.sess.opts.lint_opts.each |&(lint, level)| { + cx.set_level(lint, level, CommandLine); + } + + // Register each of the lint passes with the context + cx.add_lint(lint_while_true(cx)); + cx.add_lint(lint_path_statement(cx)); + cx.add_lint(lint_heap(cx)); + cx.add_lint(lint_type_limits(cx)); + cx.add_lint(lint_unused_unsafe(cx)); + cx.add_lint(lint_unused_mut(cx)); + cx.add_lint(lint_session(cx)); + + // type inference doesn't like this being declared below, we need to tell it + // what the type of this first function is... + let visit_item: + @fn(@ast::item, @mut Context, visit::vt<@mut Context>) = + |it, cx, vt| { + do cx.with_lint_attrs(it.attrs) { + check_item_ctypes(cx, it); + check_item_non_camel_case_types(cx, it); + check_item_default_methods(cx, it); + check_item_heap(cx, it); + + cx.process(Item(it)); + visit::visit_item(it, cx, vt); + } + }; + + // Actually perform the lint checks (iterating the ast) + do cx.with_lint_attrs(crate.node.attrs) { + cx.process(Crate(crate)); + + visit::visit_crate(crate, cx, visit::mk_vt(@visit::Visitor { + visit_item: visit_item, + visit_fn: |fk, decl, body, span, id, cx, vt| { + match *fk { + visit::fk_method(_, _, m) => { + do cx.with_lint_attrs(m.attrs) { + cx.process(Method(m)); + visit::visit_fn(fk, decl, body, span, id, cx, vt); + } + } + _ => { + visit::visit_fn(fk, decl, body, span, id, cx, vt); + } + } + }, + .. *visit::default_visitor() + })); + } + + // If we missed any lints added to the session, then there's a bug somewhere + // in the iteration code. + for tcx.sess.lints.each |_, v| { + for v.each |t| { + match *t { + (lint, span, ref msg) => + tcx.sess.span_bug(span, fmt!("unprocessed lint %?: %s", + lint, *msg)) + } + } + } tcx.sess.abort_if_errors(); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 9995de24e8d..711e3915277 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -153,15 +153,13 @@ pub fn check_crate(tcx: ty::ctxt, visit_local: visit_local, visit_expr: visit_expr, visit_arm: visit_arm, - visit_item: visit_item, .. *visit::default_visitor() }); let initial_maps = @mut IrMaps(tcx, method_map, variable_moves_map, - capture_map, - 0); + capture_map); visit::visit_crate(crate, initial_maps, visitor); tcx.sess.abort_if_errors(); } @@ -240,15 +238,12 @@ struct IrMaps { capture_info_map: HashMap<node_id, @~[CaptureInfo]>, var_kinds: ~[VarKind], lnks: ~[LiveNodeKind], - - cur_item: node_id, } fn IrMaps(tcx: ty::ctxt, method_map: typeck::method_map, variable_moves_map: moves::VariableMovesMap, - capture_map: moves::CaptureMap, - cur_item: node_id) + capture_map: moves::CaptureMap) -> IrMaps { IrMaps { tcx: tcx, @@ -262,7 +257,6 @@ fn IrMaps(tcx: ty::ctxt, capture_info_map: HashMap::new(), var_kinds: ~[], lnks: ~[], - cur_item: cur_item, } } @@ -341,13 +335,6 @@ pub impl IrMaps { } } -fn visit_item(item: @item, this: @mut IrMaps, v: vt<@mut IrMaps>) { - let old_cur_item = this.cur_item; - this.cur_item = item.id; - visit::visit_item(item, this, v); - this.cur_item = old_cur_item; -} - fn visit_fn(fk: &visit::fn_kind, decl: &fn_decl, body: &blk, @@ -362,8 +349,7 @@ fn visit_fn(fk: &visit::fn_kind, let fn_maps = @mut IrMaps(this.tcx, this.method_map, this.variable_moves_map, - this.capture_map, - this.cur_item); + this.capture_map); unsafe { debug!("creating fn_maps: %x", transmute(&*fn_maps)); @@ -1802,13 +1788,11 @@ pub impl Liveness { }; if is_assigned { - self.tcx.sess.span_lint(unused_variable, id, - self.ir.cur_item, sp, + self.tcx.sess.add_lint(unused_variable, id, sp, fmt!("variable `%s` is assigned to, \ but never used", **name)); } else { - self.tcx.sess.span_lint(unused_variable, id, - self.ir.cur_item, sp, + self.tcx.sess.add_lint(unused_variable, id, sp, fmt!("unused variable: `%s`", **name)); } } @@ -1821,8 +1805,7 @@ pub impl Liveness { ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { for self.should_warn(var).each |name| { - self.tcx.sess.span_lint(dead_assignment, id, - self.ir.cur_item, sp, + self.tcx.sess.add_lint(dead_assignment, id, sp, fmt!("value assigned to `%s` is never read", **name)); } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 95ed7fe8efc..91c0b8e61cc 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -551,7 +551,7 @@ pub impl mem_categorization_ctxt { id:elt.id(), span:elt.span(), cat:cat_rvalue, - mutbl:McImmutable, + mutbl:McDeclared, ty:expr_ty } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 3a2fb654006..e81a9d6b78f 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -221,16 +221,14 @@ use syntax::visit::vt; use syntax::print::pprust; use syntax::codemap::span; -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub enum CaptureMode { CapCopy, // Copy the value into the closure. CapMove, // Move the value into the closure. CapRef, // Reference directly from parent stack frame (used by `&fn()`). } -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub struct CaptureVar { def: def, // Variable being accessed free span: span, // Location of an access to this variable diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 9b864bd0ef2..a7e590e359c 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -16,46 +16,10 @@ use metadata::csearch::get_type_name_if_impl; use metadata::cstore::find_extern_mod_stmt_cnum; use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; -use middle::lint::{allow, level, unused_imports}; -use middle::lint::{get_lint_level, get_lint_settings_level}; +use middle::lint::unused_imports; use middle::pat_util::pat_bindings; -use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm}; -use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk}; -use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy}; -use syntax::ast::{crate, decl_item, def, def_arg, def_binding}; -use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; -use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; -use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty}; -use syntax::ast::{def_ty_param, def_typaram_binder, def_trait}; -use syntax::ast::{def_upvar, def_use, def_variant, explicit_self_, expr, expr_assign_op}; -use syntax::ast::{expr_binary, expr_break, expr_field}; -use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; -use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; -use syntax::ast::{def_upvar, def_use, def_variant, div, eq}; -use syntax::ast::{expr, expr_again, expr_assign_op}; -use syntax::ast::{expr_index, expr_loop}; -use syntax::ast::{expr_path, expr_self, expr_struct, expr_unary, fn_decl}; -use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge}; -use syntax::ast::Generics; -use syntax::ast::{gt, ident, inherited, item, item_struct}; -use syntax::ast::{item_const, item_enum, item_fn, item_foreign_mod}; -use syntax::ast::{item_impl, item_mac, item_mod, item_trait, item_ty, le}; -use syntax::ast::{local, local_crate, lt, method, mul}; -use syntax::ast::{named_field, ne, neg, node_id, pat, pat_enum, pat_ident}; -use syntax::ast::{Path, pat_lit, pat_range, pat_struct}; -use syntax::ast::{prim_ty, private, provided}; -use syntax::ast::{public, required, rem, shl, shr, stmt_decl}; -use syntax::ast::{struct_field, struct_variant_kind}; -use syntax::ast::{sty_static, subtract, trait_ref, tuple_variant_kind, Ty}; -use syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i}; -use syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, TyParam, ty_path}; -use syntax::ast::{ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint}; -use syntax::ast::unnamed_field; -use syntax::ast::{variant, view_item, view_item_extern_mod}; -use syntax::ast::{view_item_use, view_path_glob, view_path_list}; -use syntax::ast::{view_path_simple, anonymous, named, not}; -use syntax::ast::{unsafe_fn}; +use syntax::ast::*; use syntax::ast_util::{def_id_of_def, local_def}; use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; use syntax::ast_util::{Privacy, Public, Private}; @@ -65,6 +29,7 @@ use syntax::parse::token::ident_interner; use syntax::parse::token::special_idents; use syntax::print::pprust::path_to_str; use syntax::codemap::{span, dummy_sp, BytePos}; +use syntax::visit::{mk_simple_visitor, default_simple_visitor, SimpleVisitor}; use syntax::visit::{default_visitor, mk_vt, Visitor, visit_block}; use syntax::visit::{visit_crate, visit_expr, visit_expr_opt}; use syntax::visit::{visit_foreign_item, visit_item}; @@ -345,18 +310,21 @@ pub struct ImportDirective { module_path: ~[ident], subclass: @ImportDirectiveSubclass, span: span, + id: node_id, } pub fn ImportDirective(privacy: Privacy, module_path: ~[ident], subclass: @ImportDirectiveSubclass, - span: span) + span: span, + id: node_id) -> ImportDirective { ImportDirective { privacy: privacy, module_path: module_path, subclass: subclass, - span: span + span: span, + id: id } } @@ -380,7 +348,7 @@ pub struct ImportResolution { /// The privacy of this `use` directive (whether it's `use` or /// `pub use`. privacy: Privacy, - span: span, + id: node_id, // The number of outstanding references to this name. When this reaches // zero, outside modules can count on the targets being correct. Before @@ -392,21 +360,16 @@ pub struct ImportResolution { value_target: Option<Target>, /// The type that this `use` directive names, if there is one. type_target: Option<Target>, - - /// There exists one state per import statement - state: @mut ImportState, } pub fn ImportResolution(privacy: Privacy, - span: span, - state: @mut ImportState) -> ImportResolution { + id: node_id) -> ImportResolution { ImportResolution { privacy: privacy, - span: span, + id: id, outstanding_references: 0, value_target: None, type_target: None, - state: state, } } @@ -419,15 +382,6 @@ pub impl ImportResolution { } } -pub struct ImportState { - used: bool, - warned: bool -} - -pub fn ImportState() -> ImportState { - ImportState{ used: false, warned: false } -} - /// The link from a module up to its nearest parent node. pub enum ParentLink { NoParentLink, @@ -512,13 +466,15 @@ pub impl Module { pub struct TypeNsDef { privacy: Privacy, module_def: Option<@mut Module>, - type_def: Option<def> + type_def: Option<def>, + type_span: Option<span> } // Records a possibly-private value definition. pub struct ValueNsDef { privacy: Privacy, def: def, + value_span: Option<span>, } // Records the definitions (at most one for each namespace) that a name is @@ -526,11 +482,6 @@ pub struct ValueNsDef { pub struct NameBindings { type_def: Option<TypeNsDef>, //< Meaning in type namespace. value_def: Option<ValueNsDef>, //< Meaning in value namespace. - - // For error reporting - // FIXME (#3783): Merge me into TypeNsDef and ValueNsDef. - type_span: Option<span>, - value_span: Option<span>, } pub impl NameBindings { @@ -548,18 +499,19 @@ pub impl NameBindings { self.type_def = Some(TypeNsDef { privacy: privacy, module_def: Some(module_), - type_def: None + type_def: None, + type_span: Some(sp) }); } Some(copy type_def) => { self.type_def = Some(TypeNsDef { privacy: privacy, module_def: Some(module_), + type_span: Some(sp), .. type_def }); } } - self.type_span = Some(sp); } /// Records a type definition. @@ -570,24 +522,24 @@ pub impl NameBindings { self.type_def = Some(TypeNsDef { privacy: privacy, module_def: None, - type_def: Some(def) + type_def: Some(def), + type_span: Some(sp) }); } Some(copy type_def) => { self.type_def = Some(TypeNsDef { privacy: privacy, type_def: Some(def), + type_span: Some(sp), .. type_def }); } } - self.type_span = Some(sp); } /// Records a value definition. fn define_value(@mut self, privacy: Privacy, def: def, sp: span) { - self.value_def = Some(ValueNsDef { privacy: privacy, def: def }); - self.value_span = Some(sp); + self.value_def = Some(ValueNsDef { privacy: privacy, def: def, value_span: Some(sp) }); } /// Returns the module node if applicable. @@ -686,8 +638,18 @@ pub impl NameBindings { fn span_for_namespace(&self, namespace: Namespace) -> Option<span> { if self.defined_in_namespace(namespace) { match namespace { - TypeNS => self.type_span, - ValueNS => self.value_span, + TypeNS => { + match self.type_def { + None => None, + Some(type_def) => type_def.type_span + } + } + ValueNS => { + match self.value_def { + None => None, + Some(value_def) => value_def.value_span + } + } } } else { None @@ -698,9 +660,7 @@ pub impl NameBindings { pub fn NameBindings() -> NameBindings { NameBindings { type_def: None, - value_def: None, - type_span: None, - value_span: None + value_def: None } } @@ -798,6 +758,7 @@ pub fn Resolver(session: Session, def_map: @mut HashMap::new(), export_map2: @mut HashMap::new(), trait_map: HashMap::new(), + used_imports: HashSet::new(), intr: session.intr() }; @@ -855,6 +816,8 @@ pub struct Resolver { def_map: DefMap, export_map2: ExportMap2, trait_map: TraitMap, + + used_imports: HashSet<node_id>, } pub impl Resolver { @@ -872,7 +835,7 @@ pub impl Resolver { self.resolve_crate(); self.session.abort_if_errors(); - self.check_for_unused_imports_if_necessary(); + self.check_for_unused_imports(); } // @@ -1417,7 +1380,7 @@ pub impl Resolver { // Build up the import directives. let module_ = self.get_module_from_parent(parent); match view_path.node { - view_path_simple(binding, full_path, _) => { + view_path_simple(binding, full_path, id) => { let source_ident = *full_path.idents.last(); let subclass = @SingleImport(binding, source_ident); @@ -1425,7 +1388,8 @@ pub impl Resolver { module_, module_path, subclass, - view_path.span); + view_path.span, + id); } view_path_list(_, ref source_idents, _) => { for source_idents.each |source_ident| { @@ -1435,15 +1399,17 @@ pub impl Resolver { module_, copy module_path, subclass, - source_ident.span); + source_ident.span, + source_ident.node.id); } } - view_path_glob(_, _) => { + view_path_glob(_, id) => { self.build_import_directive(privacy, module_, module_path, @GlobImport, - view_path.span); + view_path.span, + id); } } } @@ -1568,10 +1534,7 @@ pub impl Resolver { // avoid creating cycles in the // module graph. - let resolution = - @mut ImportResolution(Public, - dummy_sp(), - @mut ImportState()); + let resolution = @mut ImportResolution(Public, 0); resolution.outstanding_references = 0; match existing_module.parent_link { @@ -1833,9 +1796,10 @@ pub impl Resolver { module_: @mut Module, module_path: ~[ident], subclass: @ImportDirectiveSubclass, - span: span) { + span: span, + id: node_id) { let directive = @ImportDirective(privacy, module_path, - subclass, span); + subclass, span, id); module_.imports.push(directive); // Bump the reference count on the name. Or, if this is a glob, set @@ -1857,16 +1821,7 @@ pub impl Resolver { } None => { debug!("(building import directive) creating new"); - let state = @mut ImportState(); - let resolution = @mut ImportResolution(privacy, - span, - state); - let name = self.idents_to_str(directive.module_path); - // Don't warn about unused intrinsics because they're - // automatically appended to all files - if name == ~"intrinsic::rusti" { - resolution.state.warned = true; - } + let resolution = @mut ImportResolution(privacy, id); resolution.outstanding_references = 1; module_.import_resolutions.insert(target, resolution); } @@ -2062,13 +2017,12 @@ pub impl Resolver { import_directive.span); } GlobImport => { - let span = import_directive.span; let privacy = import_directive.privacy; resolution_result = self.resolve_glob_import(privacy, module_, containing_module, - span); + import_directive.id); } } } @@ -2111,10 +2065,9 @@ pub impl Resolver { privacy: Public, module_def: Some(module), type_def: None, + type_span: None }), value_def: None, - type_span: None, - value_span: None, } } @@ -2196,7 +2149,8 @@ pub impl Resolver { if import_resolution.outstanding_references == 0 => { - fn get_binding(import_resolution: + fn get_binding(this: @mut Resolver, + import_resolution: @mut ImportResolution, namespace: Namespace) -> NamespaceResult { @@ -2213,7 +2167,7 @@ pub impl Resolver { return UnboundResult; } Some(target) => { - import_resolution.state.used = true; + this.used_imports.insert(import_resolution.id); return BoundResult(target.target_module, target.bindings); } @@ -2223,11 +2177,11 @@ pub impl Resolver { // The name is an import which has been fully // resolved. We can, therefore, just follow it. if value_result.is_unknown() { - value_result = get_binding(*import_resolution, + value_result = get_binding(self, *import_resolution, ValueNS); } if type_result.is_unknown() { - type_result = get_binding(*import_resolution, + type_result = get_binding(self, *import_resolution, TypeNS); } } @@ -2352,13 +2306,12 @@ pub impl Resolver { privacy: Privacy, module_: @mut Module, containing_module: @mut Module, - span: span) + id: node_id) -> ResolveResult<()> { // This function works in a highly imperative manner; it eagerly adds // everything it can to the list of import resolutions of the module // node. debug!("(resolving glob import) resolving %? glob import", privacy); - let state = @mut ImportState(); // We must bail out if the node has unresolved imports of any kind // (including globs). @@ -2384,9 +2337,7 @@ pub impl Resolver { None if target_import_resolution.privacy == Public => { // Simple: just copy the old import resolution. let new_import_resolution = - @mut ImportResolution(privacy, - target_import_resolution.span, - state); + @mut ImportResolution(privacy, id); new_import_resolution.value_target = copy target_import_resolution.value_target; new_import_resolution.type_target = @@ -2428,9 +2379,7 @@ pub impl Resolver { match module_.import_resolutions.find(&ident) { None => { // Create a new import resolution from this child. - dest_import_resolution = @mut ImportResolution(privacy, - span, - state); + dest_import_resolution = @mut ImportResolution(privacy, id); module_.import_resolutions.insert (ident, dest_import_resolution); } @@ -2708,7 +2657,7 @@ pub impl Resolver { Some(target) => { debug!("(resolving item in lexical scope) using \ import resolution"); - import_resolution.state.used = true; + self.used_imports.insert(import_resolution.id); return Success(copy target); } } @@ -2979,7 +2928,7 @@ pub impl Resolver { import_resolution.privacy == Public => { debug!("(resolving name in module) resolved to \ import"); - import_resolution.state.used = true; + self.used_imports.insert(import_resolution.id); return Success(copy target); } Some(_) => { @@ -3727,17 +3676,23 @@ pub impl Resolver { type_parameters: &OptVec<TyParam>, visitor: ResolveVisitor) { for type_parameters.each |type_parameter| { - for type_parameter.bounds.each |&bound| { - match bound { - TraitTyParamBound(tref) => { - self.resolve_trait_reference(tref, visitor) - } - RegionTyParamBound => {} - } + for type_parameter.bounds.each |bound| { + self.resolve_type_parameter_bound(bound, visitor); } } } + fn resolve_type_parameter_bound(@mut self, + type_parameter_bound: &TyParamBound, + visitor: ResolveVisitor) { + match *type_parameter_bound { + TraitTyParamBound(tref) => { + self.resolve_trait_reference(tref, visitor) + } + RegionTyParamBound => {} + } + } + fn resolve_trait_reference(@mut self, trait_reference: &trait_ref, visitor: ResolveVisitor) { @@ -4065,6 +4020,13 @@ pub impl Resolver { } } + ty_closure(c) => { + for c.bounds.each |bound| { + self.resolve_type_parameter_bound(bound, visitor); + } + visit_ty(ty, (), visitor); + } + _ => { // Just resolve embedded types. visit_ty(ty, (), visitor); @@ -4447,7 +4409,7 @@ pub impl Resolver { namespace)) { (Some(def), Some(Public)) => { // Found it. - import_resolution.state.used = true; + self.used_imports.insert(import_resolution.id); return ImportNameDefinition(def); } (Some(_), _) | (None, _) => { @@ -5027,8 +4989,8 @@ pub impl Resolver { &mut found_traits, trait_def_id, name); if added { - import_resolution.state.used = - true; + self.used_imports.insert( + import_resolution.id); } } _ => { @@ -5126,86 +5088,50 @@ pub impl Resolver { // resolve data structures. // - fn unused_import_lint_level(@mut self, m: @mut Module) -> level { - let settings = self.session.lint_settings; - match m.def_id { - Some(def) => get_lint_settings_level(settings, unused_imports, - def.node, def.node), - None => get_lint_level(settings.default_settings, unused_imports) - } - } - - fn check_for_unused_imports_if_necessary(@mut self) { - if self.unused_import_lint_level(self.current_module) == allow { - return; - } - - let root_module = self.graph_root.get_module(); - self.check_for_unused_imports_in_module_subtree(root_module); + fn check_for_unused_imports(@mut self) { + let vt = mk_simple_visitor(@SimpleVisitor { + visit_view_item: |vi| self.check_for_item_unused_imports(vi), + .. *default_simple_visitor() + }); + visit_crate(self.crate, (), vt); } - fn check_for_unused_imports_in_module_subtree(@mut self, - module_: @mut Module) { - // If this isn't a local crate, then bail out. We don't need to check - // for unused imports in external crates. - - match module_.def_id { - Some(def_id) if def_id.crate == local_crate => { - // OK. Continue. - } - None => { - // Check for unused imports in the root module. - } - Some(_) => { - // Bail out. - debug!("(checking for unused imports in module subtree) not \ - checking for unused imports for `%s`", - self.module_to_str(module_)); - return; - } - } - - self.check_for_unused_imports_in_module(module_); + fn check_for_item_unused_imports(&mut self, vi: @view_item) { + // Ignore public import statements because there's no way to be sure + // whether they're used or not. Also ignore imports with a dummy span + // because this means that they were generated in some fashion by the + // compiler and we don't need to consider them. + if vi.vis == public { return } + if vi.span == dummy_sp() { return } + + match vi.node { + view_item_extern_mod(*) => {} // ignore + view_item_use(ref path) => { + for path.each |p| { + match p.node { + view_path_simple(_, _, id) | view_path_glob(_, id) => { + if !self.used_imports.contains(&id) { + self.session.add_lint(unused_imports, + id, vi.span, + ~"unused import"); + } + } - for module_.children.each_value |&child_name_bindings| { - match (*child_name_bindings).get_module_if_available() { - None => { - // Nothing to do. - } - Some(child_module) => { - self.check_for_unused_imports_in_module_subtree - (child_module); + view_path_list(_, ref list, _) => { + for list.each |i| { + if !self.used_imports.contains(&i.node.id) { + self.session.add_lint(unused_imports, + i.node.id, i.span, + ~"unused import"); + } + } + } + } } } } - - for module_.anonymous_children.each_value |&child_module| { - self.check_for_unused_imports_in_module_subtree(child_module); - } - } - - fn check_for_unused_imports_in_module(@mut self, module_: @mut Module) { - for module_.import_resolutions.each_value |&import_resolution| { - // Ignore dummy spans for things like automatically injected - // imports for the prelude, and also don't warn about the same - // import statement being unused more than once. Furthermore, if - // the import is public, then we can't be sure whether it's unused - // or not so don't warn about it. - if !import_resolution.state.used && - !import_resolution.state.warned && - import_resolution.span != dummy_sp() && - import_resolution.privacy != Public { - import_resolution.state.warned = true; - let span = import_resolution.span; - self.session.span_lint_level( - self.unused_import_lint_level(module_), - span, - ~"unused import"); - } - } } - // // Diagnostics // diff --git a/src/librustc/middle/resolve_stage0.rs b/src/librustc/middle/resolve_stage0.rs index a404dcf7249..713132b12fc 100644 --- a/src/librustc/middle/resolve_stage0.rs +++ b/src/librustc/middle/resolve_stage0.rs @@ -17,8 +17,7 @@ use metadata::csearch::get_type_name_if_impl; use metadata::cstore::find_extern_mod_stmt_cnum; use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; use middle::lang_items::LanguageItems; -use middle::lint::{allow, level, unused_imports}; -use middle::lint::{get_lint_level, get_lint_settings_level}; +use middle::lint::{allow, level, warn}; use middle::pat_util::pat_bindings; use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm}; @@ -5168,14 +5167,7 @@ pub impl Resolver { // resolve data structures. // - fn unused_import_lint_level(@mut self, m: @mut Module) -> level { - let settings = self.session.lint_settings; - match m.def_id { - Some(def) => get_lint_settings_level(settings, unused_imports, - def.node, def.node), - None => get_lint_level(settings.default_settings, unused_imports) - } - } + fn unused_import_lint_level(@mut self, _: @mut Module) -> level { warn } fn check_for_unused_imports_if_necessary(@mut self) { if self.unused_import_lint_level(self.current_module) == allow { @@ -5237,12 +5229,7 @@ pub impl Resolver { !import_resolution.state.warned && import_resolution.span != dummy_sp() && import_resolution.privacy != Public { - import_resolution.state.warned = true; - let span = import_resolution.span; - self.session.span_lint_level( - self.unused_import_lint_level(module_), - span, - ~"unused import"); + // I swear I work in not(stage0)! } } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index e14d6d79ab5..b5cca20d8ec 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2228,8 +2228,7 @@ pub fn register_fn_fuller(ccx: @CrateContext, mangle_exported_name(ccx, /*bad*/copy path, node_type) }; - // XXX: Bad copy. - let llfn: ValueRef = decl_fn(ccx.llmod, copy ps, cc, llfty); + let llfn: ValueRef = decl_fn(ccx.llmod, ps, cc, llfty); ccx.item_symbols.insert(node_id, ps); // FIXME #4404 android JNI hacks diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index 7f1f35b33ab..e8853fd20e9 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -544,7 +544,7 @@ pub fn AtomicLoad(cx: block, PointerVal: ValueRef, order: AtomicOrdering) -> Val return llvm::LLVMGetUndef(ccx.int_type); } count_insn(cx, "load.atomic"); - return llvm::LLVMBuildAtomicLoad(B(cx), PointerVal, order); + return llvm::LLVMBuildAtomicLoad(B(cx), PointerVal, noname(), order); } } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 374bb23f2cb..8055d919ffd 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -101,7 +101,6 @@ use middle::ty; use util::common::indenter; use util::ppaux::ty_to_str; -use core::container::Set; // XXX: this should not be necessary use core::to_bytes; use syntax::ast; use syntax::codemap::span; diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 5b1cae473f7..fd545ca2c6e 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -818,6 +818,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, sigil: ast::BorrowedSigil, onceness: ast::Many, region: ty::re_bound(ty::br_anon(0)), + bounds: ty::EmptyBuiltinBounds(), sig: FnSig { bound_lifetime_names: opt_vec::Empty, inputs: ~[ star_u8 ], diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index bdbb45bf275..6eb2540f1df 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -795,8 +795,11 @@ pub fn make_impl_vtable(ccx: @CrateContext, let _icx = ccx.insn_ctxt("impl::make_impl_vtable"); let tcx = ccx.tcx; - // XXX: This should support multiple traits. - let trt_id = ty::impl_trait_refs(tcx, impl_id)[0].def_id; + let trt_id = match ty::impl_trait_ref(tcx, impl_id) { + Some(t_id) => t_id.def_id, + None => ccx.sess.bug("make_impl_vtable: don't know how to \ + make a vtable for a type impl!") + }; let has_tps = !ty::lookup_item_type(ccx.tcx, impl_id).generics.type_param_defs.is_empty(); diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 3b0c03cdc99..ccc906f2ee8 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -330,6 +330,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt, sigil: sigil, onceness: ast::Many, region: ty::re_static, + bounds: ty::EmptyBuiltinBounds(), sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty, inputs: ~[], output: ty::mk_nil()}}) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4ee2c5b0100..c51fba8a62b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -22,7 +22,7 @@ use middle::typeck; use middle; use util::ppaux::{note_and_explain_region, bound_region_to_str}; use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str}; -use util::ppaux::Repr; +use util::ppaux::{Repr, UserString}; use util::common::{indenter}; use util::enum_set::{EnumSet, CLike}; @@ -96,9 +96,7 @@ pub struct mt { mutbl: ast::mutability, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum vstore { vstore_fixed(uint), vstore_uniq, @@ -106,9 +104,7 @@ pub enum vstore { vstore_slice(Region) } -#[auto_encode] -#[auto_decode] -#[deriving(Eq, IterBytes)] +#[deriving(Eq, IterBytes, Encodable, Decodable)] pub enum TraitStore { BoxTraitStore, // @Trait UniqTraitStore, // ~Trait @@ -117,9 +113,7 @@ pub enum TraitStore { // XXX: This should probably go away at some point. Maybe after destructors // do? -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum SelfMode { ByCopy, ByRef, @@ -197,27 +191,22 @@ pub enum ast_ty_to_ty_cache_entry { pub type opt_region_variance = Option<region_variance>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Decodable, Encodable)] pub enum region_variance { rv_covariant, rv_invariant, rv_contravariant } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] pub enum AutoAdjustment { AutoAddEnv(ty::Region, ast::Sigil), AutoDerefRef(AutoDerefRef) } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] pub struct AutoDerefRef { autoderefs: uint, autoref: Option<AutoRef> } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] pub enum AutoRef { /// Convert from T to &T AutoPtr(Region, ast::mutability), @@ -401,7 +390,8 @@ pub struct ClosureTy { sigil: ast::Sigil, onceness: ast::Onceness, region: Region, - sig: FnSig + bounds: BuiltinBounds, + sig: FnSig, } /** @@ -453,9 +443,7 @@ pub struct param_ty { } /// Representation of regions: -#[auto_encode] -#[auto_decode] -#[deriving(Eq, IterBytes)] +#[deriving(Eq, IterBytes, Encodable, Decodable)] pub enum Region { /// Bound regions are found (primarily) in function types. They indicate /// region parameters that have yet to be replaced with actual regions @@ -501,17 +489,13 @@ pub impl Region { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq, IterBytes)] +#[deriving(Eq, IterBytes, Encodable, Decodable)] pub struct FreeRegion { scope_id: node_id, bound_region: bound_region } -#[auto_encode] -#[auto_decode] -#[deriving(Eq, IterBytes)] +#[deriving(Eq, IterBytes, Encodable, Decodable)] pub enum bound_region { /// The self region for structs, impls (&T in a type defn or &'self T) br_self, @@ -702,6 +686,7 @@ pub enum type_err { terr_int_mismatch(expected_found<IntVarValue>), terr_float_mismatch(expected_found<ast::float_ty>), terr_traits(expected_found<ast::def_id>), + terr_builtin_bounds(expected_found<BuiltinBounds>), } #[deriving(Eq, IterBytes)] @@ -724,6 +709,15 @@ pub fn EmptyBuiltinBounds() -> BuiltinBounds { EnumSet::empty() } +pub fn AllBuiltinBounds() -> BuiltinBounds { + let mut set = EnumSet::empty(); + set.add(BoundCopy); + set.add(BoundStatic); + set.add(BoundOwned); + set.add(BoundConst); + set +} + impl CLike for BuiltinBound { pub fn to_uint(&self) -> uint { *self as uint @@ -742,9 +736,7 @@ pub struct IntVid(uint); #[deriving(Eq)] pub struct FloatVid(uint); -#[deriving(Eq)] -#[auto_encode] -#[auto_decode] +#[deriving(Eq, Encodable, Decodable)] pub struct RegionVid { id: uint } @@ -777,8 +769,7 @@ impl to_bytes::IterBytes for InferTy { } } -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub enum InferRegion { ReVar(RegionVid), ReSkolemized(uint, bound_region) @@ -3189,6 +3180,7 @@ pub fn adjust_ty(cx: ctxt, sigil: s, onceness: ast::Many, region: r, + bounds: ty::AllBuiltinBounds(), sig: copy b.sig}) } ref b => { @@ -3717,6 +3709,19 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { item_path_str(cx, values.expected), item_path_str(cx, values.found)) } + terr_builtin_bounds(values) => { + if values.expected.is_empty() { + fmt!("expected no bounds but found `%s`", + values.found.user_string(cx)) + } else if values.found.is_empty() { + fmt!("expected bounds `%s` but found no bounds", + values.expected.user_string(cx)) + } else { + fmt!("expected bounds `%s` but found bounds `%s`", + values.expected.user_string(cx), + values.found.user_string(cx)) + } + } terr_self_substs => { ~"inconsistent self substitution" // XXX this is more of a bug } @@ -3878,23 +3883,23 @@ pub fn trait_method_def_ids(cx: ctxt, id: ast::def_id) -> @~[def_id] { || @csearch::get_trait_method_def_ids(cx.cstore, id)) } -pub fn impl_trait_refs(cx: ctxt, id: ast::def_id) -> ~[@TraitRef] { +pub fn impl_trait_ref(cx: ctxt, id: ast::def_id) -> Option<@TraitRef> { if id.crate == ast::local_crate { - debug!("(impl_traits) searching for trait impl %?", id); + debug!("(impl_trait_ref) searching for trait impl %?", id); match cx.items.find(&id.node) { Some(&ast_map::node_item(@ast::item { node: ast::item_impl(_, opt_trait, _, _), _}, _)) => { match opt_trait { - Some(t) => ~[ty::node_id_to_trait_ref(cx, t.ref_id)], - None => ~[] + Some(t) => Some(ty::node_id_to_trait_ref(cx, t.ref_id)), + None => None } } - _ => ~[] + _ => None } } else { - csearch::get_impl_traits(cx, id) + csearch::get_impl_trait(cx, id) } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index de6064b0a31..222493b0564 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -59,6 +59,7 @@ use middle::ty; use middle::typeck::rscope::in_binding_rscope; use middle::typeck::rscope::{region_scope, RegionError}; use middle::typeck::rscope::RegionParamNames; +use middle::typeck::lookup_def_tcx; use syntax::abi::AbiSet; use syntax::{ast, ast_util}; @@ -220,7 +221,6 @@ pub fn ast_path_to_trait_ref<AC:AstConv,RS:region_scope + Copy + 'static>( return trait_ref; } - pub fn ast_path_to_ty<AC:AstConv,RS:region_scope + Copy + 'static>( this: &AC, rscope: &RS, @@ -377,11 +377,13 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Copy + 'static>( bf.abis, &bf.lifetimes, &bf.decl)) } ast::ty_closure(ref f) => { + let bounds = conv_builtin_bounds(this.tcx(), &f.bounds); let fn_decl = ty_of_closure(this, rscope, f.sigil, f.purity, f.onceness, + bounds, f.region, &f.decl, None, @@ -646,17 +648,18 @@ fn ty_of_method_or_bare_fn<AC:AstConv,RS:region_scope + Copy + 'static>( } pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>( - this: &AC, - rscope: &RS, - sigil: ast::Sigil, - purity: ast::purity, - onceness: ast::Onceness, - opt_lifetime: Option<@ast::Lifetime>, - decl: &ast::fn_decl, - expected_sig: Option<ty::FnSig>, - lifetimes: &OptVec<ast::Lifetime>, - span: span) - -> ty::ClosureTy + this: &AC, + rscope: &RS, + sigil: ast::Sigil, + purity: ast::purity, + onceness: ast::Onceness, + bounds: ty::BuiltinBounds, + opt_lifetime: Option<@ast::Lifetime>, + decl: &ast::fn_decl, + expected_sig: Option<ty::FnSig>, + lifetimes: &OptVec<ast::Lifetime>, + span: span) + -> ty::ClosureTy { // The caller should not both provide explicit bound lifetime // names and expected types. Either we infer the bound lifetime @@ -713,8 +716,69 @@ pub fn ty_of_closure<AC:AstConv,RS:region_scope + Copy + 'static>( sigil: sigil, onceness: onceness, region: bound_region, + bounds: bounds, sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names, inputs: input_tys, output: output_ty} } } + +fn conv_builtin_bounds(tcx: ty::ctxt, + ast_bounds: &OptVec<ast::TyParamBound>) + -> ty::BuiltinBounds { + //! Converts a list of bounds from the AST into a `BuiltinBounds` + //! struct. Reports an error if any of the bounds that appear + //! in the AST refer to general traits and not the built-in traits + //! like `Copy` or `Owned`. Used to translate the bounds that + //! appear in closure and trait types, where only builtin bounds are + //! legal. + + let mut builtin_bounds = ty::EmptyBuiltinBounds(); + for ast_bounds.each |ast_bound| { + match *ast_bound { + ast::TraitTyParamBound(b) => { + match lookup_def_tcx(tcx, b.path.span, b.ref_id) { + ast::def_trait(trait_did) => { + if try_add_builtin_trait(tcx, + trait_did, + &mut builtin_bounds) { + loop; // success + } + } + _ => { } + } + tcx.sess.span_fatal( + b.path.span, + fmt!("only the builtin traits can be used \ + as closure or object bounds")); + } + ast::RegionTyParamBound => { + builtin_bounds.add(ty::BoundStatic); + } + } + } + builtin_bounds +} + +pub fn try_add_builtin_trait(tcx: ty::ctxt, + trait_def_id: ast::def_id, + builtin_bounds: &mut ty::BuiltinBounds) -> bool { + //! Checks whether `trait_ref` refers to one of the builtin + //! traits, like `Copy` or `Owned`, and adds the corresponding + //! bound to the set `builtin_bounds` if so. Returns true if `trait_ref` + //! is a builtin trait. + + let li = &tcx.lang_items; + if trait_def_id == li.owned_trait() { + builtin_bounds.add(ty::BoundOwned); + true + } else if trait_def_id == li.copy_trait() { + builtin_bounds.add(ty::BoundCopy); + true + } else if trait_def_id == li.const_trait() { + builtin_bounds.add(ty::BoundConst); + true + } else { + false + } +} diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 548b9e454ce..8d32bb7f677 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1661,7 +1661,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let (expected_sig, expected_purity, expected_sigil, - expected_onceness) = { + expected_onceness, + expected_bounds) = { match expected_sty { Some(ty::ty_closure(ref cenv)) => { let id = expr.id; @@ -1669,11 +1670,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, replace_bound_regions_in_fn_sig( tcx, @Nil, None, &cenv.sig, |br| ty::re_bound(ty::br_cap_avoid(id, @br))); - (Some(sig), cenv.purity, cenv.sigil, cenv.onceness) + (Some(sig), cenv.purity, cenv.sigil, + cenv.onceness, cenv.bounds) } _ => { // Not an error! Means we're inferring the closure type - (None, ast::impure_fn, ast::BorrowedSigil, ast::Many) + (None, ast::impure_fn, ast::BorrowedSigil, + ast::Many, ty::EmptyBuiltinBounds()) } } }; @@ -1687,15 +1690,16 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // construct the function type let fn_ty = astconv::ty_of_closure(fcx, - fcx, - sigil, - purity, - expected_onceness, - None, - decl, - expected_sig, - &opt_vec::Empty, - expr.span); + fcx, + sigil, + purity, + expected_onceness, + expected_bounds, + None, + decl, + expected_sig, + &opt_vec::Empty, + expr.span); let fty_sig; let fty = if error_happened { @@ -3526,6 +3530,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { sigil: ast::BorrowedSigil, onceness: ast::Once, region: ty::re_bound(ty::br_anon(0)), + bounds: ty::EmptyBuiltinBounds(), sig: ty::FnSig { bound_lifetime_names: opt_vec::Empty, inputs: ~[ty::mk_imm_ptr(ccx.tcx, ty::mk_mach_uint(ast::ty_u8))], diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 42ab9d97729..2e2b4550f63 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -261,24 +261,14 @@ fn lookup_vtable(vcx: &VtableContext, } impls_seen.insert(im.did); - // ty::impl_traits gives us the list of all - // traits that im implements. Again, usually - // there's just one. + // ty::impl_traits gives us the trait im implements, + // if there is one (there's either zero or one). // - // For example, if im represented the struct - // in: - // - // struct foo : baz<int>, bar, quux { ... } - // - // then ty::impl_traits would return - // - // ~[baz<int>, bar, quux] - // - // For each of the traits foo implements, if - // it's the same trait as trait_ref, we need to + // If foo implements a trait t, and if t is the + // same trait as trait_ref, we need to // unify it with trait_ref in order to get all // the ty vars sorted out. - for ty::impl_trait_refs(tcx, im.did).each |&of_trait_ref| + for ty::impl_trait_ref(tcx, im.did).each |&of_trait_ref| { if of_trait_ref.def_id != trait_ref.def_id { loop; } @@ -456,8 +446,12 @@ fn connect_trait_tps(vcx: &VtableContext, { let tcx = vcx.tcx(); - // XXX: This should work for multiple traits. - let impl_trait_ref = ty::impl_trait_refs(tcx, impl_did)[0]; + let impl_trait_ref = match ty::impl_trait_ref(tcx, impl_did) { + Some(t) => t, + None => vcx.tcx().sess.span_bug(location_info.span, + "connect_trait_tps invoked on a type impl") + }; + let impl_trait_ref = (*impl_trait_ref).subst(tcx, impl_substs); relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref); } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index c64a0235eb1..311aa551601 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -16,7 +16,7 @@ use driver; -use metadata::csearch::{each_path, get_impl_traits}; +use metadata::csearch::{each_path, get_impl_trait}; use metadata::csearch::{get_impls_for_mod}; use metadata::csearch; use metadata::cstore::{CStore, iter_crate_data}; @@ -898,13 +898,13 @@ pub impl CoherenceChecker { let self_type = lookup_item_type(self.crate_context.tcx, implementation.did); - let associated_traits = get_impl_traits(self.crate_context.tcx, + let associated_traits = get_impl_trait(self.crate_context.tcx, implementation.did); // Do a sanity check to make sure that inherent methods have base // types. - if associated_traits.len() == 0 { + if associated_traits.is_none() { match get_base_type_def_id(self.inference_context, dummy_sp(), self_type.ty) { @@ -940,7 +940,7 @@ pub impl CoherenceChecker { Some(base_type_def_id) => { // inherent methods apply to `impl Type` but not // `impl Trait for Type`: - if associated_traits.len() == 0 { + if associated_traits.is_none() { self.add_inherent_method(base_type_def_id, *implementation); } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 4773e637c35..6c7f73177fa 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1207,25 +1207,21 @@ pub fn ty_generics(ccx: &CrateCtxt, builtin_bounds: ty::EmptyBuiltinBounds(), trait_bounds: ~[] }; - for ast_bounds.each |b| { - match b { - &TraitTyParamBound(b) => { - let li = &ccx.tcx.lang_items; + for ast_bounds.each |ast_bound| { + match *ast_bound { + TraitTyParamBound(b) => { let ty = ty::mk_param(ccx.tcx, param_ty.idx, param_ty.def_id); let trait_ref = instantiate_trait_ref(ccx, b, rp, generics, ty); - if trait_ref.def_id == li.owned_trait() { - param_bounds.builtin_bounds.add(ty::BoundOwned); - } else if trait_ref.def_id == li.copy_trait() { - param_bounds.builtin_bounds.add(ty::BoundCopy); - } else if trait_ref.def_id == li.const_trait() { - param_bounds.builtin_bounds.add(ty::BoundConst); - } else { + if !astconv::try_add_builtin_trait( + ccx.tcx, trait_ref.def_id, + &mut param_bounds.builtin_bounds) + { // Must be a user-defined trait param_bounds.trait_bounds.push(trait_ref); } } - &RegionTyParamBound => { + RegionTyParamBound => { param_bounds.builtin_bounds.add(ty::BoundStatic); } } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index fcd2c6ffe59..3c337d17f86 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -56,6 +56,7 @@ use middle::ty::{FloatVar, FnSig, IntVar, TyVar}; use middle::ty::{IntType, UintType, substs}; +use middle::ty::{BuiltinBounds}; use middle::ty; use middle::typeck::infer::glb::Glb; use middle::typeck::infer::lub::Lub; @@ -100,6 +101,7 @@ pub trait Combine { fn purities(&self, a: purity, b: purity) -> cres<purity>; fn abis(&self, a: AbiSet, b: AbiSet) -> cres<AbiSet>; fn oncenesses(&self, a: Onceness, b: Onceness) -> cres<Onceness>; + fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds>; fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>; fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region>; @@ -372,11 +374,13 @@ pub fn super_closure_tys<C:Combine>( let r = if_ok!(this.contraregions(a_f.region, b_f.region)); let purity = if_ok!(this.purities(a_f.purity, b_f.purity)); let onceness = if_ok!(this.oncenesses(a_f.onceness, b_f.onceness)); + let bounds = if_ok!(this.bounds(a_f.bounds, b_f.bounds)); let sig = if_ok!(this.fn_sigs(&a_f.sig, &b_f.sig)); Ok(ty::ClosureTy {purity: purity, sigil: p, onceness: onceness, region: r, + bounds: bounds, sig: sig}) } diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 42e42ddb1e7..9ade6de6cf4 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::ty::{BuiltinBounds}; use middle::ty::RegionVid; use middle::ty; use middle::typeck::infer::combine::*; @@ -114,6 +115,12 @@ impl Combine for Glb { } } + fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> { + // More bounds is a subtype of fewer bounds, so + // the GLB (mutual subtype) is the union. + Ok(a.union(b)) + } + fn regions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> { debug!("%s.regions(%?, %?)", self.tag(), diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 20a051f0531..82fd4e3ae6d 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::ty::{BuiltinBounds}; use middle::ty::RegionVid; use middle::ty; use middle::typeck::infer::combine::*; @@ -100,6 +101,12 @@ impl Combine for Lub { } } + fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> { + // More bounds is a subtype of fewer bounds, so + // the LUB (mutual supertype) is the intersection. + Ok(a.intersection(b)) + } + fn contraregions(&self, a: ty::Region, b: ty::Region) -> cres<ty::Region> { return Glb(**self).regions(a, b); diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index ca083bc2d86..8da3d7bfa00 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::ty::{BuiltinBounds}; use middle::ty; use middle::ty::TyVar; use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; @@ -99,6 +100,19 @@ impl Combine for Sub { }) } + fn bounds(&self, a: BuiltinBounds, b: BuiltinBounds) -> cres<BuiltinBounds> { + // More bounds is a subtype of fewer bounds. + // + // e.g., fn:Copy() <: fn(), because the former is a function + // that only closes over copyable things, but the latter is + // any function at all. + if a.contains(b) { + Ok(a) + } else { + Err(ty::terr_builtin_bounds(expected_found(self, a, b))) + } + } + fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t> { debug!("%s.tys(%s, %s)", self.tag(), a.inf_str(self.infcx), b.inf_str(self.infcx)); diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 0dec0fc937b..dd313c54efb 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -73,8 +73,7 @@ pub mod infer; pub mod collect; pub mod coherence; -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub enum method_origin { // supertrait method invoked on "self" inside a default method // first field is supertrait ID; @@ -98,8 +97,7 @@ pub enum method_origin { // details for a method invoked with a receiver whose type is a type parameter // with a bounded trait. -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub struct method_param { // the trait containing the method to be invoked trait_id: ast::def_id, diff --git a/src/librustc/util/enum_set.rs b/src/librustc/util/enum_set.rs index dae4bb69c61..2e6c4ee3eaa 100644 --- a/src/librustc/util/enum_set.rs +++ b/src/librustc/util/enum_set.rs @@ -8,11 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[cfg(stage0)] use core; #[deriving(Eq, IterBytes)] pub struct EnumSet<E> { - bits: uint + // We must maintain the invariant that no bits are set + // for which no variant exists + priv bits: uint } pub trait CLike { @@ -37,10 +40,18 @@ pub impl<E:CLike> EnumSet<E> { (self.bits & e.bits) != 0 } + fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> { + EnumSet {bits: self.bits & e.bits} + } + fn contains(&self, e: EnumSet<E>) -> bool { (self.bits & e.bits) == e.bits } + fn union(&self, e: EnumSet<E>) -> EnumSet<E> { + EnumSet {bits: self.bits | e.bits} + } + fn add(&mut self, e: E) { self.bits |= bit(e); } diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index 5b19a3bd660..680e0924d79 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -28,3 +28,7 @@ condition! { condition! { missing_pkg_files: (super::PkgId) -> (); } + +condition! { + bad_pkg_id: (super::Path, ~str) -> ::util::PkgId; +} diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 477a7af4550..bbd8d092354 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -10,12 +10,10 @@ // rustpkg utilities having to do with paths and directories -use util::PkgId; +pub use util::{PkgId, RemotePath, LocalPath}; use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use core::os::mkdir_recursive; - -#[deriving(Eq)] -pub enum OutputType { Main, Lib, Bench, Test } +pub use util::{normalize, OutputType, Main, Lib, Bench, Test}; /// Returns the value of RUST_PATH, as a list /// of Paths. In general this should be read from the @@ -31,24 +29,6 @@ pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; /// succeeded. pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) } -/// Replace all occurrences of '-' in the stem part of path with '_' -/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux -/// as the same name -pub fn normalize(p: ~Path) -> ~Path { - match p.filestem() { - None => p, - Some(st) => { - let replaced = str::replace(st, "-", "_"); - if replaced != st { - ~p.with_filestem(replaced) - } - else { - p - } - } - } -} - // n.b. So far this only handles local workspaces // n.b. The next three functions ignore the package version right // now. Should fix that. @@ -56,7 +36,7 @@ pub fn normalize(p: ~Path) -> ~Path { /// True if there's a directory in <workspace> with /// pkgid's short name pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { - let pkgpath = workspace.push("src").push(pkgid.path.to_str()); + let pkgpath = workspace.push("src").push(pkgid.local_path.to_str()); os::path_is_dir(&pkgpath) } @@ -64,34 +44,58 @@ pub fn workspace_contains_package_id(pkgid: &PkgId, workspace: &Path) -> bool { /// Doesn't check that it exists. pub fn pkgid_src_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { let result = workspace.push("src"); - result.push(pkgid.path.to_str()) + result.push(pkgid.local_path.to_str()) } /// Figure out what the executable name for <pkgid> in <workspace>'s build /// directory is, and if the file exists, return it. pub fn built_executable_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { let mut result = workspace.push("build"); - result = result.push_rel(&pkgid.path); // should use a target-specific subdirectory - result = mk_output_path(Main, fmt!("%s-%s", pkgid.path.to_str(), pkgid.version.to_str()), - result); + result = mk_output_path(Main, pkgid, &result); debug!("built_executable_in_workspace: checking whether %s exists", result.to_str()); if os::path_exists(&result) { Some(result) } else { + // This is not an error, but it's worth logging it + error!(fmt!("built_executable_in_workspace: %s does not exist", result.to_str())); None } } -/// Figure out what the library name for <pkgid> in <workspace>'s build +/// Figure out what the test name for <pkgid> in <workspace>'s build /// directory is, and if the file exists, return it. -pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { +pub fn built_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { + output_in_workspace(pkgid, workspace, Test) +} + +/// Figure out what the test name for <pkgid> in <workspace>'s build +/// directory is, and if the file exists, return it. +pub fn built_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { + output_in_workspace(pkgid, workspace, Bench) +} + +fn output_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Option<Path> { let mut result = workspace.push("build"); - result = result.push_rel(&pkgid.path); // should use a target-specific subdirectory - result = mk_output_path(Lib, pkgid.path.to_str(), result); + result = mk_output_path(what, pkgid, &result); + debug!("output_in_workspace: checking whether %s exists", + result.to_str()); + if os::path_exists(&result) { + Some(result) + } + else { + error!(fmt!("output_in_workspace: %s does not exist", result.to_str())); + None + } +} + +/// Figure out what the library name for <pkgid> in <workspace>'s build +/// directory is, and if the file exists, return it. +pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Path> { + let result = mk_output_path(Lib, pkgid, &workspace.push("build")); debug!("built_library_in_workspace: checking whether %s exists", result.to_str()); @@ -100,8 +104,7 @@ pub fn built_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Option<Pat let dir_contents = os::list_dir(&result.pop()); debug!("dir has %? entries", dir_contents.len()); - // n.b. This code assumes the pkgid's path only has one element - let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.path.to_str()); + let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.short_name); let lib_filetype = fmt!("%s%s", pkgid.version.to_str(), os::consts::DLL_SUFFIX); debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype); @@ -173,12 +176,14 @@ pub fn target_library_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { /// Returns the test executable that would be installed for <pkgid> /// in <workspace> +/// note that we *don't* install test executables, so this is just for unit testing pub fn target_test_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { target_file_in_workspace(pkgid, workspace, Test) } /// Returns the bench executable that would be installed for <pkgid> /// in <workspace> +/// note that we *don't* install bench executables, so this is just for unit testing pub fn target_bench_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { target_file_in_workspace(pkgid, workspace, Bench) } @@ -187,18 +192,14 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path, what: OutputType) -> Path { use conditions::bad_path::cond; - let (subdir, create_dir) = match what { - Main => ("bin", true), Lib => ("lib", true), Test | Bench => ("build", false) + let subdir = match what { + Lib => "lib", Main | Test | Bench => "bin" }; let result = workspace.push(subdir); - if create_dir { - if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { - cond.raise((copy result, - fmt!("I couldn't create the %s dir", subdir))); - } + if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { + cond.raise((copy result, fmt!("I couldn't create the %s dir", subdir))); } - mk_output_path(what, pkgid.path.to_str(), result) - + mk_output_path(what, pkgid, &result) } /// Return the directory for <pkgid>'s build artifacts in <workspace>. @@ -209,7 +210,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { let mut result = workspace.push("build"); // n.b. Should actually use a target-specific // subdirectory of build/ - result = result.push(normalize(~copy pkgid.path).to_str()); + result = result.push_rel(&*pkgid.local_path); if os::path_exists(&result) || os::mkdir_recursive(&result, u_rwx) { result } @@ -220,15 +221,26 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path { /// Return the output file for a given directory name, /// given whether we're building a library and whether we're building tests -pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path { - match what { - Lib => dir.push(os::dll_filename(short_name)), - _ => dir.push(fmt!("%s%s%s", short_name, +pub fn mk_output_path(what: OutputType, pkg_id: &PkgId, workspace: &Path) -> Path { + let short_name_with_version = pkg_id.short_name_with_version(); + // Not local_path.dir_path()! For package foo/bar/blat/, we want + // the executable blat-0.5 to live under blat/ + let dir = workspace.push_rel(&*pkg_id.local_path); + debug!("mk_output_path: short_name = %s, path = %s", + if what == Lib { copy short_name_with_version } else { copy pkg_id.short_name }, + dir.to_str()); + let output_path = match what { + // this code is duplicated from elsewhere; fix this + Lib => dir.push(os::dll_filename(short_name_with_version)), + // executable names *aren't* versioned + _ => dir.push(fmt!("%s%s%s", copy pkg_id.short_name, match what { Test => "test", Bench => "bench", _ => "" } os::EXE_SUFFIX)) - } + }; + debug!("mk_output_path: returning %s", output_path.to_str()); + output_path } diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index 884f0a73589..a69613776ef 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -30,12 +30,10 @@ use rustc::metadata::filesearch; use std::{getopts}; use syntax::{ast, diagnostic}; use util::*; -use path_util::normalize; -use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace}; +use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace, u_rwx}; use path_util::{built_executable_in_workspace, built_library_in_workspace}; use path_util::{target_executable_in_workspace, target_library_in_workspace}; use workspace::pkg_parent_workspaces; -use rustc::driver::session::{lib_crate, bin_crate, crate_type}; use context::Ctx; mod conditions; @@ -159,27 +157,6 @@ impl<'self> PkgScript<'self> { impl Ctx { fn run(&self, cmd: ~str, args: ~[~str]) { - let root = util::root(); - - util::need_dir(&root); - util::need_dir(&root.push(~"work")); - util::need_dir(&root.push(~"lib")); - util::need_dir(&root.push(~"bin")); - util::need_dir(&root.push(~"tmp")); - - fn sep_name_vers(in: ~str) -> (Option<~str>, Option<~str>) { - let mut name = None; - let mut vers = None; - - for str::each_split_char(in, '@') |s| { - if name.is_none() { name = Some(s.to_owned()); } - else if vers.is_none() { vers = Some(s.to_owned()); } - else { break; } - } - - (name, vers) - } - match cmd { ~"build" => { if args.len() < 1 { @@ -229,9 +206,7 @@ impl Ctx { return usage::uninstall(); } - let (name, vers) = sep_name_vers(copy args[0]); - - self.prefer(name.get(), vers); + self.prefer(args[0], None); } ~"test" => { self.test(); @@ -241,20 +216,16 @@ impl Ctx { return usage::uninstall(); } - let (name, vers) = sep_name_vers(copy args[0]); - - self.uninstall(name.get(), vers); + self.uninstall(args[0], None); } ~"unprefer" => { if args.len() < 1 { return usage::uninstall(); } - let (name, vers) = sep_name_vers(copy args[0]); - - self.unprefer(name.get(), vers); + self.unprefer(args[0], None); } - _ => fail!("reached an unhandled command") + _ => fail!(fmt!("I don't know the command `%s`", cmd)) } } @@ -269,7 +240,7 @@ impl Ctx { debug!("Destination dir = %s", build_dir.to_str()); // Create the package source - let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, pkgid); + let mut src = PkgSrc::new(workspace, &build_dir, pkgid); debug!("Package src = %?", src); // Is there custom build logic? If so, use it @@ -307,7 +278,6 @@ impl Ctx { // Build it! src.build(&build_dir, cfgs, self.sysroot_opt); } - } fn clean(&self, workspace: &Path, id: &PkgId) { @@ -319,7 +289,7 @@ impl Ctx { util::note(fmt!("Cleaning package %s (removing directory %s)", id.to_str(), dir.to_str())); if os::path_exists(&dir) { - util::remove_dir_r(&dir); + os::remove_dir_recursive(&dir); util::note(fmt!("Removed directory %s", dir.to_str())); } @@ -337,6 +307,8 @@ impl Ctx { // Should use RUST_PATH in the future. // Also should use workcache to not build if not necessary. self.build(workspace, id); + debug!("install: workspace = %s, id = %s", workspace.to_str(), + id.to_str()); // Now copy stuff into the install dirs let maybe_executable = built_executable_in_workspace(id, workspace); @@ -344,104 +316,29 @@ impl Ctx { let target_exec = target_executable_in_workspace(id, workspace); let target_lib = target_library_in_workspace(id, workspace); + debug!("target_exec = %s target_lib = %s \ + maybe_executable = %? maybe_library = %?", + target_exec.to_str(), target_lib.to_str(), + maybe_executable, maybe_library); + for maybe_executable.each |exec| { debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str()); - if !os::copy_file(exec, &target_exec) { + if !(os::mkdir_recursive(&target_exec.dir_path(), u_rwx) && + os::copy_file(exec, &target_exec)) { cond.raise((copy *exec, copy target_exec)); } } for maybe_library.each |lib| { debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str()); - if !os::copy_file(lib, &target_lib) { + if !(os::mkdir_recursive(&target_lib.dir_path(), u_rwx) && + os::copy_file(lib, &target_lib)) { cond.raise((copy *lib, copy target_lib)); } } } - fn fetch(&self, _dir: &Path, _url: ~str, _target: Option<~str>) { - // stub - fail!("fetch not yet implemented"); - } - - fn fetch_curl(&self, dir: &Path, url: ~str) { - util::note(fmt!("fetching from %s using curl", url)); - - let tar = dir.dir_path().push(&dir.file_path().to_str() + ~".tar"); - - if run::program_output(~"curl", ~[~"-f", ~"-s", - ~"-o", tar.to_str(), - url]).status != 0 { - util::error(~"fetching failed: downloading using curl failed"); - - fail!(); - } - - if run::program_output(~"tar", ~[~"-x", ~"--strip-components=1", - ~"-C", dir.to_str(), ~"-f", - tar.to_str()]).status != 0 { - util::error(~"fetching failed: extracting using tar failed" + - ~"(is it a valid tar archive?)"); - - fail!(); - } - } - - fn fetch_git(&self, dir: &Path, url: ~str, mut target: Option<~str>) { - util::note(fmt!("fetching from %s using git", url)); - - // Git can't clone into a non-empty directory - util::remove_dir_r(dir); - - if run::program_output(~"git", ~[~"clone", url, - dir.to_str()]).status != 0 { - util::error(~"fetching failed: can't clone repository"); - fail!(); - } - - if !target.is_none() { - let mut success = true; - - do util::temp_change_dir(dir) { - success = run::program_output(~"git", - ~[~"checkout", - target.swap_unwrap()]).status != 0 - } - - if !success { - util::error(~"fetching failed: can't checkout target"); - fail!(); - } - } - } - - fn prefer(&self, id: ~str, vers: Option<~str>) { - let package = match util::get_pkg(id, vers) { - result::Ok(package) => package, - result::Err(err) => { - util::error(err); - fail!(); // Condition? - } - }; - let name = package.id.path.to_str(); // ??? - - util::note(fmt!("preferring %s v%s", name, package.id.version.to_str())); - - let bin_dir = util::root().push(~"bin"); - - for package.bins.each |&bin| { - let path = Path(bin); - let mut name = None; - for str::each_split_char(path.file_path().to_str(), '-') |s| { - name = Some(s.to_owned()); - break; - } - let out = bin_dir.push(name.unwrap()); - - util::link_exe(&path, &out); - util::note(fmt!("linked %s", out.to_str())); - } - - util::note(fmt!("preferred %s v%s", name, package.id.version.to_str())); + fn prefer(&self, _id: &str, _vers: Option<~str>) { + fail!(~"prefer not yet implemented"); } fn test(&self) { @@ -449,15 +346,16 @@ impl Ctx { fail!("test not yet implemented"); } - fn uninstall(&self, _id: ~str, _vers: Option<~str>) { + fn uninstall(&self, _id: &str, _vers: Option<~str>) { fail!("uninstall not yet implemented"); } - fn unprefer(&self, _id: ~str, _vers: Option<~str>) { + fn unprefer(&self, _id: &str, _vers: Option<~str>) { fail!("unprefer not yet implemented"); } } + pub fn main() { io::println("WARNING: The Rust package manager is experimental and may be unstable"); @@ -518,32 +416,6 @@ pub struct Crate { cfgs: ~[~str] } -pub struct Listener { - cmds: ~[~str], - cb: ~fn() -} - -pub fn run(listeners: ~[Listener]) { - let rcmd = copy os::args()[2]; - let mut found = false; - - for listeners.each |listener| { - for listener.cmds.each |&cmd| { - if cmd == rcmd { - (listener.cb)(); - - found = true; - - break; - } - } - } - - if !found { - os::set_exit_status(42); - } -} - pub impl Crate { fn new(p: &Path) -> Crate { @@ -602,10 +474,6 @@ pub fn src_dir() -> Path { os::getcwd() } -condition! { - bad_pkg_id: (super::Path, ~str) -> ::util::PkgId; -} - // An enumeration of the unpacked source of a package workspace. // This contains a list of files found in the source workspace. pub struct PkgSrc { @@ -641,17 +509,19 @@ impl PkgSrc { fn check_dir(&self) -> Path { use conditions::nonexistent_package::cond; - debug!("Pushing onto root: %s | %s", self.id.path.to_str(), + debug!("Pushing onto root: %s | %s", self.id.to_str(), self.root.to_str()); - let dir = self.root.push_rel(&self.id.path).normalize(); + let mut dir = self.root.push("src"); + dir = dir.push(self.id.to_str()); // ?? Should this use the version number? debug!("Checking dir: %s", dir.to_str()); - // tjc: Rather than erroring out, need to try downloading the - // contents of the path to a local directory (#5679) if !os::path_exists(&dir) { - cond.raise((copy self.id, ~"missing package dir")); + if !self.fetch_git() { + cond.raise((copy self.id, ~"supplied path for package dir does not \ + exist, and couldn't interpret it as a URL fragment")); + } } if !os::path_is_dir(&dir) { @@ -662,6 +532,28 @@ impl PkgSrc { dir } + /// Try interpreting self's package id as a remote package, and try + /// fetching it and caching it in a local directory. If that didn't + /// work, return false. + /// (right now we only support git) + fn fetch_git(&self) -> bool { + + let mut local = self.root.push("src"); + local = local.push(self.id.to_str()); + // Git can't clone into a non-empty directory + os::remove_dir_recursive(&local); + + let url = fmt!("https://%s", self.id.remote_path.to_str()); + util::note(fmt!("git clone %s %s", url, local.to_str())); + + if run::program_output(~"git", ~[~"clone", copy url, local.to_str()]).status != 0 { + util::note(fmt!("fetching %s failed: can't clone repository", url)); + return false; + } + true + } + + // If a file named "pkg.rs" in the current directory exists, // return the path for it. Otherwise, None fn package_script_option(&self, cwd: &Path) -> Option<Path> { @@ -680,7 +572,7 @@ impl PkgSrc { /// Requires that dashes in p have already been normalized to /// underscores fn stem_matches(&self, p: &Path) -> bool { - let self_id = normalize(~copy self.id.path).filestem(); + let self_id = self.id.local_path.filestem(); if self_id == p.filestem() { return true; } @@ -715,7 +607,7 @@ impl PkgSrc { let dir = self.check_dir(); let prefix = dir.components.len(); - debug!("Matching against %?", self.id.path.filestem()); + debug!("Matching against %?", self.id.local_path.filestem()); for os::walk_dir(&dir) |pth| { match pth.filename() { Some(~"lib.rs") => push_crate(&mut self.libs, @@ -752,8 +644,7 @@ impl PkgSrc { src_dir: &Path, crates: &[Crate], cfgs: &[~str], - test: bool, crate_type: crate_type) { - + what: OutputType) { for crates.each |&crate| { let path = &src_dir.push_rel(&crate.file).normalize(); util::note(fmt!("build_crates: compiling %s", path.to_str())); @@ -763,7 +654,7 @@ impl PkgSrc { dst_dir, crate.flags, crate.cfgs + cfgs, - false, test, crate_type); + false, what); if !result { build_err::cond.raise(fmt!("build failure on %s", path.to_str())); @@ -776,12 +667,13 @@ impl PkgSrc { fn build(&self, dst_dir: &Path, cfgs: ~[~str], maybe_sysroot: Option<@Path>) { let dir = self.check_dir(); debug!("Building libs"); - self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, false, lib_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, Lib); debug!("Building mains"); - self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, false, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, Main); debug!("Building tests"); - self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, true, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, Test); debug!("Building benches"); - self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, true, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, Bench); } } + diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index e661e758d41..8eba3f06de3 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -17,8 +17,8 @@ use std::tempfile::mkdtemp; use util::{PkgId, default_version}; use path_util::{target_executable_in_workspace, target_library_in_workspace, target_test_in_workspace, target_bench_in_workspace, - make_dir_rwx, u_rwx}; -use core::os::mkdir_recursive; + make_dir_rwx, u_rwx, RemotePath, LocalPath, normalize, + built_bench_in_workspace, built_test_in_workspace}; fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { Ctx { @@ -29,15 +29,22 @@ fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { } fn fake_pkg() -> PkgId { + let sn = ~"bogus"; + let remote = RemotePath(Path(sn)); PkgId { - path: Path(~"bogus"), + local_path: normalize(copy remote), + remote_path: remote, + short_name: sn, version: default_version() } } fn remote_pkg() -> PkgId { + let remote = RemotePath(Path(~"github.com/catamorphism/test-pkg")); PkgId { - path: Path(~"github.com/catamorphism/test-pkg"), + local_path: normalize(copy remote), + remote_path: remote, + short_name: ~"test_pkg", version: default_version() } } @@ -49,10 +56,11 @@ fn writeFile(file_path: &Path, contents: ~str) { out.write_line(contents); } -fn mk_temp_workspace(short_name: &Path) -> Path { +fn mk_temp_workspace(short_name: &LocalPath) -> Path { let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); - let package_dir = workspace.push(~"src").push_rel(short_name); - assert!(mkdir_recursive(&package_dir, u_rwx)); + // include version number in directory name + let package_dir = workspace.push(~"src").push(fmt!("%s-0.1", short_name.to_str())); + assert!(os::mkdir_recursive(&package_dir, u_rwx)); // Create main, lib, test, and bench files writeFile(&package_dir.push(~"main.rs"), ~"fn main() { let _x = (); }"); @@ -85,7 +93,9 @@ fn test_sysroot() -> Path { self_path.pop() } +// Ignored on i686 -- see #6517 #[test] +#[ignore(cfg(target_arch = "x86"))] fn test_make_dir_rwx() { let temp = &os::tmpdir(); let dir = temp.push(~"quux"); @@ -99,12 +109,13 @@ fn test_make_dir_rwx() { } #[test] +#[ignore(cfg(target_arch = "x86"))] fn test_install_valid() { let sysroot = test_sysroot(); debug!("sysroot = %s", sysroot.to_str()); let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = fake_pkg(); - let temp_workspace = mk_temp_workspace(&temp_pkg_id.path); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.local_path); // should have test, bench, lib, and main ctxt.install(&temp_workspace, &temp_pkg_id); // Check that all files exist @@ -124,6 +135,7 @@ fn test_install_valid() { } #[test] +#[ignore(cfg(target_arch = "x86"))] fn test_install_invalid() { use conditions::nonexistent_package::cond; use cond1 = conditions::missing_pkg_files::cond; @@ -146,27 +158,80 @@ fn test_install_invalid() { } #[test] -#[ignore(reason = "install from URL-fragment not yet implemented")] +#[ignore(cfg(target_arch = "x86"))] fn test_install_url() { + let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); let sysroot = test_sysroot(); debug!("sysroot = %s", sysroot.to_str()); let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = remote_pkg(); - let temp_workspace = mk_temp_workspace(&temp_pkg_id.path); // should have test, bench, lib, and main - ctxt.install(&temp_workspace, &temp_pkg_id); + ctxt.install(&workspace, &temp_pkg_id); // Check that all files exist - let exec = target_executable_in_workspace(&temp_pkg_id, &temp_workspace); + let exec = target_executable_in_workspace(&temp_pkg_id, &workspace); debug!("exec = %s", exec.to_str()); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); - let lib = target_library_in_workspace(&temp_pkg_id, &temp_workspace); + let lib = target_library_in_workspace(&temp_pkg_id, &workspace); debug!("lib = %s", lib.to_str()); assert!(os::path_exists(&lib)); assert!(is_rwx(&lib)); + let built_test = built_test_in_workspace(&temp_pkg_id, &workspace).expect(~"test_install_url"); + assert!(os::path_exists(&built_test)); + let built_bench = built_bench_in_workspace(&temp_pkg_id, + &workspace).expect(~"test_install_url"); + assert!(os::path_exists(&built_bench)); // And that the test and bench executables aren't installed - assert!(!os::path_exists(&target_test_in_workspace(&temp_pkg_id, &temp_workspace))); - let bench = target_bench_in_workspace(&temp_pkg_id, &temp_workspace); + let test = target_test_in_workspace(&temp_pkg_id, &workspace); + assert!(!os::path_exists(&test)); + debug!("test = %s", test.to_str()); + let bench = target_bench_in_workspace(&temp_pkg_id, &workspace); debug!("bench = %s", bench.to_str()); assert!(!os::path_exists(&bench)); } + +#[test] +fn test_package_ids_must_be_relative_path_like() { + use conditions::bad_pkg_id::cond; + + /* + Okay: + - One identifier, with no slashes + - Several slash-delimited things, with no / at the root + + Not okay: + - Empty string + - Absolute path (as per os::is_absolute) + + */ + + let default_version_str = "0.1"; + let addversion = |s| { + fmt!("%s-%s", s, default_version_str) + }; + + let whatever = PkgId::new("foo"); + + assert!(addversion("foo") == whatever.to_str()); + assert!(addversion("github.com/mozilla/rust") == + PkgId::new("github.com/mozilla/rust").to_str()); + + do cond.trap(|(p, e)| { + assert!("" == p.to_str()); + assert!("0-length pkgid" == e); + copy whatever + }).in { + let x = PkgId::new(""); + assert!(addversion("foo") == x.to_str()); + } + + do cond.trap(|(p, e)| { + assert!(p.to_str() == os::make_absolute(&Path("foo/bar/quux")).to_str()); + assert!("absolute pkgid" == e); + copy whatever + }).in { + let z = PkgId::new(os::make_absolute(&Path("foo/bar/quux")).to_str()); + assert!(addversion("foo") == z.to_str()); + } + +} diff --git a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/main.rs index 62785c06db3..62785c06db3 100644 --- a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs +++ b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/main.rs diff --git a/src/librustpkg/testsuite/pass/src/external-crate/src/main.rs b/src/librustpkg/testsuite/pass/src/external-crate/main.rs index d094bcd6bba..d094bcd6bba 100644 --- a/src/librustpkg/testsuite/pass/src/external-crate/src/main.rs +++ b/src/librustpkg/testsuite/pass/src/external-crate/main.rs diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index e9c4b7fde55..4a9c276948a 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -13,20 +13,18 @@ use core::cmp::Ord; use core::hash::Streaming; use core::rt::io::Writer; use rustc::driver::{driver, session}; -use rustc::driver::session::{lib_crate, unknown_crate}; use rustc::metadata::filesearch; use std::getopts::groups::getopts; use std::semver; -use std::{json, term, getopts}; +use std::{term, getopts}; use syntax::ast_util::*; use syntax::codemap::{dummy_sp, spanned, dummy_spanned}; use syntax::ext::base::{mk_ctxt, ext_ctxt}; -use syntax::ext::build; use syntax::{ast, attr, codemap, diagnostic, fold}; -use syntax::ast::{meta_name_value, meta_list, attribute}; +use syntax::ast::{meta_name_value, meta_list}; use syntax::attr::{mk_attr}; use rustc::back::link::output_type_exe; -use rustc::driver::session::{lib_crate, unknown_crate, crate_type}; +use rustc::driver::session::{lib_crate, bin_crate}; static Commands: &'static [&'static str] = &["build", "clean", "do", "info", "install", "prefer", "test", "uninstall", @@ -83,20 +81,34 @@ impl ToStr for Version { } } +#[deriving(Eq)] +pub enum OutputType { Main, Lib, Bench, Test } + /// Placeholder pub fn default_version() -> Version { ExactRevision(0.1) } -// Path-fragment identifier of a package such as -// 'github.com/graydon/test'; path must be a relative -// path with >=1 component. +/// Path-fragment identifier of a package such as +/// 'github.com/graydon/test'; path must be a relative +/// path with >=1 component. pub struct PkgId { - path: Path, + /// Remote path: for example, github.com/mozilla/quux-whatever + remote_path: RemotePath, + /// Local path: for example, /home/quux/github.com/mozilla/quux_whatever + /// Note that '-' normalizes to '_' when mapping a remote path + /// onto a local path + /// Also, this will change when we implement #6407, though we'll still + /// need to keep track of separate local and remote paths + local_path: LocalPath, + /// Short name. This is the local path's filestem, but we store it + /// redundantly so as to not call get() everywhere (filestem() returns an + /// option) + short_name: ~str, version: Version } pub impl PkgId { fn new(s: &str) -> PkgId { - use bad_pkg_id::cond; + use conditions::bad_pkg_id::cond; let p = Path(s); if p.is_absolute { @@ -105,31 +117,32 @@ pub impl PkgId { if p.components.len() < 1 { return cond.raise((p, ~"0-length pkgid")); } + let remote_path = RemotePath(p); + let local_path = normalize(copy remote_path); + let short_name = (copy local_path).filestem().expect(fmt!("Strange path! %s", s)); PkgId { - path: p, + local_path: local_path, + remote_path: remote_path, + short_name: short_name, version: default_version() } } fn hash(&self) -> ~str { - fmt!("%s-%s-%s", self.path.to_str(), - hash(self.path.to_str() + self.version.to_str()), + fmt!("%s-%s-%s", self.remote_path.to_str(), + hash(self.remote_path.to_str() + self.version.to_str()), self.version.to_str()) } + fn short_name_with_version(&self) -> ~str { + fmt!("%s-%s", self.short_name, self.version.to_str()) + } } impl ToStr for PkgId { fn to_str(&self) -> ~str { // should probably use the filestem and not the whole path - fmt!("%s-%s", self.path.to_str(), - // Replace dots with -s in the version - // this is because otherwise rustc will think - // that foo-0.1 has .1 as its extension - // (Temporary hack until I figure out how to - // get rustc to not name the object file - // foo-0.o if I pass in foo-0.1 to build_output_filenames) - str::replace(self.version.to_str(), ".", "-")) + fmt!("%s-%s", self.local_path.to_str(), self.version.to_str()) } } @@ -156,26 +169,6 @@ pub fn is_cmd(cmd: &str) -> bool { Commands.any(|&c| c == cmd) } -pub fn parse_name(id: ~str) -> result::Result<~str, ~str> { - let mut last_part = None; - - for str::each_split_char(id, '.') |part| { - for str::each_char(part) |char| { - if char::is_whitespace(char) { - return result::Err( - ~"could not parse id: contains whitespace"); - } else if char::is_uppercase(char) { - return result::Err( - ~"could not parse id: should be all lowercase"); - } - } - last_part = Some(part.to_owned()); - } - if last_part.is_none() { return result::Err(~"could not parse id: is empty"); } - - result::Ok(last_part.unwrap()) -} - struct ListenerFn { cmds: ~[~str], span: codemap::span, @@ -248,52 +241,6 @@ fn fold_item(ctx: @mut ReadyCtx, res } -fn add_pkg_module(ctx: @mut ReadyCtx, m: ast::_mod) -> ast::_mod { - let listeners = mk_listener_vec(ctx); - let ext_cx = ctx.ext_cx; - let item = quote_item! ( - mod __pkg { - extern mod rustpkg (vers="0.7-pre"); - static listeners : &[rustpkg::Listener] = $listeners; - #[main] - fn main() { - rustpkg::run(listeners); - } - } - ); - ast::_mod { - items: vec::append_one(/*bad*/copy m.items, item.get()), - .. m - } -} - -fn mk_listener_vec(ctx: @mut ReadyCtx) -> @ast::expr { - let descs = do ctx.fns.map |listener| { - mk_listener_rec(ctx, listener) - }; - let ext_cx = ctx.ext_cx; - build::mk_slice_vec_e(ext_cx, dummy_sp(), descs) -} - -fn mk_listener_rec(ctx: @mut ReadyCtx, listener: &ListenerFn) -> @ast::expr { - let span = listener.span; - let cmds = do listener.cmds.map |&cmd| { - let ext_cx = ctx.ext_cx; - build::mk_base_str(ext_cx, span, cmd) - }; - - let ext_cx = ctx.ext_cx; - let cmds_expr = build::mk_slice_vec_e(ext_cx, span, cmds); - let cb_expr = build::mk_path(ext_cx, span, copy listener.path); - - quote_expr!( - Listener { - cmds: $cmds_expr, - cb: $cb_expr - } - ) -} - /// Generate/filter main function, add the list of commands, etc. pub fn ready_crate(sess: session::Session, crate: @ast::crate) -> @ast::crate { @@ -375,67 +322,6 @@ pub fn hash(data: ~str) -> ~str { hasher.result_str() } -pub fn temp_change_dir<T>(dir: &Path, cb: &fn() -> T) { - let cwd = os::getcwd(); - - os::change_dir(dir); - cb(); - os::change_dir(&cwd); -} - -pub fn touch(path: &Path) { - match io::mk_file_writer(path, ~[io::Create]) { - result::Ok(writer) => writer.write_line(~""), - _ => {} - } -} - -pub fn remove_dir_r(path: &Path) { - for os::walk_dir(path) |&file| { - let mut cdir = file; - - loop { - if os::path_is_dir(&cdir) { - os::remove_dir(&cdir); - } else { - os::remove_file(&cdir); - } - - cdir = cdir.dir_path(); - - if cdir == *path { break; } - } - } - - os::remove_dir(path); -} - -pub fn wait_for_lock(path: &Path) { - if os::path_exists(path) { - warn(fmt!("the database appears locked, please wait (or rm %s)", - path.to_str())); - - loop { - if !os::path_exists(path) { break; } - } - } -} - -pub fn load_pkgs() -> result::Result<~[json::Json], ~str> { - fail!("load_pkg not implemented"); -} - -pub fn get_pkg(_id: ~str, - _vers: Option<~str>) -> result::Result<Pkg, ~str> { - fail!("get_pkg not implemented"); -} - -pub fn add_pkg(pkg: &Pkg) -> bool { - note(fmt!("Would be adding package, but add_pkg is not yet implemented %s", - pkg.to_str())); - false -} - // FIXME (#4432): Use workcache to only compile when needed pub fn compile_input(sysroot: Option<@Path>, pkg_id: &PkgId, @@ -444,31 +330,24 @@ pub fn compile_input(sysroot: Option<@Path>, flags: &[~str], cfgs: &[~str], opt: bool, - test: bool, - crate_type: session::crate_type) -> bool { - - // Want just the directory component here - let pkg_filename = pkg_id.path.filename().expect(~"Weird pkg id"); - let short_name = fmt!("%s-%s", pkg_filename, pkg_id.version.to_str()); + what: OutputType) -> bool { assert!(in_file.components.len() > 1); let input = driver::file_input(copy *in_file); - debug!("compile_input: %s / %?", in_file.to_str(), crate_type); + debug!("compile_input: %s / %?", in_file.to_str(), what); // tjc: by default, use the package ID name as the link name // not sure if we should support anything else - let binary = @copy os::args()[0]; - let building_library = match crate_type { - lib_crate | unknown_crate => true, - _ => false - }; + let binary = @(copy os::args()[0]); + let building_library = what == Lib; let out_file = if building_library { - out_dir.push(os::dll_filename(short_name)) + out_dir.push(os::dll_filename(pkg_id.short_name)) } else { - out_dir.push(short_name + if test { ~"test" } else { ~"" } - + os::EXE_SUFFIX) + out_dir.push(pkg_id.short_name + match what { + Test => ~"test", Bench => ~"bench", Main | Lib => ~"" + } + os::EXE_SUFFIX) }; debug!("compiling %s into %s", @@ -478,18 +357,24 @@ pub fn compile_input(sysroot: Option<@Path>, debug!("cfgs: %s", str::connect(cfgs, ~" ")); debug!("compile_input's sysroot = %?", sysroot); + let crate_type = match what { + Lib => lib_crate, + Test | Bench | Main => bin_crate + }; let matches = getopts(~[~"-Z", ~"time-passes"] - + if building_library { ~[~"--lib"] } - else if test { ~[~"--test"] } - // bench? - else { ~[] } + + match what { + Lib => ~[~"--lib"], + // --test compiles both #[test] and #[bench] fns + Test | Bench => ~[~"--test"], + Main => ~[] + } + flags + cfgs.flat_map(|&c| { ~[~"--cfg", c] }), driver::optgroups()).get(); let mut options = session::options { crate_type: crate_type, optimize: if opt { session::Aggressive } else { session::No }, - test: test, + test: what == Test || what == Bench, maybe_sysroot: sysroot, addl_lib_search_paths: ~[copy *out_dir], // output_type should be conditional @@ -540,26 +425,27 @@ pub fn compile_crate_from_input(input: &driver::input, debug!("Calling compile_upto, outputs = %?", outputs); let (crate, _) = driver::compile_upto(sess, copy cfg, input, driver::cu_parse, Some(outputs)); + let mut crate = crate; debug!("About to inject link_meta info..."); // Inject the inferred link_meta info if it's not already there // (assumes that name and vers are the only linkage metas) - let mut crate_to_use = crate; debug!("How many attrs? %?", attr::find_linkage_metas(crate.node.attrs).len()); if attr::find_linkage_metas(crate.node.attrs).is_empty() { - crate_to_use = add_attrs(copy *crate, - ~[mk_attr(@dummy_spanned(meta_list(@~"link", - // change PkgId to have a <shortname> field? - ~[@dummy_spanned(meta_name_value(@~"name", - mk_string_lit(@pkg_id.path.filestem().get()))), - @dummy_spanned(meta_name_value(@~"vers", - mk_string_lit(@pkg_id.version.to_str())))])))]); + crate = @codemap::respan(crate.span, ast::crate_ { + attrs: ~[mk_attr(@dummy_spanned( + meta_list(@~"link", + ~[@dummy_spanned(meta_name_value(@~"name", + mk_string_lit(@(copy pkg_id.short_name)))), + @dummy_spanned(meta_name_value(@~"vers", + mk_string_lit(@(copy pkg_id.version.to_str()))))])))], + ..copy crate.node}); } - driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use)); - crate_to_use + driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate)); + crate } } } @@ -573,30 +459,41 @@ pub fn exe_suffix() -> ~str { ~".exe" } #[cfg(target_os = "macos")] pub fn exe_suffix() -> ~str { ~"" } - -/// Returns a copy of crate `c` with attributes `attrs` added to its -/// attributes -fn add_attrs(mut c: ast::crate, new_attrs: ~[attribute]) -> @ast::crate { - c.node.attrs += new_attrs; - @c -} - // Called by build_crates // FIXME (#4432): Use workcache to only compile when needed pub fn compile_crate(sysroot: Option<@Path>, pkg_id: &PkgId, crate: &Path, dir: &Path, flags: &[~str], cfgs: &[~str], opt: bool, - test: bool, crate_type: crate_type) -> bool { + what: OutputType) -> bool { debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); debug!("compile_crate: short_name = %s, flags =...", pkg_id.to_str()); for flags.each |&fl| { debug!("+++ %s", fl); } - compile_input(sysroot, pkg_id, - crate, dir, flags, cfgs, opt, test, crate_type) + compile_input(sysroot, pkg_id, crate, dir, flags, cfgs, opt, what) +} + +// normalize should be the only way to construct a LocalPath +// (though this isn't enforced) +/// Replace all occurrences of '-' in the stem part of path with '_' +/// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux +/// as the same name +pub fn normalize(p_: RemotePath) -> LocalPath { + let RemotePath(p) = p_; + match p.filestem() { + None => LocalPath(p), + Some(st) => { + let replaced = str::replace(st, "-", "_"); + if replaced != st { + LocalPath(p.with_filestem(replaced)) + } + else { + LocalPath(p) + } + } + } } - #[cfg(windows)] pub fn link_exe(_src: &Path, _dest: &Path) -> bool { /* FIXME (#1768): Investigate how to do this on win32 @@ -628,9 +525,13 @@ pub fn mk_string_lit(s: @~str) -> ast::lit { } } +/// Wrappers to prevent local and remote paths from getting confused +pub struct RemotePath (Path); +pub struct LocalPath (Path); + #[cfg(test)] mod test { - use super::{is_cmd, parse_name}; + use super::is_cmd; #[test] fn test_is_cmd() { @@ -645,9 +546,4 @@ mod test { assert!(is_cmd(~"unprefer")); } - #[test] - fn test_parse_name() { - assert!(parse_name(~"org.mozilla.servo").get() == ~"servo"); - assert!(parse_name(~"org. mozilla.servo 2131").is_err()); - } } diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs index 8941dbfd20e..cb9f735bce8 100644 --- a/src/librustpkg/workspace.rs +++ b/src/librustpkg/workspace.rs @@ -21,9 +21,10 @@ pub fn pkg_parent_workspaces(pkgid: &PkgId, action: &fn(&Path) -> bool) -> bool workspace_contains_package_id(pkgid, ws)); if workspaces.is_empty() { // tjc: make this a condition - fail!("Package %s not found in any of the following workspaces: %s", - pkgid.path.to_str(), - rust_path().to_str()); + fail!("Package %s not found in any of \ + the following workspaces: %s", + pkgid.remote_path.to_str(), + rust_path().to_str()); } for workspaces.each |ws| { if action(ws) { diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 07c1c226d1f..64f78d5ab7b 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -779,7 +779,7 @@ pub mod writer { priv impl Encoder { // used internally to emit things like the vector length and so on fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) { - assert!(v <= 0xFFFF_FFFF_u); // FIXME(#6130) assert warns on 32-bit + assert!(v <= 0xFFFF_FFFF_u); self.wr_tagged_u32(t as uint, v as u32); } diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 7702b46ddcb..270cf675c87 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -1331,26 +1331,20 @@ mod tests { use std::serialize::Decodable; - #[auto_encode] - #[auto_decode] - #[deriving(Eq)] + #[deriving(Eq, Encodable, Decodable)] enum Animal { Dog, Frog(~str, int) } - #[auto_encode] - #[auto_decode] - #[deriving(Eq)] + #[deriving(Eq, Encodable, Decodable)] struct Inner { a: (), b: uint, c: ~[~str], } - #[auto_encode] - #[auto_decode] - #[deriving(Eq)] + #[deriving(Eq, Encodable, Decodable)] struct Outer { inner: ~[Inner], } diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs index 8cf2da3a1e8..46f50eafec1 100644 --- a/src/libstd/rc.rs +++ b/src/libstd/rc.rs @@ -11,7 +11,11 @@ /** Task-local reference counted smart pointers Task-local reference counted smart pointers are an alternative to managed boxes with deterministic -destruction. They are restricted to containing `Owned` types in order to prevent cycles. +destruction. They are restricted to containing types that are either `Owned` or `Const` (or both) to +prevent cycles. + +Neither `Rc<T>` or `RcMut<T>` is ever `Owned` and `RcMut<T>` is never `Const`. If `T` is `Const`, a +cycle cannot be created with `Rc<T>` because there is no way to modify it after creation. */ @@ -30,16 +34,26 @@ pub struct Rc<T> { priv ptr: *mut RcBox<T>, } -pub impl<T: Owned> Rc<T> { - fn new(value: T) -> Rc<T> { - unsafe { - let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>; - assert!(!ptr::is_null(ptr)); - intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1}); - Rc{ptr: ptr} - } +priv impl<T> Rc<T> { + unsafe fn new(value: T) -> Rc<T> { + let ptr = malloc(sys::size_of::<RcBox<T>>() as size_t) as *mut RcBox<T>; + assert!(!ptr::is_null(ptr)); + intrinsics::move_val_init(&mut *ptr, RcBox{value: value, count: 1}); + Rc{ptr: ptr} } +} + +// FIXME: #6516: should be a static method +pub fn rc_from_owned<T: Owned>(value: T) -> Rc<T> { + unsafe { Rc::new(value) } +} +// FIXME: #6516: should be a static method +pub fn rc_from_const<T: Const>(value: T) -> Rc<T> { + unsafe { Rc::new(value) } +} + +pub impl<T> Rc<T> { #[inline(always)] fn borrow<'r>(&'r self) -> &'r T { unsafe { cast::copy_lifetime(self, &(*self.ptr).value) } @@ -48,7 +62,7 @@ pub impl<T: Owned> Rc<T> { #[unsafe_destructor] #[cfg(not(stage0))] -impl<T: Owned> Drop for Rc<T> { +impl<T> Drop for Rc<T> { fn finalize(&self) { unsafe { (*self.ptr).count -= 1; @@ -62,7 +76,7 @@ impl<T: Owned> Drop for Rc<T> { #[unsafe_destructor] #[cfg(stage0)] -impl<T: Owned> Drop for Rc<T> { +impl<T> Drop for Rc<T> { fn finalize(&self) { unsafe { (*self.ptr).count -= 1; @@ -75,7 +89,8 @@ impl<T: Owned> Drop for Rc<T> { } -impl<T: Owned> Clone for Rc<T> { +impl<T> Clone for Rc<T> { + /// Return a shallow copy of the reference counted pointer. #[inline] fn clone(&self) -> Rc<T> { unsafe { @@ -85,19 +100,48 @@ impl<T: Owned> Clone for Rc<T> { } } +impl<T: DeepClone> DeepClone for Rc<T> { + /// Return a deep copy of the reference counted pointer. + #[inline] + fn deep_clone(&self) -> Rc<T> { + unsafe { Rc::new(self.borrow().deep_clone()) } + } +} + #[cfg(test)] mod test_rc { use super::*; + use core::cell::Cell; + + #[test] + fn test_clone() { + let x = rc_from_owned(Cell(5)); + let y = x.clone(); + do x.borrow().with_mut_ref |inner| { + *inner = 20; + } + assert_eq!(y.borrow().take(), 20); + } + + #[test] + fn test_deep_clone() { + let x = rc_from_owned(Cell(5)); + let y = x.deep_clone(); + do x.borrow().with_mut_ref |inner| { + *inner = 20; + } + assert_eq!(y.borrow().take(), 5); + } #[test] fn test_simple() { - let x = Rc::new(5); + let x = rc_from_const(5); assert_eq!(*x.borrow(), 5); } #[test] - fn test_clone() { - let x = Rc::new(5); + fn test_simple_clone() { + let x = rc_from_const(5); let y = x.clone(); assert_eq!(*x.borrow(), 5); assert_eq!(*y.borrow(), 5); @@ -105,7 +149,7 @@ mod test_rc { #[test] fn test_destructor() { - let x = Rc::new(~5); + let x = rc_from_owned(~5); assert_eq!(**x.borrow(), 5); } } @@ -137,43 +181,55 @@ pub struct RcMut<T> { priv ptr: *mut RcMutBox<T>, } -pub impl<T: Owned> RcMut<T> { - fn new(value: T) -> RcMut<T> { - unsafe { - let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>; - assert!(!ptr::is_null(ptr)); - intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing}); - RcMut{ptr: ptr} - } +priv impl<T> RcMut<T> { + unsafe fn new(value: T) -> RcMut<T> { + let ptr = malloc(sys::size_of::<RcMutBox<T>>() as size_t) as *mut RcMutBox<T>; + assert!(!ptr::is_null(ptr)); + intrinsics::move_val_init(&mut *ptr, RcMutBox{value: value, count: 1, borrow: Nothing}); + RcMut{ptr: ptr} } +} + +// FIXME: #6516: should be a static method +pub fn rc_mut_from_owned<T: Owned>(value: T) -> RcMut<T> { + unsafe { RcMut::new(value) } +} + +// FIXME: #6516: should be a static method +pub fn rc_mut_from_const<T: Const>(value: T) -> RcMut<T> { + unsafe { RcMut::new(value) } +} +pub impl<T> RcMut<T> { /// Fails if there is already a mutable borrow of the box #[inline] - fn with_borrow(&self, f: &fn(&T)) { + fn with_borrow<U>(&self, f: &fn(&T) -> U) -> U { unsafe { assert!((*self.ptr).borrow != Mutable); let previous = (*self.ptr).borrow; (*self.ptr).borrow = Immutable; - f(&(*self.ptr).value); + let res = f(&(*self.ptr).value); (*self.ptr).borrow = previous; + res } } /// Fails if there is already a mutable or immutable borrow of the box #[inline] - fn with_mut_borrow(&self, f: &fn(&mut T)) { + fn with_mut_borrow<U>(&self, f: &fn(&mut T) -> U) -> U { unsafe { assert!((*self.ptr).borrow == Nothing); (*self.ptr).borrow = Mutable; - f(&mut (*self.ptr).value); + let res = f(&mut (*self.ptr).value); (*self.ptr).borrow = Nothing; + res } } } #[unsafe_destructor] #[cfg(not(stage0))] -impl<T: Owned> Drop for RcMut<T> { +impl<T> Drop for RcMut<T> { fn finalize(&self) { unsafe { (*self.ptr).count -= 1; @@ -187,7 +243,7 @@ impl<T: Owned> Drop for RcMut<T> { #[unsafe_destructor] #[cfg(stage0)] -impl<T: Owned> Drop for RcMut<T> { +impl<T> Drop for RcMut<T> { fn finalize(&self) { unsafe { (*self.ptr).count -= 1; @@ -199,7 +255,8 @@ impl<T: Owned> Drop for RcMut<T> { } } -impl<T: Owned> Clone for RcMut<T> { +impl<T> Clone for RcMut<T> { + /// Return a shallow copy of the reference counted pointer. #[inline] fn clone(&self) -> RcMut<T> { unsafe { @@ -209,13 +266,48 @@ impl<T: Owned> Clone for RcMut<T> { } } +impl<T: DeepClone> DeepClone for RcMut<T> { + /// Return a deep copy of the reference counted pointer. + #[inline] + fn deep_clone(&self) -> RcMut<T> { + do self.with_borrow |x| { + // FIXME: #6497: should avoid freeze (slow) + unsafe { RcMut::new(x.deep_clone()) } + } + } +} + #[cfg(test)] mod test_rc_mut { use super::*; #[test] + fn test_clone() { + let x = rc_mut_from_owned(5); + let y = x.clone(); + do x.with_mut_borrow |value| { + *value = 20; + } + do y.with_borrow |value| { + assert_eq!(*value, 20); + } + } + + #[test] + fn test_deep_clone() { + let x = rc_mut_from_const(5); + let y = x.deep_clone(); + do x.with_mut_borrow |value| { + *value = 20; + } + do y.with_borrow |value| { + assert_eq!(*value, 5); + } + } + + #[test] fn borrow_many() { - let x = RcMut::new(5); + let x = rc_mut_from_owned(5); let y = x.clone(); do x.with_borrow |a| { @@ -231,7 +323,7 @@ mod test_rc_mut { #[test] fn modify() { - let x = RcMut::new(5); + let x = rc_mut_from_const(5); let y = x.clone(); do y.with_mut_borrow |a| { @@ -246,14 +338,14 @@ mod test_rc_mut { #[test] fn release_immutable() { - let x = RcMut::new(5); + let x = rc_mut_from_owned(5); do x.with_borrow |_| {} do x.with_mut_borrow |_| {} } #[test] fn release_mutable() { - let x = RcMut::new(5); + let x = rc_mut_from_const(5); do x.with_mut_borrow |_| {} do x.with_borrow |_| {} } @@ -261,7 +353,7 @@ mod test_rc_mut { #[test] #[should_fail] fn frozen() { - let x = RcMut::new(5); + let x = rc_mut_from_owned(5); let y = x.clone(); do x.with_borrow |_| { @@ -273,7 +365,7 @@ mod test_rc_mut { #[test] #[should_fail] fn mutable_dupe() { - let x = RcMut::new(5); + let x = rc_mut_from_const(5); let y = x.clone(); do x.with_mut_borrow |_| { @@ -285,7 +377,7 @@ mod test_rc_mut { #[test] #[should_fail] fn mutable_freeze() { - let x = RcMut::new(5); + let x = rc_mut_from_owned(5); let y = x.clone(); do x.with_mut_borrow |_| { @@ -297,7 +389,7 @@ mod test_rc_mut { #[test] #[should_fail] fn restore_freeze() { - let x = RcMut::new(5); + let x = rc_mut_from_const(5); let y = x.clone(); do x.with_borrow |_| { diff --git a/src/libstd/time.rs b/src/libstd/time.rs index e731f679221..202b96f9797 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -29,9 +29,7 @@ pub mod rustrt { } /// A record specifying a time value in seconds and nanoseconds. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct Timespec { sec: i64, nsec: i32 } /* @@ -100,9 +98,7 @@ pub fn tzset() { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct Tm { tm_sec: i32, // seconds after the minute ~[0-60] tm_min: i32, // minutes after the hour ~[0-59] diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index a9e4ec50c7c..f173df60df8 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -92,9 +92,7 @@ use core::util::replace; * */ -#[deriving(Eq)] -#[auto_encode] -#[auto_decode] +#[deriving(Eq, Encodable, Decodable)] struct WorkKey { kind: ~str, name: ~str diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index ee62bb270b8..1b166dcf366 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -58,9 +58,7 @@ enum AbiArchitecture { Archs(u32) // Multiple architectures (bitset) } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct AbiSet { priv bits: u32 // each bit represents one of the abis below } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index f77d00ce9b1..dcbbd7ab531 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -47,9 +47,7 @@ pub type SyntaxContext = uint; pub type SCTable = ~[SyntaxContext_]; pub static empty_ctxt : uint = 0; -#[deriving(Eq)] -#[auto_encode] -#[auto_decode] +#[deriving(Eq, Encodable, Decodable)] pub enum SyntaxContext_ { EmptyCtxt, Mark (Mrk,SyntaxContext), @@ -115,9 +113,7 @@ impl to_bytes::IterBytes for ident { // Functions may or may not have names. pub type fn_ident = Option<ident>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct Lifetime { id: node_id, span: span, @@ -142,9 +138,7 @@ impl to_bytes::IterBytes for Lifetime { // for instance: core::cmp::Eq . It's represented // as a sequence of identifiers, along with a bunch // of supporting information. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct Path { span: span, global: bool, @@ -157,9 +151,7 @@ pub type crate_num = int; pub type node_id = int; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct def_id { crate: crate_num, node: node_id, @@ -168,9 +160,7 @@ pub struct def_id { pub static local_crate: crate_num = 0; pub static crate_node_id: node_id = 0; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] // The AST represents all type param bounds as types. // typeck::collect::compute_bounds matches these against // the "special" built-in traits (see middle::lang_items) and @@ -180,18 +170,14 @@ pub enum TyParamBound { RegionTyParamBound } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct TyParam { ident: ident, id: node_id, bounds: @OptVec<TyParamBound> } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct Generics { lifetimes: OptVec<Lifetime>, ty_params: OptVec<TyParam> @@ -209,9 +195,7 @@ pub impl Generics { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum def { def_fn(def_id, purity), def_static_method(/* method */ def_id, @@ -248,9 +232,7 @@ pub type crate_cfg = ~[@meta_item]; pub type crate = spanned<crate_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct crate_ { module: _mod, attrs: ~[attribute], @@ -259,9 +241,7 @@ pub struct crate_ { pub type meta_item = spanned<meta_item_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum meta_item_ { meta_word(@~str), meta_list(@~str, ~[@meta_item]), @@ -270,9 +250,7 @@ pub enum meta_item_ { pub type blk = spanned<blk_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct blk_ { view_items: ~[@view_item], stmts: ~[@stmt], @@ -281,26 +259,20 @@ pub struct blk_ { rules: blk_check_mode, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct pat { id: node_id, node: pat_, span: span, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct field_pat { ident: ident, pat: @pat, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum binding_mode { bind_by_copy, bind_by_ref(mutability), @@ -334,9 +306,7 @@ impl to_bytes::IterBytes for binding_mode { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum pat_ { pat_wild, // A pat_ident may either be a new bound variable, @@ -361,9 +331,7 @@ pub enum pat_ { pat_vec(~[@pat], Option<@pat>, ~[@pat]) } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum mutability { m_mutbl, m_imm, m_const, } #[cfg(stage0)] @@ -379,9 +347,7 @@ impl to_bytes::IterBytes for mutability { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum Sigil { BorrowedSigil, OwnedSigil, @@ -411,9 +377,7 @@ impl ToStr for Sigil { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum vstore { // FIXME (#3469): Change uint to @expr (actually only constant exprs) vstore_fixed(Option<uint>), // [1,2,3,4] @@ -422,9 +386,7 @@ pub enum vstore { vstore_slice(Option<@Lifetime>) // &'foo? [1,2,3,4] } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum expr_vstore { expr_vstore_uniq, // ~[1,2,3,4] expr_vstore_box, // @[1,2,3,4] @@ -433,9 +395,7 @@ pub enum expr_vstore { expr_vstore_mut_slice, // &mut [1,2,3,4] } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum binop { add, subtract, @@ -457,9 +417,7 @@ pub enum binop { gt, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum unop { box(mutability), uniq(mutability), @@ -470,9 +428,7 @@ pub enum unop { pub type stmt = spanned<stmt_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum stmt_ { stmt_decl(@decl, node_id), @@ -488,9 +444,7 @@ pub enum stmt_ { // FIXME (pending discussion of #1697, #2178...): local should really be // a refinement on pat. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct local_ { is_mutbl: bool, ty: @Ty, @@ -503,23 +457,17 @@ pub type local = spanned<local_>; pub type decl = spanned<decl_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum decl_ { decl_local(~[@local]), decl_item(@item), } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct arm { pats: ~[@pat], guard: Option<@expr>, body: blk, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct field_ { mutbl: mutability, ident: ident, @@ -528,14 +476,10 @@ pub struct field_ { pub type field = spanned<field_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum blk_check_mode { default_blk, unsafe_blk, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct expr { id: node_id, // Extra node ID is only used for index, assign_op, unary, binary, method @@ -545,18 +489,14 @@ pub struct expr { span: span, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum CallSugar { NoSugar, DoSugar, ForSugar } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum expr_ { expr_vstore(@expr, expr_vstore), expr_vec(~[@expr], mutability), @@ -627,9 +567,7 @@ pub enum expr_ { // else knows what to do with them, so you'll probably get a syntax // error. // -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] #[doc="For macro invocations; parsing is delegated to the macro"] pub enum token_tree { // a single token @@ -702,9 +640,7 @@ pub enum token_tree { // pub type matcher = spanned<matcher_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum matcher_ { // match one token match_tok(::parse::token::Token), @@ -717,18 +653,14 @@ pub enum matcher_ { pub type mac = spanned<mac_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum mac_ { mac_invoc_tt(@Path,~[token_tree]), // new macro-invocation } pub type lit = spanned<lit_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum lit_ { lit_str(@~str), lit_int(i64, int_ty), @@ -742,17 +674,13 @@ pub enum lit_ { // NB: If you change this, you'll probably want to change the corresponding // type structure in middle/ty.rs as well. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct mt { ty: @Ty, mutbl: mutability, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct ty_field_ { ident: ident, mt: mt, @@ -760,9 +688,7 @@ pub struct ty_field_ { pub type ty_field = spanned<ty_field_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct ty_method { ident: ident, attrs: ~[attribute], @@ -774,9 +700,7 @@ pub struct ty_method { span: span, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] // A trait method is either required (meaning it doesn't have an // implementation, just a signature) or provided (meaning it has a default // implementation). @@ -785,9 +709,7 @@ pub enum trait_method { provided(@method), } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum int_ty { ty_i, ty_char, ty_i8, ty_i16, ty_i32, ty_i64, } impl ToStr for int_ty { @@ -809,9 +731,7 @@ impl to_bytes::IterBytes for int_ty { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum uint_ty { ty_u, ty_u8, ty_u16, ty_u32, ty_u64, } impl ToStr for uint_ty { @@ -833,9 +753,7 @@ impl to_bytes::IterBytes for uint_ty { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum float_ty { ty_f, ty_f32, ty_f64, } impl ToStr for float_ty { @@ -858,9 +776,7 @@ impl to_bytes::IterBytes for float_ty { } // NB Eq method appears below. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct Ty { id: node_id, node: ty_, @@ -868,9 +784,7 @@ pub struct Ty { } // Not represented directly in the AST, referred to by name through a ty_path. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum prim_ty { ty_int(int_ty), ty_uint(uint_ty), @@ -879,9 +793,7 @@ pub enum prim_ty { ty_bool, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum Onceness { Once, Many @@ -909,21 +821,18 @@ impl to_bytes::IterBytes for Onceness { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct TyClosure { sigil: Sigil, region: Option<@Lifetime>, lifetimes: OptVec<Lifetime>, purity: purity, onceness: Onceness, - decl: fn_decl + decl: fn_decl, + bounds: OptVec<TyParamBound> } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct TyBareFn { purity: purity, abis: AbiSet, @@ -931,9 +840,7 @@ pub struct TyBareFn { decl: fn_decl } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum ty_ { ty_nil, ty_bot, /* bottom type */ @@ -967,17 +874,13 @@ impl to_bytes::IterBytes for Ty { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum asm_dialect { asm_att, asm_intel } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct inline_asm { asm: @~str, clobbers: @~str, @@ -988,9 +891,7 @@ pub struct inline_asm { dialect: asm_dialect } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct arg { is_mutbl: bool, ty: @Ty, @@ -998,18 +899,14 @@ pub struct arg { id: node_id, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct fn_decl { inputs: ~[arg], output: @Ty, cf: ret_style, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum purity { pure_fn, // declared with "pure fn" unsafe_fn, // declared with "unsafe fn" @@ -1041,9 +938,7 @@ impl to_bytes::IterBytes for purity { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum ret_style { noreturn, // functions with return type _|_ that always // raise an error or exit (i.e. never return to the caller) @@ -1063,9 +958,7 @@ impl to_bytes::IterBytes for ret_style { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum explicit_self_ { sty_static, // no self sty_value, // `self` @@ -1102,9 +995,7 @@ impl to_bytes::IterBytes for explicit_self_ { pub type explicit_self = spanned<explicit_self_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct method { ident: ident, attrs: ~[attribute], @@ -1119,23 +1010,17 @@ pub struct method { vis: visibility, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct _mod { view_items: ~[@view_item], items: ~[@item], } // Foreign mods can be named or anonymous -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum foreign_mod_sort { named, anonymous } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct foreign_mod { sort: foreign_mod_sort, abis: AbiSet, @@ -1143,32 +1028,24 @@ pub struct foreign_mod { items: ~[@foreign_item], } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct variant_arg { ty: @Ty, id: node_id, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum variant_kind { tuple_variant_kind(~[variant_arg]), struct_variant_kind(@struct_def), } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct enum_def { variants: ~[variant], } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct variant_ { name: ident, attrs: ~[attribute], @@ -1180,9 +1057,7 @@ pub struct variant_ { pub type variant = spanned<variant_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct path_list_ident_ { name: ident, id: node_id, @@ -1192,9 +1067,7 @@ pub type path_list_ident = spanned<path_list_ident_>; pub type view_path = spanned<view_path_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum view_path_ { // quux = foo::bar::baz @@ -1211,9 +1084,7 @@ pub enum view_path_ { view_path_list(@Path, ~[path_list_ident], node_id) } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct view_item { node: view_item_, attrs: ~[attribute], @@ -1221,9 +1092,7 @@ pub struct view_item { span: span, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum view_item_ { view_item_extern_mod(ident, ~[@meta_item], node_id), view_item_use(~[@view_path]), @@ -1235,15 +1104,11 @@ pub type attribute = spanned<attribute_>; // Distinguishes between attributes that decorate items and attributes that // are contained as statements within items. These two cases need to be // distinguished for pretty-printing. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum attr_style { attr_outer, attr_inner, } // doc-comments are promoted to attributes that have is_sugared_doc = true -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct attribute_ { style: attr_style, value: @meta_item, @@ -1257,17 +1122,13 @@ pub struct attribute_ { If this impl is an item_impl, the impl_id is redundant (it could be the same as the impl's node id). */ -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct trait_ref { path: @Path, ref_id: node_id, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum visibility { public, private, inherited } impl visibility { @@ -1279,9 +1140,7 @@ impl visibility { } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct struct_field_ { kind: struct_field_kind, id: node_id, @@ -1291,17 +1150,13 @@ pub struct struct_field_ { pub type struct_field = spanned<struct_field_>; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum struct_field_kind { named_field(ident, visibility), unnamed_field // element of a tuple-like struct } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct struct_def { fields: ~[@struct_field], /* fields, not including ctor */ /* ID of the constructor. This is only used for tuple- or enum-like @@ -1313,9 +1168,7 @@ pub struct struct_def { FIXME (#3300): Should allow items to be anonymous. Right now we just use dummy names for anon items. */ -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct item { ident: ident, attrs: ~[attribute], @@ -1325,9 +1178,7 @@ pub struct item { span: span, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum item_ { item_const(@Ty, @expr), item_fn(fn_decl, purity, AbiSet, Generics, blk), @@ -1345,9 +1196,7 @@ pub enum item_ { item_mac(mac), } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct foreign_item { ident: ident, attrs: ~[attribute], @@ -1357,9 +1206,7 @@ pub struct foreign_item { vis: visibility, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum foreign_item_ { foreign_item_fn(fn_decl, purity, Generics), foreign_item_const(@Ty) @@ -1368,9 +1215,7 @@ pub enum foreign_item_ { // The data we save and restore about an inlined item or method. This is not // part of the AST that we parse from a file, but it becomes part of the tree // that we trans. -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub enum inlined_item { ii_item(@item), ii_method(def_id /* impl id */, @method), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index a98e3002dcf..d4a67d61d94 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -370,8 +370,7 @@ pub fn empty_generics() -> Generics { // ______________________________________________________________________ // Enumerating the IDs which appear in an AST -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub struct id_range { min: node_id, max: node_id, @@ -413,7 +412,12 @@ pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { match vp.node { view_path_simple(_, _, id) => vfn(id), view_path_glob(_, id) => vfn(id), - view_path_list(_, _, id) => vfn(id) + view_path_list(_, ref paths, id) => { + vfn(id); + for paths.each |p| { + vfn(p.node.id); + } + } } } } diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index cd0b29f2a1e..44a368738fd 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -127,9 +127,7 @@ pub struct span { expn_info: Option<@ExpnInfo> } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, Encodable, Decodable)] pub struct spanned<T> { node: T, span: span } impl cmp::Eq for span { diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 5c306aefc6a..6bb3ac5eba4 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -8,102 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - -The compiler code necessary to implement the #[auto_encode] and -#[auto_decode] extension. The idea here is that type-defining items may -be tagged with #[auto_encode] and #[auto_decode], which will cause -us to generate a little companion module with the same name as the item. - -For example, a type like: - - #[auto_encode] - #[auto_decode] - struct Node {id: uint} - -would generate two implementations like: - -impl<S:std::serialize::Encoder> Encodable<S> for Node { - fn encode(&self, s: &S) { - do s.emit_struct("Node", 1) { - s.emit_field("id", 0, || s.emit_uint(self.id)) - } - } -} - -impl<D:Decoder> Decodable for node_id { - fn decode(d: &D) -> Node { - do d.read_struct("Node", 1) { - Node { - id: d.read_field(~"x", 0, || decode(d)) - } - } - } -} - -Other interesting scenarios are whe the item has type parameters or -references other non-built-in types. A type definition like: - - #[auto_encode] - #[auto_decode] - struct spanned<T> {node: T, span: span} - -would yield functions like: - - impl< - S: Encoder, - T: Encodable<S> - > spanned<T>: Encodable<S> { - fn encode<S:Encoder>(s: &S) { - do s.emit_rec { - s.emit_field("node", 0, || self.node.encode(s)); - s.emit_field("span", 1, || self.span.encode(s)); - } - } - } - - impl< - D: Decoder, - T: Decodable<D> - > spanned<T>: Decodable<D> { - fn decode(d: &D) -> spanned<T> { - do d.read_rec { - { - node: d.read_field(~"node", 0, || decode(d)), - span: d.read_field(~"span", 1, || decode(d)), - } - } - } - } - -FIXME (#2810)--Hygiene. Search for "__" strings. We also assume "std" is the -standard library. - -Misc notes: ------------ - -I use move mode arguments for ast nodes that will get inserted as is -into the tree. This is intended to prevent us from inserting the same -node twice. - -*/ +/// Deprecated #[auto_encode] and #[auto_decode] syntax extensions use ast; -use ast_util; -use attr; -use codemap; use codemap::span; use ext::base::*; -use parse; -use opt_vec; -use opt_vec::OptVec; -use ext::build; - -// Transitional reexports so qquote can find the paths it is looking for -mod syntax { - pub use ext; - pub use parse; -} pub fn expand_auto_encode( cx: @ext_ctxt, @@ -111,53 +20,8 @@ pub fn expand_auto_encode( _mitem: @ast::meta_item, in_items: ~[@ast::item] ) -> ~[@ast::item] { - fn is_auto_encode(a: &ast::attribute) -> bool { - *attr::get_attr_name(a) == ~"auto_encode" - } - - fn filter_attrs(item: @ast::item) -> @ast::item { - @ast::item { - attrs: item.attrs.filtered(|a| !is_auto_encode(a)), - .. copy *item - } - } - - do vec::flat_map(in_items) |item| { - if item.attrs.any(is_auto_encode) { - match item.node { - ast::item_struct(ref struct_def, ref generics) => { - let ser_impl = mk_struct_ser_impl( - cx, - item.span, - item.ident, - struct_def.fields, - generics - ); - - ~[filter_attrs(*item), ser_impl] - }, - ast::item_enum(ref enum_def, ref generics) => { - let ser_impl = mk_enum_ser_impl( - cx, - item.span, - item.ident, - copy *enum_def, - generics - ); - - ~[filter_attrs(*item), ser_impl] - }, - _ => { - cx.span_err(span, ~"#[auto_encode] can only be \ - applied to structs, record types, \ - and enum definitions"); - ~[*item] - } - } - } else { - ~[*item] - } - } + cx.span_err(span, "`#[auto_encode]` is deprecated, use `#[deriving(Encodable)]` instead"); + in_items } pub fn expand_auto_decode( @@ -166,1346 +30,6 @@ pub fn expand_auto_decode( _mitem: @ast::meta_item, in_items: ~[@ast::item] ) -> ~[@ast::item] { - fn is_auto_decode(a: &ast::attribute) -> bool { - *attr::get_attr_name(a) == ~"auto_decode" - } - - fn filter_attrs(item: @ast::item) -> @ast::item { - @ast::item { - attrs: item.attrs.filtered(|a| !is_auto_decode(a)), - .. copy *item - } - } - - do vec::flat_map(in_items) |item| { - if item.attrs.any(is_auto_decode) { - match item.node { - ast::item_struct(ref struct_def, ref generics) => { - let deser_impl = mk_struct_deser_impl( - cx, - item.span, - item.ident, - struct_def.fields, - generics - ); - - ~[filter_attrs(*item), deser_impl] - }, - ast::item_enum(ref enum_def, ref generics) => { - let deser_impl = mk_enum_deser_impl( - cx, - item.span, - item.ident, - copy *enum_def, - generics - ); - - ~[filter_attrs(*item), deser_impl] - }, - _ => { - cx.span_err(span, ~"#[auto_decode] can only be \ - applied to structs, record types, \ - and enum definitions"); - ~[*item] - } - } - } else { - ~[*item] - } - } -} - -trait ExtCtxtMethods { - fn bind_path(&self, - span: span, - ident: ast::ident, - path: @ast::Path, - bounds: @OptVec<ast::TyParamBound>) - -> ast::TyParam; - fn expr(&self, span: span, node: ast::expr_) -> @ast::expr; - fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path; - fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path; - fn path_tps(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty]) - -> @ast::Path; - fn path_tps_global(&self, - span: span, - strs: ~[ast::ident], - tps: ~[@ast::Ty]) - -> @ast::Path; - fn ty_path(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty]) - -> @ast::Ty; - fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat; - fn stmt(&self, expr: @ast::expr) -> @ast::stmt; - fn lit_str(&self, span: span, s: @~str) -> @ast::expr; - fn lit_uint(&self, span: span, i: uint) -> @ast::expr; - fn lambda0(&self, blk: ast::blk) -> @ast::expr; - fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr; - fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk; - fn expr_blk(&self, expr: @ast::expr) -> ast::blk; - fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr; - fn expr_path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::expr; - fn expr_var(&self, span: span, var: &str) -> @ast::expr; - fn expr_self(&self, span: span) -> @ast::expr; - fn expr_field(&self, span: span, expr: @ast::expr, ident: ast::ident) - -> @ast::expr; - fn expr_call(&self, span: span, expr: @ast::expr, args: ~[@ast::expr]) - -> @ast::expr; - fn expr_method_call(&self, - span: span, - expr: @ast::expr, - ident: ast::ident, - args: ~[@ast::expr]) - -> @ast::expr; - fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr; - fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) - -> @ast::expr; - fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr; - fn lambda_stmts_1(&self, - span: span, - stmts: ~[@ast::stmt], - ident: ast::ident) - -> @ast::expr; -} - -impl ExtCtxtMethods for @ext_ctxt { - fn bind_path( - &self, - _span: span, - ident: ast::ident, - path: @ast::Path, - bounds: @OptVec<ast::TyParamBound> - ) -> ast::TyParam { - let bound = ast::TraitTyParamBound(@ast::trait_ref { - ref_id: self.next_id(), - path: path - }); - - ast::TyParam { - ident: ident, - id: self.next_id(), - bounds: @bounds.prepend(bound) - } - } - - fn expr(&self, span: span, node: ast::expr_) -> @ast::expr { - @ast::expr { - id: self.next_id(), - callee_id: self.next_id(), - node: node, - span: span, - } - } - - fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path { - @ast::Path { - span: span, - global: false, - idents: strs, - rp: None, - types: ~[] - } - } - - fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path { - @ast::Path { - span: span, - global: true, - idents: strs, - rp: None, - types: ~[] - } - } - - fn path_tps( - &self, - span: span, - strs: ~[ast::ident], - tps: ~[@ast::Ty] - ) -> @ast::Path { - @ast::Path { - span: span, - global: false, - idents: strs, - rp: None, - types: tps - } - } - - fn path_tps_global( - &self, - span: span, - strs: ~[ast::ident], - tps: ~[@ast::Ty] - ) -> @ast::Path { - @ast::Path { - span: span, - global: true, - idents: strs, - rp: None, - types: tps - } - } - - fn ty_path( - &self, - span: span, - strs: ~[ast::ident], - tps: ~[@ast::Ty] - ) -> @ast::Ty { - @ast::Ty { - id: self.next_id(), - node: ast::ty_path( - self.path_tps(span, strs, tps), - self.next_id()), - span: span, - } - } - - fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat { - @ast::pat { - id: self.next_id(), - node: ast::pat_ident( - ast::bind_by_ref(ast::m_imm), - self.path(span, ~[nm]), - None), - span: span, - } - } - - fn stmt(&self, expr: @ast::expr) -> @ast::stmt { - @codemap::spanned { node: ast::stmt_semi(expr, self.next_id()), - span: expr.span } - } - - fn lit_str(&self, span: span, s: @~str) -> @ast::expr { - self.expr( - span, - ast::expr_vstore( - self.expr( - span, - ast::expr_lit( - @codemap::spanned { node: ast::lit_str(s), - span: span})), - ast::expr_vstore_uniq)) - } - - fn lit_uint(&self, span: span, i: uint) -> @ast::expr { - self.expr( - span, - ast::expr_lit( - @codemap::spanned { node: ast::lit_uint(i as u64, ast::ty_u), - span: span})) - } - - fn lambda0(&self, blk: ast::blk) -> @ast::expr { - let ext_cx = *self; - let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); - quote_expr!( || $blk_e ) - } - - fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr { - let ext_cx = *self; - let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); - quote_expr!( |$ident| $blk_e ) - } - - fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk { - codemap::spanned { - node: ast::blk_ { - view_items: ~[], - stmts: stmts, - expr: None, - id: self.next_id(), - rules: ast::default_blk, - }, - span: span, - } - } - - fn expr_blk(&self, expr: @ast::expr) -> ast::blk { - codemap::spanned { - node: ast::blk_ { - view_items: ~[], - stmts: ~[], - expr: Some(expr), - id: self.next_id(), - rules: ast::default_blk, - }, - span: expr.span, - } - } - - fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr { - self.expr(span, ast::expr_path(self.path(span, strs))) - } - - fn expr_path_global( - &self, - span: span, - strs: ~[ast::ident] - ) -> @ast::expr { - self.expr(span, ast::expr_path(self.path_global(span, strs))) - } - - fn expr_var(&self, span: span, var: &str) -> @ast::expr { - self.expr_path(span, ~[self.ident_of(var)]) - } - - fn expr_self(&self, span: span) -> @ast::expr { - self.expr(span, ast::expr_self) - } - - fn expr_field( - &self, - span: span, - expr: @ast::expr, - ident: ast::ident - ) -> @ast::expr { - self.expr(span, ast::expr_field(expr, ident, ~[])) - } - - fn expr_call( - &self, - span: span, - expr: @ast::expr, - args: ~[@ast::expr] - ) -> @ast::expr { - self.expr(span, ast::expr_call(expr, args, ast::NoSugar)) - } - - fn expr_method_call( - &self, - span: span, - expr: @ast::expr, - ident: ast::ident, - args: ~[@ast::expr] - ) -> @ast::expr { - self.expr(span, - ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar)) - } - - fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr { - self.lambda0(self.expr_blk(expr)) - } - - fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) - -> @ast::expr { - self.lambda1(self.expr_blk(expr), ident) - } - - fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr { - self.lambda0(self.blk(span, stmts)) - } - - fn lambda_stmts_1(&self, - span: span, - stmts: ~[@ast::stmt], - ident: ast::ident) - -> @ast::expr { - self.lambda1(self.blk(span, stmts), ident) - } -} - -fn mk_impl( - cx: @ext_ctxt, - span: span, - ident: ast::ident, - ty_param: ast::TyParam, - path: @ast::Path, - generics: &ast::Generics, - f: &fn(@ast::Ty) -> @ast::method -) -> @ast::item { - /*! - * - * Given that we are deriving auto-encode a type `T<'a, ..., - * 'z, A, ..., Z>`, creates an impl like: - * - * impl<'a, ..., 'z, A:Tr, ..., Z:Tr> Tr for T<A, ..., Z> { ... } - * - * where Tr is either Serializable and Deserialize. - * - * FIXME(#5090): Remove code duplication between this and the code - * in deriving.rs - */ - - - // Copy the lifetimes - let impl_lifetimes = generics.lifetimes.map(|l| { - build::mk_lifetime(cx, l.span, l.ident) - }); - - // All the type parameters need to bound to the trait. - let mut impl_tps = opt_vec::with(ty_param); - for generics.ty_params.each |tp| { - let t_bound = ast::TraitTyParamBound(@ast::trait_ref { - path: path, - ref_id: cx.next_id(), - }); - - impl_tps.push(ast::TyParam { - ident: tp.ident, - id: cx.next_id(), - bounds: @tp.bounds.prepend(t_bound) - }) - } - - let opt_trait = Some(@ast::trait_ref { - path: path, - ref_id: cx.next_id(), - }); - - let ty = cx.ty_path( - span, - ~[ident], - opt_vec::take_vec(generics.ty_params.map( - |tp| cx.ty_path(span, ~[tp.ident], ~[]))) - ); - - let generics = ast::Generics { - lifetimes: impl_lifetimes, - ty_params: impl_tps - }; - - @ast::item { - // This is a new-style impl declaration. - // XXX: clownshoes - ident: parse::token::special_idents::clownshoes_extensions, - attrs: ~[], - id: cx.next_id(), - node: ast::item_impl(generics, opt_trait, ty, ~[f(ty)]), - vis: ast::public, - span: span, - } -} - -fn mk_ser_impl( - cx: @ext_ctxt, - span: span, - ident: ast::ident, - generics: &ast::Generics, - body: @ast::expr -) -> @ast::item { - // Make a path to the std::serialize::Encodable typaram. - let ty_param = cx.bind_path( - span, - cx.ident_of("__S"), - cx.path_global( - span, - ~[ - cx.ident_of("std"), - cx.ident_of("serialize"), - cx.ident_of("Encoder"), - ] - ), - @opt_vec::Empty - ); - - // Make a path to the std::serialize::Encodable trait. - let path = cx.path_tps_global( - span, - ~[ - cx.ident_of("std"), - cx.ident_of("serialize"), - cx.ident_of("Encodable"), - ], - ~[cx.ty_path(span, ~[cx.ident_of("__S")], ~[])] - ); - - mk_impl( - cx, - span, - ident, - ty_param, - path, - generics, - |_ty| mk_ser_method(cx, span, cx.expr_blk(body)) - ) -} - -fn mk_deser_impl( - cx: @ext_ctxt, - span: span, - ident: ast::ident, - generics: &ast::Generics, - body: @ast::expr -) -> @ast::item { - // Make a path to the std::serialize::Decodable typaram. - let ty_param = cx.bind_path( - span, - cx.ident_of("__D"), - cx.path_global( - span, - ~[ - cx.ident_of("std"), - cx.ident_of("serialize"), - cx.ident_of("Decoder"), - ] - ), - @opt_vec::Empty - ); - - // Make a path to the std::serialize::Decodable trait. - let path = cx.path_tps_global( - span, - ~[ - cx.ident_of("std"), - cx.ident_of("serialize"), - cx.ident_of("Decodable"), - ], - ~[cx.ty_path(span, ~[cx.ident_of("__D")], ~[])] - ); - - mk_impl( - cx, - span, - ident, - ty_param, - path, - generics, - |ty| mk_deser_method(cx, span, ty, cx.expr_blk(body)) - ) -} - -fn mk_ser_method( - cx: @ext_ctxt, - span: span, - ser_body: ast::blk -) -> @ast::method { - let ty_s = @ast::Ty { - id: cx.next_id(), - node: ast::ty_rptr( - None, - ast::mt { - ty: cx.ty_path(span, ~[cx.ident_of("__S")], ~[]), - mutbl: ast::m_mutbl - } - ), - span: span, - }; - - let ser_inputs = ~[ast::arg { - is_mutbl: false, - ty: ty_s, - pat: @ast::pat { - id: cx.next_id(), - node: ast::pat_ident( - ast::bind_by_copy, - ast_util::ident_to_path(span, cx.ident_of("__s")), - None), - span: span, - }, - id: cx.next_id(), - }]; - - let ser_output = @ast::Ty { - id: cx.next_id(), - node: ast::ty_nil, - span: span, - }; - - let ser_decl = ast::fn_decl { - inputs: ser_inputs, - output: ser_output, - cf: ast::return_val, - }; - - @ast::method { - ident: cx.ident_of("encode"), - attrs: ~[], - generics: ast_util::empty_generics(), - explicit_self: codemap::spanned { - node: ast::sty_region(None, ast::m_imm), - span: span - }, - purity: ast::impure_fn, - decl: ser_decl, - body: ser_body, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: ast::public, - } -} - -fn mk_deser_method( - cx: @ext_ctxt, - span: span, - ty: @ast::Ty, - deser_body: ast::blk -) -> @ast::method { - let ty_d = @ast::Ty { - id: cx.next_id(), - node: ast::ty_rptr( - None, - ast::mt { - ty: cx.ty_path(span, ~[cx.ident_of("__D")], ~[]), - mutbl: ast::m_mutbl - } - ), - span: span, - }; - - let deser_inputs = ~[ - ast::arg { - is_mutbl: false, - ty: ty_d, - pat: @ast::pat { - id: cx.next_id(), - node: ast::pat_ident(ast::bind_by_copy, - ast_util::ident_to_path(span, - cx.ident_of( - "__d")), - None), - span: span, - }, - id: cx.next_id(), - } - ]; - - let deser_decl = ast::fn_decl { - inputs: deser_inputs, - output: ty, - cf: ast::return_val, - }; - - @ast::method { - ident: cx.ident_of("decode"), - attrs: ~[], - generics: ast_util::empty_generics(), - explicit_self: codemap::spanned { node: ast::sty_static, span: span }, - purity: ast::impure_fn, - decl: deser_decl, - body: deser_body, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: ast::public, - } -} - -fn mk_struct_ser_impl( - cx: @ext_ctxt, - span: span, - ident: ast::ident, - fields: &[@ast::struct_field], - generics: &ast::Generics -) -> @ast::item { - let fields = do mk_struct_fields(fields).mapi |idx, field| { - // ast for `|__s| self.$(name).encode(__s)` - let expr_lambda = cx.lambda_expr_1( - cx.expr_method_call( - span, - cx.expr_field(span, cx.expr_self(span), field.ident), - cx.ident_of(~"encode"), - ~[cx.expr_var(span, "__s")] - ), - cx.ident_of("__s") - ); - - // ast for `__s.emit_struct_field($(name), $(idx), $(expr_lambda))` - cx.stmt( - cx.expr_method_call( - span, - cx.expr_var(span, "__s"), - cx.ident_of("emit_struct_field"), - ~[ - cx.lit_str(span, @cx.str_of(field.ident)), - cx.lit_uint(span, idx), - expr_lambda, - ] - ) - ) - }; - - // ast for `__s.emit_struct($(name), |__s| $(fields))` - let ser_body = cx.expr_method_call( - span, - cx.expr_var(span, "__s"), - cx.ident_of("emit_struct"), - ~[ - cx.lit_str(span, @cx.str_of(ident)), - cx.lit_uint(span, fields.len()), - cx.lambda_stmts_1(span, fields, cx.ident_of("__s")), - ] - ); - - mk_ser_impl(cx, span, ident, generics, ser_body) -} - -fn mk_struct_deser_impl( - cx: @ext_ctxt, - span: span, - ident: ast::ident, - fields: &[@ast::struct_field], - generics: &ast::Generics -) -> @ast::item { - let fields = do mk_struct_fields(fields).mapi |idx, field| { - // ast for `|__d| std::serialize::decode(__d)` - let expr_lambda = cx.lambda1( - cx.expr_blk( - cx.expr_call( - span, - cx.expr_path_global(span, ~[ - cx.ident_of("std"), - cx.ident_of("serialize"), - cx.ident_of("Decodable"), - cx.ident_of("decode"), - ]), - ~[cx.expr_var(span, "__d")] - ) - ), - cx.ident_of("__d") - ); - - // ast for `__d.read_struct_field($(name), $(idx), $(expr_lambda))` - let expr: @ast::expr = cx.expr_method_call( - span, - cx.expr_var(span, "__d"), - cx.ident_of("read_struct_field"), - ~[ - cx.lit_str(span, @cx.str_of(field.ident)), - cx.lit_uint(span, idx), - expr_lambda, - ] - ); - - codemap::spanned { - node: ast::field_ { - mutbl: field.mutbl, - ident: field.ident, - expr: expr, - }, - span: span, - } - }; - - // ast for `read_struct($(name), |__d| $(fields))` - let body = cx.expr_method_call( - span, - cx.expr_var(span, "__d"), - cx.ident_of("read_struct"), - ~[ - cx.lit_str(span, @cx.str_of(ident)), - cx.lit_uint(span, fields.len()), - cx.lambda_expr_1( - cx.expr( - span, - ast::expr_struct( - cx.path(span, ~[ident]), - fields, - None - ) - ), - cx.ident_of("__d") - ), - ] - ); - - mk_deser_impl(cx, span, ident, generics, body) -} - -// Records and structs don't have the same fields types, but they share enough -// that if we extract the right subfields out we can share the code -// generator code. -struct field { - span: span, - ident: ast::ident, - mutbl: ast::mutability, -} - -fn mk_struct_fields(fields: &[@ast::struct_field]) -> ~[field] { - do fields.map |field| { - let ident = match field.node.kind { - ast::named_field(ident, _) => ident, - _ => fail!("[auto_encode] does not support unnamed fields") - }; - - field { - span: field.span, - ident: ident, - mutbl: ast::m_imm, - } - } -} - -fn mk_enum_ser_impl( - cx: @ext_ctxt, - span: span, - ident: ast::ident, - enum_def: ast::enum_def, - generics: &ast::Generics -) -> @ast::item { - let body = mk_enum_ser_body( - cx, - span, - ident, - copy enum_def.variants - ); - - mk_ser_impl(cx, span, ident, generics, body) -} - -fn mk_enum_deser_impl( - cx: @ext_ctxt, - span: span, - ident: ast::ident, - enum_def: ast::enum_def, - generics: &ast::Generics -) -> @ast::item { - let body = mk_enum_deser_body( - cx, - span, - ident, - enum_def.variants - ); - - mk_deser_impl(cx, span, ident, generics, body) -} - -fn ser_variant( - cx: @ext_ctxt, - span: span, - v_name: ast::ident, - v_idx: uint, - args: ~[ast::variant_arg] -) -> ast::arm { - // Name the variant arguments. - let names = args.mapi(|i, _arg| cx.ident_of(fmt!("__v%u", i))); - - // Bind the names to the variant argument type. - let pats = args.mapi(|i, arg| cx.binder_pat(arg.ty.span, names[i])); - - let pat_node = if pats.is_empty() { - ast::pat_ident( - ast::bind_infer, - cx.path(span, ~[v_name]), - None - ) - } else { - ast::pat_enum( - cx.path(span, ~[v_name]), - Some(pats) - ) - }; - - let pat = @ast::pat { - id: cx.next_id(), - node: pat_node, - span: span, - }; - - let stmts = do args.mapi |a_idx, _arg| { - // ast for `__s.emit_enum_variant_arg` - let expr_emit = cx.expr_field( - span, - cx.expr_var(span, "__s"), - cx.ident_of("emit_enum_variant_arg") - ); - - // ast for `|__s| $(v).encode(__s)` - let expr_encode = cx.lambda_expr_1( - cx.expr_method_call( - span, - cx.expr_path(span, ~[names[a_idx]]), - cx.ident_of("encode"), - ~[cx.expr_var(span, "__s")] - ), - cx.ident_of("__s") - ); - - // ast for `$(expr_emit)($(a_idx), $(expr_encode))` - cx.stmt( - cx.expr_call( - span, - expr_emit, - ~[cx.lit_uint(span, a_idx), expr_encode] - ) - ) - }; - - // ast for `__s.emit_enum_variant($(name), $(idx), $(sz), $(lambda))` - let body = cx.expr_method_call( - span, - cx.expr_var(span, "__s"), - cx.ident_of("emit_enum_variant"), - ~[ - cx.lit_str(span, @cx.str_of(v_name)), - cx.lit_uint(span, v_idx), - cx.lit_uint(span, stmts.len()), - cx.lambda_stmts_1(span, stmts, cx.ident_of("__s")), - ] - ); - - ast::arm { pats: ~[pat], guard: None, body: cx.expr_blk(body) } -} - -fn mk_enum_ser_body( - cx: @ext_ctxt, - span: span, - name: ast::ident, - variants: ~[ast::variant] -) -> @ast::expr { - let arms = do variants.mapi |v_idx, variant| { - match variant.node.kind { - ast::tuple_variant_kind(ref args) => - ser_variant( - cx, - span, - variant.node.name, - v_idx, - /*bad*/ copy *args - ), - ast::struct_variant_kind(*) => - fail!("struct variants unimplemented"), - } - }; - - // ast for `match *self { $(arms) }` - let match_expr = cx.expr( - span, - ast::expr_match(cx.expr(span, - ast::expr_unary(ast::deref, - cx.expr_self(span))), - arms) - ); - - // ast for `__s.emit_enum($(name), || $(match_expr))` - cx.expr_method_call( - span, - cx.expr_var(span, "__s"), - cx.ident_of("emit_enum"), - ~[ - cx.lit_str(span, @cx.str_of(name)), - cx.lambda_expr_1(match_expr, cx.ident_of("__s")), - ] - ) -} - -fn mk_enum_deser_variant_nary( - cx: @ext_ctxt, - span: span, - name: ast::ident, - args: ~[ast::variant_arg] -) -> @ast::expr { - let args = do args.mapi |idx, _arg| { - // ast for `|__s| std::serialize::decode(__d)` - let expr_lambda = cx.lambda_expr_1( - cx.expr_call( - span, - cx.expr_path_global(span, ~[ - cx.ident_of("std"), - cx.ident_of("serialize"), - cx.ident_of("Decodable"), - cx.ident_of("decode"), - ]), - ~[cx.expr_var(span, "__d")] - ), - cx.ident_of("__d") - ); - - // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))` - cx.expr_method_call( - span, - cx.expr_var(span, "__d"), - cx.ident_of("read_enum_variant_arg"), - ~[cx.lit_uint(span, idx), expr_lambda] - ) - }; - - // ast for `$(name)($(args))` - cx.expr_call(span, cx.expr_path(span, ~[name]), args) -} - -fn mk_enum_deser_body( - ext_cx: @ext_ctxt, - span: span, - name: ast::ident, - variants: &[ast::variant] -) -> @ast::expr { - let expr_arm_names = build::mk_base_vec_e( - ext_cx, - span, - do variants.map |variant| { - build::mk_base_str( - ext_cx, - span, - ext_cx.str_of(variant.node.name) - ) - } - ); - - let mut arms = do variants.mapi |v_idx, variant| { - let body = match variant.node.kind { - ast::tuple_variant_kind(ref args) => { - if args.is_empty() { - // for a nullary variant v, do "v" - ext_cx.expr_path(span, ~[variant.node.name]) - } else { - // for an n-ary variant v, do "v(a_1, ..., a_n)" - mk_enum_deser_variant_nary( - ext_cx, - span, - variant.node.name, - copy *args - ) - } - }, - ast::struct_variant_kind(*) => - fail!("struct variants unimplemented"), - }; - - let pat = @ast::pat { - id: ext_cx.next_id(), - node: ast::pat_lit(ext_cx.lit_uint(span, v_idx)), - span: span, - }; - - ast::arm { - pats: ~[pat], - guard: None, - body: ext_cx.expr_blk(body), - } - }; - - let quoted_expr = copy quote_expr!( - ::core::sys::FailWithCause::fail_with("explicit failure", "empty", 1); - ).node; - - let impossible_case = ast::arm { - pats: ~[@ast::pat { - id: ext_cx.next_id(), - node: ast::pat_wild, - span: span, - }], - guard: None, - - // FIXME(#3198): proper error message - body: ext_cx.expr_blk(ext_cx.expr(span, quoted_expr)), - }; - - arms.push(impossible_case); - - // ast for `|i| { match i { $(arms) } }` - let expr_lambda = ext_cx.expr( - span, - ast::expr_fn_block( - ast::fn_decl { - inputs: ~[ - ast::arg { - is_mutbl: false, - ty: @ast::Ty { - id: ext_cx.next_id(), - node: ast::ty_infer, - span: span - }, - pat: @ast::pat { - id: ext_cx.next_id(), - node: ast::pat_ident( - ast::bind_by_copy, - ast_util::ident_to_path(span, - ext_cx.ident_of("__d")), - None), - span: span, - }, - id: ext_cx.next_id(), - }, - ast::arg { - is_mutbl: false, - ty: @ast::Ty { - id: ext_cx.next_id(), - node: ast::ty_infer, - span: span - }, - pat: @ast::pat { - id: ext_cx.next_id(), - node: ast::pat_ident( - ast::bind_by_copy, - ast_util::ident_to_path(span, - ext_cx.ident_of("i")), - None), - span: span, - }, - id: ext_cx.next_id(), - } - ], - output: @ast::Ty { - id: ext_cx.next_id(), - node: ast::ty_infer, - span: span, - }, - cf: ast::return_val, - }, - ext_cx.expr_blk( - ext_cx.expr( - span, - ast::expr_match(ext_cx.expr_var(span, "i"), arms) - ) - ) - ) - ); - - // ast for `__d.read_enum_variant($expr_arm_names, $(expr_lambda))` - let expr_lambda = ext_cx.lambda_expr_1( - ext_cx.expr_method_call( - span, - ext_cx.expr_var(span, "__d"), - ext_cx.ident_of("read_enum_variant"), - ~[expr_arm_names, expr_lambda] - ), - ext_cx.ident_of("__d") - ); - - // ast for `__d.read_enum($(e_name), $(expr_lambda))` - ext_cx.expr_method_call( - span, - ext_cx.expr_var(span, "__d"), - ext_cx.ident_of("read_enum"), - ~[ - ext_cx.lit_str(span, @ext_cx.str_of(name)), - expr_lambda - ] - ) -} - -#[cfg(test)] -mod test { - use core::option::{None, Some}; - use std::serialize::Encodable; - use std::serialize::Encoder; - - // just adding the ones I want to test, for now: - #[deriving(Eq)] - pub enum call { - CallToEmitEnum(~str), - CallToEmitEnumVariant(~str, uint, uint), - CallToEmitEnumVariantArg(uint), - CallToEmitUint(uint), - CallToEmitNil, - CallToEmitStruct(~str,uint), - CallToEmitField(~str,uint), - CallToEmitOption, - CallToEmitOptionNone, - CallToEmitOptionSome, - // all of the ones I was too lazy to handle: - CallToOther - } - // using `@mut` rather than changing the - // type of self in every method of every encoder everywhere. - pub struct TestEncoder {call_log : @mut ~[call]} - - pub impl TestEncoder { - // these self's should be &mut self's, as well.... - fn add_to_log (&self, c : call) { - self.call_log.push(copy c); - } - fn add_unknown_to_log (&self) { - self.add_to_log (CallToOther) - } - } - - impl Encoder for TestEncoder { - fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) } - - fn emit_uint(&mut self, v: uint) { - self.add_to_log(CallToEmitUint(v)); - } - fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); } - fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); } - fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); } - fn emit_u8(&mut self, _v: u8) { self.add_unknown_to_log(); } - - fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); } - fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); } - fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); } - fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); } - fn emit_i8(&mut self, _v: i8) { self.add_unknown_to_log(); } - - fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); } - - fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); } - fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); } - fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); } - - fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); } - fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); } - - fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitEnum(name.to_str())); - f(self); - } - - fn emit_enum_variant(&mut self, - name: &str, - id: uint, - cnt: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt)); - f(self); - } - - fn emit_enum_variant_arg(&mut self, - idx: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitEnumVariantArg(idx)); - f(self); - } - - fn emit_enum_struct_variant(&mut self, - name: &str, - id: uint, - cnt: uint, - f: &fn(&mut TestEncoder)) { - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field(&mut self, - _name: &str, - idx: uint, - f: &fn(&mut TestEncoder)) { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&mut self, - name: &str, - len: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitStruct (name.to_str(),len)); - f(self); - } - fn emit_struct_field(&mut self, - name: &str, - idx: uint, - f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitField (name.to_str(),idx)); - f(self); - } - - fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_tuple_struct(&mut self, - _name: &str, - _len: uint, - f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_tuple_struct_arg(&mut self, - _idx: uint, - f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_option(&mut self, f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitOption); - f(self); - } - fn emit_option_none(&mut self) { - self.add_to_log(CallToEmitOptionNone); - } - fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) { - self.add_to_log(CallToEmitOptionSome); - f(self); - } - - fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - - fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { - self.add_unknown_to_log(); - f(self); - } - } - - - fn to_call_log<E:Encodable<TestEncoder>>(val: E) -> ~[call] { - let mut te = TestEncoder { - call_log: @mut ~[] - }; - val.encode(&mut te); - copy *te.call_log - } - - #[auto_encode] - enum Written { - Book(uint,uint), - Magazine(~str) - } - - #[test] - fn test_encode_enum() { - assert_eq!( - to_call_log(Book(34,44)), - ~[ - CallToEmitEnum(~"Written"), - CallToEmitEnumVariant(~"Book",0,2), - CallToEmitEnumVariantArg(0), - CallToEmitUint(34), - CallToEmitEnumVariantArg(1), - CallToEmitUint(44), - ] - ); - } - - pub struct BPos(uint); - - #[auto_encode] - pub struct HasPos { pos : BPos } - - #[test] - fn test_encode_newtype() { - assert_eq!( - to_call_log(HasPos { pos:BPos(48) }), - ~[ - CallToEmitStruct(~"HasPos",1), - CallToEmitField(~"pos",0), - CallToEmitUint(48), - ] - ); - } - - #[test] - fn test_encode_option() { - let mut v = None; - - assert_eq!( - to_call_log(v), - ~[ - CallToEmitOption, - CallToEmitOptionNone, - ] - ); - - v = Some(54u); - assert_eq!( - to_call_log(v), - ~[ - CallToEmitOption, - CallToEmitOptionSome, - CallToEmitUint(54) - ] - ); - } + cx.span_err(span, "`#[auto_decode]` is deprecated, use `#[deriving(Decodable)]` instead"); + in_items } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 30470d2ebe7..a97c69ba4ff 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -139,6 +139,8 @@ pub fn syntax_expander_table() -> SyntaxEnv { @SE(ItemDecorator(ext::auto_encode::expand_auto_decode))); syntax_expanders.insert(@~"env", builtin_normal_tt(ext::env::expand_syntax_ext)); + syntax_expanders.insert(@~"bytes", + builtin_normal_tt(ext::bytes::expand_syntax_ext)); syntax_expanders.insert(@~"concat_idents", builtin_normal_tt( ext::concat_idents::expand_syntax_ext)); @@ -148,15 +150,6 @@ pub fn syntax_expander_table() -> SyntaxEnv { syntax_expanders.insert(@~"deriving", @SE(ItemDecorator( ext::deriving::expand_meta_deriving))); - syntax_expanders.insert(@~"deriving_eq", - @SE(ItemDecorator( - ext::deriving::eq::expand_deriving_obsolete))); - syntax_expanders.insert(@~"deriving_iter_bytes", - @SE(ItemDecorator( - ext::deriving::iter_bytes::expand_deriving_obsolete))); - syntax_expanders.insert(@~"deriving_clone", - @SE(ItemDecorator( - ext::deriving::clone::expand_deriving_obsolete))); // Quasi-quoting expanders syntax_expanders.insert(@~"quote_tokens", diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 605ba65b51a..624e0495e59 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -196,6 +196,7 @@ pub fn mk_global_struct_e(cx: @ext_ctxt, } pub fn mk_glob_use(cx: @ext_ctxt, sp: span, + vis: ast::visibility, path: ~[ast::ident]) -> @ast::view_item { let glob = @codemap::spanned { node: ast::view_path_glob(mk_raw_path(sp, path), cx.next_id()), @@ -203,7 +204,7 @@ pub fn mk_glob_use(cx: @ext_ctxt, }; @ast::view_item { node: ast::view_item_use(~[glob]), attrs: ~[], - vis: ast::private, + vis: vis, span: sp } } pub fn mk_local(cx: @ext_ctxt, sp: span, mutbl: bool, @@ -538,3 +539,301 @@ pub fn duplicate_expr(cx: @ext_ctxt, expr: @ast::expr) -> @ast::expr { folder.fold_expr(expr) } + + +// Transitional reexports so qquote can find the paths it is looking for +mod syntax { + pub use ext; + pub use parse; +} + +trait ExtCtxtMethods { + fn bind_path(&self, + span: span, + ident: ast::ident, + path: @ast::Path, + bounds: @OptVec<ast::TyParamBound>) + -> ast::TyParam; + fn expr(&self, span: span, node: ast::expr_) -> @ast::expr; + fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path; + fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path; + fn path_tps(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty]) + -> @ast::Path; + fn path_tps_global(&self, + span: span, + strs: ~[ast::ident], + tps: ~[@ast::Ty]) + -> @ast::Path; + fn ty_path(&self, span: span, strs: ~[ast::ident], tps: ~[@ast::Ty]) + -> @ast::Ty; + fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat; + fn stmt(&self, expr: @ast::expr) -> @ast::stmt; + fn lit_str(&self, span: span, s: @~str) -> @ast::expr; + fn lit_uint(&self, span: span, i: uint) -> @ast::expr; + fn lambda0(&self, blk: ast::blk) -> @ast::expr; + fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr; + fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk; + fn expr_blk(&self, expr: @ast::expr) -> ast::blk; + fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr; + fn expr_path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::expr; + fn expr_var(&self, span: span, var: &str) -> @ast::expr; + fn expr_self(&self, span: span) -> @ast::expr; + fn expr_field(&self, span: span, expr: @ast::expr, ident: ast::ident) + -> @ast::expr; + fn expr_call(&self, span: span, expr: @ast::expr, args: ~[@ast::expr]) + -> @ast::expr; + fn expr_method_call(&self, + span: span, + expr: @ast::expr, + ident: ast::ident, + args: ~[@ast::expr]) + -> @ast::expr; + fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr; + fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) + -> @ast::expr; + fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr; + fn lambda_stmts_1(&self, + span: span, + stmts: ~[@ast::stmt], + ident: ast::ident) + -> @ast::expr; +} + +impl ExtCtxtMethods for @ext_ctxt { + fn bind_path( + &self, + _span: span, + ident: ast::ident, + path: @ast::Path, + bounds: @OptVec<ast::TyParamBound> + ) -> ast::TyParam { + let bound = ast::TraitTyParamBound(@ast::trait_ref { + ref_id: self.next_id(), + path: path + }); + + ast::TyParam { + ident: ident, + id: self.next_id(), + bounds: @bounds.prepend(bound) + } + } + + fn expr(&self, span: span, node: ast::expr_) -> @ast::expr { + @ast::expr { + id: self.next_id(), + callee_id: self.next_id(), + node: node, + span: span, + } + } + + fn path(&self, span: span, strs: ~[ast::ident]) -> @ast::Path { + @ast::Path { + span: span, + global: false, + idents: strs, + rp: None, + types: ~[] + } + } + + fn path_global(&self, span: span, strs: ~[ast::ident]) -> @ast::Path { + @ast::Path { + span: span, + global: true, + idents: strs, + rp: None, + types: ~[] + } + } + + fn path_tps( + &self, + span: span, + strs: ~[ast::ident], + tps: ~[@ast::Ty] + ) -> @ast::Path { + @ast::Path { + span: span, + global: false, + idents: strs, + rp: None, + types: tps + } + } + + fn path_tps_global( + &self, + span: span, + strs: ~[ast::ident], + tps: ~[@ast::Ty] + ) -> @ast::Path { + @ast::Path { + span: span, + global: true, + idents: strs, + rp: None, + types: tps + } + } + + fn ty_path( + &self, + span: span, + strs: ~[ast::ident], + tps: ~[@ast::Ty] + ) -> @ast::Ty { + @ast::Ty { + id: self.next_id(), + node: ast::ty_path( + self.path_tps(span, strs, tps), + self.next_id()), + span: span, + } + } + + fn binder_pat(&self, span: span, nm: ast::ident) -> @ast::pat { + @ast::pat { + id: self.next_id(), + node: ast::pat_ident( + ast::bind_by_ref(ast::m_imm), + self.path(span, ~[nm]), + None), + span: span, + } + } + + fn stmt(&self, expr: @ast::expr) -> @ast::stmt { + @codemap::spanned { node: ast::stmt_semi(expr, self.next_id()), + span: expr.span } + } + + fn lit_str(&self, span: span, s: @~str) -> @ast::expr { + self.expr( + span, + ast::expr_vstore( + self.expr( + span, + ast::expr_lit( + @codemap::spanned { node: ast::lit_str(s), + span: span})), + ast::expr_vstore_uniq)) + } + + fn lit_uint(&self, span: span, i: uint) -> @ast::expr { + self.expr( + span, + ast::expr_lit( + @codemap::spanned { node: ast::lit_uint(i as u64, ast::ty_u), + span: span})) + } + + fn lambda0(&self, blk: ast::blk) -> @ast::expr { + let ext_cx = *self; + let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); + quote_expr!( || $blk_e ) + } + + fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr { + let ext_cx = *self; + let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); + quote_expr!( |$ident| $blk_e ) + } + + fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk { + codemap::spanned { + node: ast::blk_ { + view_items: ~[], + stmts: stmts, + expr: None, + id: self.next_id(), + rules: ast::default_blk, + }, + span: span, + } + } + + fn expr_blk(&self, expr: @ast::expr) -> ast::blk { + codemap::spanned { + node: ast::blk_ { + view_items: ~[], + stmts: ~[], + expr: Some(expr), + id: self.next_id(), + rules: ast::default_blk, + }, + span: expr.span, + } + } + + fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr { + self.expr(span, ast::expr_path(self.path(span, strs))) + } + + fn expr_path_global( + &self, + span: span, + strs: ~[ast::ident] + ) -> @ast::expr { + self.expr(span, ast::expr_path(self.path_global(span, strs))) + } + + fn expr_var(&self, span: span, var: &str) -> @ast::expr { + self.expr_path(span, ~[self.ident_of(var)]) + } + + fn expr_self(&self, span: span) -> @ast::expr { + self.expr(span, ast::expr_self) + } + + fn expr_field( + &self, + span: span, + expr: @ast::expr, + ident: ast::ident + ) -> @ast::expr { + self.expr(span, ast::expr_field(expr, ident, ~[])) + } + + fn expr_call( + &self, + span: span, + expr: @ast::expr, + args: ~[@ast::expr] + ) -> @ast::expr { + self.expr(span, ast::expr_call(expr, args, ast::NoSugar)) + } + + fn expr_method_call( + &self, + span: span, + expr: @ast::expr, + ident: ast::ident, + args: ~[@ast::expr] + ) -> @ast::expr { + self.expr(span, + ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar)) + } + + fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr { + self.lambda0(self.expr_blk(expr)) + } + + fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) + -> @ast::expr { + self.lambda1(self.expr_blk(expr), ident) + } + + fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr { + self.lambda0(self.blk(span, stmts)) + } + + fn lambda_stmts_1(&self, + span: span, + stmts: ~[@ast::stmt], + ident: ast::ident) + -> @ast::expr { + self.lambda1(self.blk(span, stmts), ident) + } +} diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs new file mode 100644 index 00000000000..7c2f27ada3b --- /dev/null +++ b/src/libsyntax/ext/bytes.rs @@ -0,0 +1,73 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/* The compiler code necessary to support the bytes! extension. */ + +use ast; +use codemap::span; +use ext::base::*; +use ext::base; +use ext::build::{mk_u8, mk_slice_vec_e}; + +pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) -> base::MacResult { + // Gather all argument expressions + let exprs = get_exprs_from_tts(cx, tts); + let mut bytes = ~[]; + + for exprs.each |expr| { + match expr.node { + // expression is a literal + ast::expr_lit(lit) => match lit.node { + // string literal, push each byte to vector expression + ast::lit_str(s) => { + for s.each |byte| { + bytes.push(mk_u8(cx, sp, byte)); + } + } + + // u8 literal, push to vector expression + ast::lit_uint(v, ast::ty_u8) => { + if v > 0xFF { + cx.span_err(sp, "Too large u8 literal in bytes!") + } else { + bytes.push(mk_u8(cx, sp, v as u8)); + } + } + + // integer literal, push to vector expression + ast::lit_int_unsuffixed(v) => { + if v > 0xFF { + cx.span_err(sp, "Too large integer literal in bytes!") + } else if v < 0 { + cx.span_err(sp, "Negative integer literal in bytes!") + } else { + bytes.push(mk_u8(cx, sp, v as u8)); + } + } + + // char literal, push to vector expression + ast::lit_int(v, ast::ty_char) => { + if (v as char).is_ascii() { + bytes.push(mk_u8(cx, sp, v as u8)); + } else { + cx.span_err(sp, "Non-ascii char literal in bytes!") + } + } + + _ => cx.span_err(sp, "Unsupported literal in bytes!") + }, + + _ => cx.span_err(sp, "Non-literal in bytes!") + } + } + + let e = mk_slice_vec_e(cx, sp, bytes); + MRExpr(e) +} diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 1a45107c267..aceb60ebbd7 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -32,7 +32,7 @@ pub fn expand_deriving_clone(cx: @ext_ctxt, args: ~[], ret_ty: Self, const_nonmatching: false, - combine_substructure: cs_clone + combine_substructure: |c, s, sub| cs_clone("Clone", c, s, sub) } ] }; @@ -42,17 +42,39 @@ pub fn expand_deriving_clone(cx: @ext_ctxt, &trait_def) } -pub fn expand_deriving_obsolete(cx: @ext_ctxt, - span: span, - _mitem: @meta_item, - in_items: ~[@item]) - -> ~[@item] { - cx.span_err(span, ~"`#[deriving_clone]` is obsolete; use `#[deriving(Clone)]` instead"); - in_items +pub fn expand_deriving_deep_clone(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) + -> ~[@item] { + let trait_def = TraitDef { + path: Path::new(~[~"core", ~"clone", ~"DeepClone"]), + additional_bounds: ~[], + generics: LifetimeBounds::empty(), + methods: ~[ + MethodDef { + name: ~"deep_clone", + generics: LifetimeBounds::empty(), + explicit_self: borrowed_explicit_self(), + args: ~[], + ret_ty: Self, + const_nonmatching: false, + // cs_clone uses the ident passed to it, i.e. it will + // call deep_clone (not clone) here. + combine_substructure: |c, s, sub| cs_clone("DeepClone", c, s, sub) + } + ] + }; + + expand_deriving_generic(cx, span, + mitem, in_items, + &trait_def) } -fn cs_clone(cx: @ext_ctxt, span: span, - substr: &Substructure) -> @expr { +fn cs_clone( + name: &str, + cx: @ext_ctxt, span: span, + substr: &Substructure) -> @expr { let clone_ident = substr.method_ident; let ctor_ident; let all_fields; @@ -68,8 +90,12 @@ fn cs_clone(cx: @ext_ctxt, span: span, ctor_ident = ~[ variant.node.name ]; all_fields = af; }, - EnumNonMatching(*) => cx.span_bug(span, "Non-matching enum variants in `deriving(Clone)`"), - StaticEnum(*) | StaticStruct(*) => cx.span_bug(span, "Static method in `deriving(Clone)`") + EnumNonMatching(*) => cx.span_bug(span, + fmt!("Non-matching enum variants in `deriving(%s)`", + name)), + StaticEnum(*) | StaticStruct(*) => cx.span_bug(span, + fmt!("Static method in `deriving(%s)`", + name)) } match *all_fields { @@ -84,8 +110,8 @@ fn cs_clone(cx: @ext_ctxt, span: span, let ident = match o_id { Some(i) => i, None => cx.span_bug(span, - ~"unnamed field in normal struct \ - in `deriving(Clone)`") + fmt!("unnamed field in normal struct in `deriving(%s)`", + name)) }; build::Field { ident: ident, ex: subcall(self_f) } }; diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs index 7fc2fdc7963..3d93f844ea3 100644 --- a/src/libsyntax/ext/deriving/cmp/eq.rs +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -56,11 +56,3 @@ pub fn expand_deriving_eq(cx: @ext_ctxt, expand_deriving_generic(cx, span, mitem, in_items, &trait_def) } - -pub fn expand_deriving_obsolete(cx: @ext_ctxt, - span: span, - _mitem: @meta_item, - in_items: ~[@item]) -> ~[@item] { - cx.span_err(span, ~"`#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead"); - in_items -} diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 3be65ecd8db..2e2f382a768 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! +The compiler code necessary for #[deriving(Decodable)]. See +encodable.rs for more. +*/ + use ast; use ast::*; use ext::base::ext_ctxt; diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 2078ec9d45c..8a1c3933f51 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -8,6 +8,74 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! + +The compiler code necessary to implement the #[deriving(Encodable)] +(and Decodable, in decodable.rs) extension. The idea here is that +type-defining items may be tagged with #[deriving(Encodable, +Decodable)]. + +For example, a type like: + + #[deriving(Encodable, Decodable)] + struct Node {id: uint} + +would generate two implementations like: + +impl<S:std::serialize::Encoder> Encodable<S> for Node { + fn encode(&self, s: &S) { + do s.emit_struct("Node", 1) { + s.emit_field("id", 0, || s.emit_uint(self.id)) + } + } +} + +impl<D:Decoder> Decodable for node_id { + fn decode(d: &D) -> Node { + do d.read_struct("Node", 1) { + Node { + id: d.read_field(~"x", 0, || decode(d)) + } + } + } +} + +Other interesting scenarios are whe the item has type parameters or +references other non-built-in types. A type definition like: + + #[deriving(Encodable, Decodable)] + struct spanned<T> {node: T, span: span} + +would yield functions like: + + impl< + S: Encoder, + T: Encodable<S> + > spanned<T>: Encodable<S> { + fn encode<S:Encoder>(s: &S) { + do s.emit_rec { + s.emit_field("node", 0, || self.node.encode(s)); + s.emit_field("span", 1, || self.span.encode(s)); + } + } + } + + impl< + D: Decoder, + T: Decodable<D> + > spanned<T>: Decodable<D> { + fn decode(d: &D) -> spanned<T> { + do d.read_rec { + { + node: d.read_field(~"node", 0, || decode(d)), + span: d.read_field(~"span", 1, || decode(d)), + } + } + } + } +*/ + + use ast; use ast::*; use ext::base::ext_ctxt; @@ -403,3 +471,247 @@ fn expand_deriving_encodable_enum_method( // Create the method. create_encode_method(cx, span, ~[stmt]) } + +#[cfg(test)] +mod test { + extern mod std; + use core::option::{None, Some}; + use std::serialize::Encodable; + use std::serialize::Encoder; + + // just adding the ones I want to test, for now: + #[deriving(Eq)] + pub enum call { + CallToEmitEnum(~str), + CallToEmitEnumVariant(~str, uint, uint), + CallToEmitEnumVariantArg(uint), + CallToEmitUint(uint), + CallToEmitNil, + CallToEmitStruct(~str,uint), + CallToEmitField(~str,uint), + CallToEmitOption, + CallToEmitOptionNone, + CallToEmitOptionSome, + // all of the ones I was too lazy to handle: + CallToOther + } + // using `@mut` rather than changing the + // type of self in every method of every encoder everywhere. + pub struct TestEncoder {call_log : @mut ~[call]} + + pub impl TestEncoder { + // these self's should be &mut self's, as well.... + fn add_to_log (&self, c : call) { + self.call_log.push(copy c); + } + fn add_unknown_to_log (&self) { + self.add_to_log (CallToOther) + } + } + + impl Encoder for TestEncoder { + fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) } + + fn emit_uint(&mut self, v: uint) { + self.add_to_log(CallToEmitUint(v)); + } + fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); } + fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); } + fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); } + fn emit_u8(&mut self, _v: u8) { self.add_unknown_to_log(); } + + fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); } + fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); } + fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); } + fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); } + fn emit_i8(&mut self, _v: i8) { self.add_unknown_to_log(); } + + fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); } + + fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); } + fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); } + fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); } + + fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); } + fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); } + + fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnum(name.to_str())); + f(self); + } + + fn emit_enum_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt)); + f(self); + } + + fn emit_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnumVariantArg(idx)); + f(self); + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut TestEncoder)) { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _name: &str, + idx: uint, + f: &fn(&mut TestEncoder)) { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, + name: &str, + len: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitStruct (name.to_str(),len)); + f(self); + } + fn emit_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitField (name.to_str(),idx)); + f(self); + } + + fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + + fn emit_tuple_struct(&mut self, + _name: &str, + _len: uint, + f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + + fn emit_tuple_struct_arg(&mut self, + _idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + + fn emit_option(&mut self, f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitOption); + f(self); + } + fn emit_option_none(&mut self) { + self.add_to_log(CallToEmitOptionNone); + } + fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitOptionSome); + f(self); + } + + fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + + fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); + } + } + + + fn to_call_log<E:Encodable<TestEncoder>>(val: E) -> ~[call] { + let mut te = TestEncoder { + call_log: @mut ~[] + }; + val.encode(&mut te); + copy *te.call_log + } + + #[deriving(Encodable)] + enum Written { + Book(uint,uint), + Magazine(~str) + } + + #[test] + fn test_encode_enum() { + assert_eq!( + to_call_log(Book(34,44)), + ~[ + CallToEmitEnum(~"Written"), + CallToEmitEnumVariant(~"Book",0,2), + CallToEmitEnumVariantArg(0), + CallToEmitUint(34), + CallToEmitEnumVariantArg(1), + CallToEmitUint(44), + ] + ); + } + + pub struct BPos(uint); + + #[deriving(Encodable)] + pub struct HasPos { pos : BPos } + + #[test] + fn test_encode_newtype() { + assert_eq!( + to_call_log(HasPos { pos:BPos(48) }), + ~[ + CallToEmitStruct(~"HasPos",1), + CallToEmitField(~"pos",0), + CallToEmitUint(48), + ] + ); + } + + #[test] + fn test_encode_option() { + let mut v = None; + + assert_eq!( + to_call_log(v), + ~[ + CallToEmitOption, + CallToEmitOptionNone, + ] + ); + + v = Some(54u); + assert_eq!( + to_call_log(v), + ~[ + CallToEmitOption, + CallToEmitOptionSome, + CallToEmitUint(54) + ] + ); + } +} diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index 27e3a54add5..1c9ec6ece2e 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -41,16 +41,6 @@ pub fn expand_deriving_iter_bytes(cx: @ext_ctxt, expand_deriving_generic(cx, span, mitem, in_items, &trait_def) } -pub fn expand_deriving_obsolete(cx: @ext_ctxt, - span: span, - _mitem: @meta_item, - in_items: ~[@item]) - -> ~[@item] { - cx.span_err(span, ~"`#[deriving_iter_bytes]` is obsolete; use `#[deriving(IterBytes)]` \ - instead"); - in_items -} - fn iter_bytes_substructure(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { let lsb0_f = match substr.nonself_args { [l, f] => ~[l, f], diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index ba1f4e3ebb2..78cd5cdb423 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -8,8 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/// The compiler code necessary to implement the #[deriving(Eq)] and -/// #[deriving(IterBytes)] extensions. +/*! +The compiler code necessary to implement the #[deriving] extensions. + + +FIXME (#2810)--Hygiene. Search for "__" strings (in other files too). +We also assume "std" is the standard library, and "core" is the core +library. + +*/ use ast; use ast::{Ty, enum_def, expr, ident, item, Generics, meta_item, struct_def}; @@ -77,6 +84,7 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, titem, in_items))); match *tname { ~"Clone" => expand!(clone::expand_deriving_clone), + ~"DeepClone" => expand!(clone::expand_deriving_deep_clone), ~"IterBytes" => expand!(iter_bytes::expand_deriving_iter_bytes), @@ -203,8 +211,6 @@ pub fn create_derived_impl(cx: @ext_ctxt, * * where B1, B2, ... are the bounds given by `bounds_paths`. * - * FIXME(#5090): Remove code duplication between this and the - * code in auto_encode.rs */ // Copy the lifetimes diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index f4227cd2f2c..fc673c4422f 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -41,7 +41,6 @@ pub mod rt { pub use parse::new_parser_from_tts; pub use codemap::{BytePos, span, dummy_spanned}; - use print::pprust; use print::pprust::{item_to_str, ty_to_str}; pub trait ToTokens { @@ -678,10 +677,11 @@ fn expand_tts(cx: @ext_ctxt, // We want to emit a block expression that does a sequence of 'use's to // import the runtime module, followed by a tt-building expression. - let uses = ~[ build::mk_glob_use(cx, sp, ids_ext(cx, ~[~"syntax", - ~"ext", - ~"quote", - ~"rt"])) ]; + let uses = ~[ build::mk_glob_use(cx, sp, ast::public, + ids_ext(cx, ~[~"syntax", + ~"ext", + ~"quote", + ~"rt"])) ]; // We also bind a single value, sp, to ext_cx.call_site() // diff --git a/src/libsyntax/ext/trace_macros.rs b/src/libsyntax/ext/trace_macros.rs index 9660afb1bc0..1bb40808142 100644 --- a/src/libsyntax/ext/trace_macros.rs +++ b/src/libsyntax/ext/trace_macros.rs @@ -34,9 +34,9 @@ pub fn expand_trace_macros(cx: @ext_ctxt, rdr.dup() ); - if rust_parser.is_keyword(&~"true") { + if rust_parser.is_keyword("true") { cx.set_trace_macros(true); - } else if rust_parser.is_keyword(&~"false") { + } else if rust_parser.is_keyword("false") { cx.set_trace_macros(false); } else { cx.span_fatal(sp, ~"trace_macros! only accepts `true` or `false`") diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index f6dbbbf420d..275a7b963a4 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -589,6 +589,7 @@ pub fn noop_fold_ty(t: &ty_, fld: @ast_fold) -> ty_ { purity: f.purity, region: f.region, onceness: f.onceness, + bounds: f.bounds.map(|x| fold_ty_param_bound(x, fld)), decl: fold_fn_decl(&f.decl, fld), lifetimes: copy f.lifetimes, }) diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index a98e93eec84..fb3622396c9 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -20,8 +20,7 @@ use core::prelude::*; use core::old_iter; use core::old_iter::BaseIter; -#[auto_encode] -#[auto_decode] +#[deriving(Encodable, Decodable)] pub enum OptVec<T> { Empty, Vec(~[T]) diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 322f294836b..6595343654f 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -137,27 +137,27 @@ pub impl Parser { // A sanity check that the word we are asking for is a known keyword // NOTE: this could be done statically.... - fn require_keyword(&self, word: &~str) { - if !self.keywords.contains(word) { - self.bug(fmt!("unknown keyword: %s", *word)); + fn require_keyword(&self, word: &str) { + if !self.keywords.contains_equiv(&word) { + self.bug(fmt!("unknown keyword: %s", word)); } } // return true when this token represents the given string, and is not // followed immediately by :: . - fn token_is_word(&self, word: &~str, tok: &token::Token) -> bool { + fn token_is_word(&self, word: &str, tok: &token::Token) -> bool { match *tok { - token::IDENT(sid, false) => { *self.id_to_str(sid) == *word } + token::IDENT(sid, false) => { word == *self.id_to_str(sid) } _ => { false } } } - fn token_is_keyword(&self, word: &~str, tok: &token::Token) -> bool { + fn token_is_keyword(&self, word: &str, tok: &token::Token) -> bool { self.require_keyword(word); self.token_is_word(word, tok) } - fn is_keyword(&self, word: &~str) -> bool { + fn is_keyword(&self, word: &str) -> bool { self.token_is_keyword(word, © *self.token) } @@ -177,10 +177,10 @@ pub impl Parser { // if the given word is not a keyword, signal an error. // if the next token is the given keyword, eat it and return // true. Otherwise, return false. - fn eat_keyword(&self, word: &~str) -> bool { + fn eat_keyword(&self, word: &str) -> bool { self.require_keyword(word); let is_kw = match *self.token { - token::IDENT(sid, false) => *word == *self.id_to_str(sid), + token::IDENT(sid, false) => word == *self.id_to_str(sid), _ => false }; if is_kw { self.bump() } @@ -190,13 +190,13 @@ pub impl Parser { // if the given word is not a keyword, signal an error. // if the next token is not the given word, signal an error. // otherwise, eat it. - fn expect_keyword(&self, word: &~str) { + fn expect_keyword(&self, word: &str) { self.require_keyword(word); if !self.eat_keyword(word) { self.fatal( fmt!( "expected `%s`, found `%s`", - *word, + word, self.this_token_to_str() ) ); @@ -204,8 +204,8 @@ pub impl Parser { } // return true if the given string is a strict keyword - fn is_strict_keyword(&self, word: &~str) -> bool { - self.strict_keywords.contains(word) + fn is_strict_keyword(&self, word: &str) -> bool { + self.strict_keywords.contains_equiv(&word) } // signal an error if the current token is a strict keyword @@ -213,23 +213,23 @@ pub impl Parser { match *self.token { token::IDENT(_, false) => { let w = token_to_str(self.reader, © *self.token); - self.check_strict_keywords_(&w); + self.check_strict_keywords_(w); } _ => () } } // signal an error if the given string is a strict keyword - fn check_strict_keywords_(&self, w: &~str) { + fn check_strict_keywords_(&self, w: &str) { if self.is_strict_keyword(w) { self.span_err(*self.last_span, - fmt!("found `%s` in ident position", *w)); + fmt!("found `%s` in ident position", w)); } } // return true if this is a reserved keyword - fn is_reserved_keyword(&self, word: &~str) -> bool { - self.reserved_keywords.contains(word) + fn is_reserved_keyword(&self, word: &str) -> bool { + self.reserved_keywords.contains_equiv(&word) } // signal an error if the current token is a reserved keyword @@ -237,16 +237,16 @@ pub impl Parser { match *self.token { token::IDENT(_, false) => { let w = token_to_str(self.reader, © *self.token); - self.check_reserved_keywords_(&w); + self.check_reserved_keywords_(w); } _ => () } } // signal an error if the given string is a reserved keyword - fn check_reserved_keywords_(&self, w: &~str) { + fn check_reserved_keywords_(&self, w: &str) { if self.is_reserved_keyword(w) { - self.fatal(fmt!("`%s` is a reserved keyword", *w)); + self.fatal(fmt!("`%s` is a reserved keyword", w)); } } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index 211d123e887..859fde90e29 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -302,9 +302,9 @@ pub impl Parser { } fn try_parse_obsolete_priv_section(&self, attrs: &[attribute]) -> bool { - if self.is_keyword(&~"priv") && self.look_ahead(1) == token::LBRACE { + if self.is_keyword("priv") && self.look_ahead(1) == token::LBRACE { self.obsolete(copy *self.span, ObsoletePrivSection); - self.eat_keyword(&~"priv"); + self.eat_keyword("priv"); self.bump(); while *self.token != token::RBRACE { self.parse_single_struct_field(ast::private, attrs.to_owned()); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b76098858cb..25b45a5f3b5 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -338,10 +338,10 @@ pub impl Parser { // is this one of the keywords that signals a closure type? fn token_is_closure_keyword(&self, tok: &token::Token) -> bool { - self.token_is_keyword(&~"pure", tok) || - self.token_is_keyword(&~"unsafe", tok) || - self.token_is_keyword(&~"once", tok) || - self.token_is_keyword(&~"fn", tok) + self.token_is_keyword("pure", tok) || + self.token_is_keyword("unsafe", tok) || + self.token_is_keyword("once", tok) || + self.token_is_keyword("fn", tok) } fn token_is_lifetime(&self, tok: &token::Token) -> bool { @@ -378,7 +378,7 @@ pub impl Parser { let opt_abis = self.parse_opt_abis(); let abis = opt_abis.get_or_default(AbiSet::Rust()); let purity = self.parse_unsafety(); - self.expect_keyword(&~"fn"); + self.expect_keyword("fn"); let (decl, lifetimes) = self.parse_ty_fn_decl(); return ty_bare_fn(@TyBareFn { abis: abis, @@ -395,12 +395,13 @@ pub impl Parser { -> ty_ { /* - (&|~|@) ['r] [pure|unsafe] [once] fn <'lt> (S) -> T - ^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~^ ^~^ ^ - | | | | | | | - | | | | | | Return type - | | | | | Argument types - | | | | Lifetimes + (&|~|@) ['r] [pure|unsafe] [once] fn [:Bounds] <'lt> (S) -> T + ^~~~~~^ ^~~^ ^~~~~~~~~~~~^ ^~~~~^ ^~~~~~~~^ ^~~~^ ^~^ ^ + | | | | | | | | + | | | | | | | Return type + | | | | | | Argument types + | | | | | Lifetimes + | | | | Closure bounds | | | Once-ness (a.k.a., affine) | | Purity | Lifetime bound @@ -413,7 +414,8 @@ pub impl Parser { let purity = self.parse_unsafety(); let onceness = parse_onceness(self); - self.expect_keyword(&~"fn"); + self.expect_keyword("fn"); + let bounds = self.parse_optional_ty_param_bounds(); if self.parse_fn_ty_sigil().is_some() { self.obsolete(*self.span, ObsoletePostFnTySigil); @@ -426,12 +428,13 @@ pub impl Parser { region: region, purity: purity, onceness: onceness, + bounds: bounds, decl: decl, lifetimes: lifetimes, }); fn parse_onceness(this: &Parser) -> Onceness { - if this.eat_keyword(&~"once") { + if this.eat_keyword(~"once") { Once } else { Many @@ -441,10 +444,10 @@ pub impl Parser { // looks like this should be called parse_unsafety fn parse_unsafety(&self) -> purity { - if self.eat_keyword(&~"pure") { + if self.eat_keyword("pure") { self.obsolete(*self.last_span, ObsoletePurity); return impure_fn; - } else if self.eat_keyword(&~"unsafe") { + } else if self.eat_keyword("unsafe") { return unsafe_fn; } else { return impure_fn; @@ -699,7 +702,7 @@ pub impl Parser { // BORROWED POINTER self.bump(); self.parse_borrowed_pointee() - } else if self.eat_keyword(&~"extern") { + } else if self.eat_keyword("extern") { // EXTERN FUNCTION self.parse_ty_bare_fn() } else if self.token_is_closure_keyword(© *self.token) { @@ -823,7 +826,7 @@ pub impl Parser { let mut is_mutbl = false; let pat = if require_name || self.is_named_argument() { self.parse_arg_mode(); - is_mutbl = self.eat_keyword(&~"mut"); + is_mutbl = self.eat_keyword("mut"); let pat = self.parse_pat(false); self.expect(&token::COLON); pat @@ -851,7 +854,7 @@ pub impl Parser { // parse an argument in a lambda header e.g. |arg, arg| fn parse_fn_block_arg(&self) -> arg_or_capture_item { self.parse_arg_mode(); - let is_mutbl = self.eat_keyword(&~"mut"); + let is_mutbl = self.eat_keyword("mut"); let pat = self.parse_pat(false); let t = if self.eat(&token::COLON) { self.parse_ty(false) @@ -902,9 +905,9 @@ pub impl Parser { // matches lit = true | false | token_lit fn parse_lit(&self) -> lit { let lo = self.span.lo; - let lit = if self.eat_keyword(&~"true") { + let lit = if self.eat_keyword("true") { lit_bool(true) - } else if self.eat_keyword(&~"false") { + } else if self.eat_keyword("false") { lit_bool(false) } else { // XXX: This is a really bad copy! @@ -1140,15 +1143,15 @@ pub impl Parser { } fn token_is_mutability(&self, tok: &token::Token) -> bool { - self.token_is_keyword(&~"mut", tok) || - self.token_is_keyword(&~"const", tok) + self.token_is_keyword("mut", tok) || + self.token_is_keyword("const", tok) } // parse mutability declaration (mut/const/imm) fn parse_mutability(&self) -> mutability { - if self.eat_keyword(&~"mut") { + if self.eat_keyword("mut") { m_mutbl - } else if self.eat_keyword(&~"const") { + } else if self.eat_keyword("const") { m_const } else { m_imm @@ -1246,30 +1249,30 @@ pub impl Parser { expr_block(blk)); } else if token::is_bar(&*self.token) { return self.parse_lambda_expr(); - } else if self.eat_keyword(&~"self") { + } else if self.eat_keyword("self") { ex = expr_self; hi = self.span.hi; - } else if self.eat_keyword(&~"if") { + } else if self.eat_keyword("if") { return self.parse_if_expr(); - } else if self.eat_keyword(&~"for") { + } else if self.eat_keyword("for") { return self.parse_sugary_call_expr(~"for", ForSugar, expr_loop_body); - } else if self.eat_keyword(&~"do") { + } else if self.eat_keyword("do") { return self.parse_sugary_call_expr(~"do", DoSugar, expr_do_body); - } else if self.eat_keyword(&~"while") { + } else if self.eat_keyword("while") { return self.parse_while_expr(); } else if self.token_is_lifetime(&*self.token) { let lifetime = self.get_lifetime(&*self.token); self.bump(); self.expect(&token::COLON); - self.expect_keyword(&~"loop"); + self.expect_keyword("loop"); return self.parse_loop_expr(Some(lifetime)); - } else if self.eat_keyword(&~"loop") { + } else if self.eat_keyword("loop") { return self.parse_loop_expr(None); - } else if self.eat_keyword(&~"match") { + } else if self.eat_keyword("match") { return self.parse_match_expr(); - } else if self.eat_keyword(&~"unsafe") { + } else if self.eat_keyword("unsafe") { return self.parse_block_expr(lo, unsafe_blk); } else if *self.token == token::LBRACKET { self.bump(); @@ -1309,7 +1312,7 @@ pub impl Parser { } } hi = self.span.hi; - } else if self.eat_keyword(&~"__log") { + } else if self.eat_keyword("__log") { // LOG expression self.expect(&token::LPAREN); let lvl = self.parse_expr(); @@ -1318,14 +1321,14 @@ pub impl Parser { ex = expr_log(lvl, e); hi = self.span.hi; self.expect(&token::RPAREN); - } else if self.eat_keyword(&~"return") { + } else if self.eat_keyword("return") { // RETURN expression if can_begin_expr(&*self.token) { let e = self.parse_expr(); hi = e.span.hi; ex = expr_ret(Some(e)); } else { ex = expr_ret(None); } - } else if self.eat_keyword(&~"break") { + } else if self.eat_keyword("break") { // BREAK expression if self.token_is_lifetime(&*self.token) { let lifetime = self.get_lifetime(&*self.token); @@ -1335,14 +1338,14 @@ pub impl Parser { ex = expr_break(None); } hi = self.span.hi; - } else if self.eat_keyword(&~"copy") { + } else if self.eat_keyword("copy") { // COPY expression let e = self.parse_expr(); ex = expr_copy(e); hi = e.span.hi; } else if *self.token == token::MOD_SEP || - is_ident(&*self.token) && !self.is_keyword(&~"true") && - !self.is_keyword(&~"false") { + is_ident(&*self.token) && !self.is_keyword("true") && + !self.is_keyword("false") { let pth = self.parse_path_with_tps(true); // `!`, as an operator, is prefix, so we know this isn't that @@ -1822,7 +1825,7 @@ pub impl Parser { } } None => { - if as_prec > min_prec && self.eat_keyword(&~"as") { + if as_prec > min_prec && self.eat_keyword("as") { let rhs = self.parse_ty(true); let _as = self.mk_expr(lhs.span.lo, rhs.span.hi, @@ -1896,7 +1899,7 @@ pub impl Parser { let thn = self.parse_block(); let mut els: Option<@expr> = None; let mut hi = thn.span.hi; - if self.eat_keyword(&~"else") { + if self.eat_keyword("else") { let elexpr = self.parse_else_expr(); els = Some(elexpr); hi = elexpr.span.hi; @@ -1963,7 +1966,7 @@ pub impl Parser { } fn parse_else_expr(&self) -> @expr { - if self.eat_keyword(&~"if") { + if self.eat_keyword("if") { return self.parse_if_expr(); } else { let blk = self.parse_block(); @@ -2077,7 +2080,7 @@ pub impl Parser { fn looking_at_record_literal(&self) -> bool { let lookahead = self.look_ahead(1); *self.token == token::LBRACE && - (self.token_is_keyword(&~"mut", &lookahead) || + (self.token_is_keyword("mut", &lookahead) || (is_plain_ident(&lookahead) && self.look_ahead(2) == token::COLON)) } @@ -2090,7 +2093,7 @@ pub impl Parser { while *self.token != token::RBRACE { let pats = self.parse_pats(); let mut guard = None; - if self.eat_keyword(&~"if") { guard = Some(self.parse_expr()); } + if self.eat_keyword("if") { guard = Some(self.parse_expr()); } self.expect(&token::FAT_ARROW); let expr = self.parse_expr_res(RESTRICT_STMT_EXPR); @@ -2379,8 +2382,8 @@ pub impl Parser { } ref tok => { if !is_ident_or_path(tok) - || self.is_keyword(&~"true") - || self.is_keyword(&~"false") + || self.is_keyword("true") + || self.is_keyword("false") { // Parse an expression pattern or exp .. exp. // @@ -2399,11 +2402,11 @@ pub impl Parser { } else { pat = pat_lit(val); } - } else if self.eat_keyword(&~"ref") { + } else if self.eat_keyword("ref") { // parse ref pat let mutbl = self.parse_mutability(); pat = self.parse_pat_ident(refutable, bind_by_ref(mutbl)); - } else if self.eat_keyword(&~"copy") { + } else if self.eat_keyword("copy") { // parse copy pat pat = self.parse_pat_ident(refutable, bind_by_copy); } else { @@ -2552,7 +2555,7 @@ pub impl Parser { // parse a "let" stmt fn parse_let(&self) -> @decl { - let is_mutbl = self.eat_keyword(&~"mut"); + let is_mutbl = self.eat_keyword("mut"); let lo = self.span.lo; let mut locals = ~[self.parse_local(is_mutbl)]; while self.eat(&token::COMMA) { @@ -2566,7 +2569,7 @@ pub impl Parser { pr: visibility, attrs: ~[attribute]) -> @struct_field { let lo = self.span.lo; - if self.eat_keyword(&~"mut") { + if self.eat_keyword("mut") { // Do nothing, for backwards compatibility. // XXX: Remove after snapshot. } @@ -2596,9 +2599,9 @@ pub impl Parser { } let lo = self.span.lo; - if self.is_keyword(&~"let") { + if self.is_keyword("let") { check_expected_item(self, first_item_attrs); - self.expect_keyword(&~"let"); + self.expect_keyword("let"); let decl = self.parse_let(); return @spanned(lo, decl.span.hi, stmt_decl(decl, self.get_id())); } else if is_ident(&*self.token) @@ -2685,7 +2688,7 @@ pub impl Parser { maybe_whole!(self, nt_block); let lo = self.span.lo; - if self.eat_keyword(&~"unsafe") { + if self.eat_keyword("unsafe") { self.obsolete(copy *self.span, ObsoleteUnsafeBlock); } self.expect(&token::LBRACE); @@ -2700,7 +2703,7 @@ pub impl Parser { maybe_whole!(pair_empty self, nt_block); let lo = self.span.lo; - if self.eat_keyword(&~"unsafe") { + if self.eat_keyword("unsafe") { self.obsolete(copy *self.span, ObsoleteUnsafeBlock); } self.expect(&token::LBRACE); @@ -2834,10 +2837,10 @@ pub impl Parser { } fn parse_optional_purity(&self) -> ast::purity { - if self.eat_keyword(&~"pure") { + if self.eat_keyword("pure") { self.obsolete(*self.last_span, ObsoletePurity); ast::impure_fn - } else if self.eat_keyword(&~"unsafe") { + } else if self.eat_keyword("unsafe") { ast::unsafe_fn } else { ast::impure_fn @@ -2845,15 +2848,15 @@ pub impl Parser { } fn parse_optional_onceness(&self) -> ast::Onceness { - if self.eat_keyword(&~"once") { ast::Once } else { ast::Many } + if self.eat_keyword("once") { ast::Once } else { ast::Many } } // matches optbounds = ( ( : ( boundseq )? )? ) // where boundseq = ( bound + boundseq ) | bound // and bound = 'static | ty - fn parse_optional_ty_param_bounds(&self) -> @OptVec<TyParamBound> { + fn parse_optional_ty_param_bounds(&self) -> OptVec<TyParamBound> { if !self.eat(&token::COLON) { - return @opt_vec::Empty; + return opt_vec::Empty; } let mut result = opt_vec::Empty; @@ -2907,13 +2910,13 @@ pub impl Parser { } } - return @result; + return result; } // matches typaram = IDENT optbounds fn parse_ty_param(&self) -> TyParam { let ident = self.parse_ident(); - let bounds = self.parse_optional_ty_param_bounds(); + let bounds = @self.parse_optional_ty_param_bounds(); ast::TyParam { ident: ident, id: self.get_id(), bounds: bounds } } @@ -3008,10 +3011,10 @@ pub impl Parser { p: &Parser ) -> ast::explicit_self_ { // We need to make sure it isn't a mode or a type - if p.token_is_keyword(&~"self", &p.look_ahead(1)) || - ((p.token_is_keyword(&~"const", &p.look_ahead(1)) || - p.token_is_keyword(&~"mut", &p.look_ahead(1))) && - p.token_is_keyword(&~"self", &p.look_ahead(2))) { + if p.token_is_keyword("self", &p.look_ahead(1)) || + ((p.token_is_keyword("const", &p.look_ahead(1)) || + p.token_is_keyword("mut", &p.look_ahead(1))) && + p.token_is_keyword("self", &p.look_ahead(2))) { p.bump(); let mutability = p.parse_mutability(); @@ -3032,25 +3035,25 @@ pub impl Parser { // // We already know that the current token is `&`. - if (this.token_is_keyword(&~"self", &this.look_ahead(1))) { + if (this.token_is_keyword("self", &this.look_ahead(1))) { this.bump(); this.expect_self_ident(); sty_region(None, m_imm) } else if (this.token_is_mutability(&this.look_ahead(1)) && - this.token_is_keyword(&~"self", &this.look_ahead(2))) { + this.token_is_keyword("self", &this.look_ahead(2))) { this.bump(); let mutability = this.parse_mutability(); this.expect_self_ident(); sty_region(None, mutability) } else if (this.token_is_lifetime(&this.look_ahead(1)) && - this.token_is_keyword(&~"self", &this.look_ahead(2))) { + this.token_is_keyword("self", &this.look_ahead(2))) { this.bump(); let lifetime = @this.parse_lifetime(); this.expect_self_ident(); sty_region(Some(lifetime), m_imm) } else if (this.token_is_lifetime(&this.look_ahead(1)) && this.token_is_mutability(&this.look_ahead(2)) && - this.token_is_keyword(&~"self", &this.look_ahead(3))) { + this.token_is_keyword("self", &this.look_ahead(3))) { this.bump(); let lifetime = @this.parse_lifetime(); let mutability = this.parse_mutability(); @@ -3259,7 +3262,7 @@ pub impl Parser { let mut ty = self.parse_ty(false); // Parse traits, if necessary. - let opt_trait = if could_be_trait && self.eat_keyword(&~"for") { + let opt_trait = if could_be_trait && self.eat_keyword("for") { // New-style trait. Reinterpret the type as a trait. let opt_trait_ref = match ty.node { ty_path(path, node_id) => { @@ -3434,11 +3437,11 @@ pub impl Parser { return ~[]; } - if self.eat_keyword(&~"priv") { + if self.eat_keyword("priv") { return ~[self.parse_single_struct_field(private, attrs)] } - if self.eat_keyword(&~"pub") { + if self.eat_keyword("pub") { return ~[self.parse_single_struct_field(public, attrs)]; } @@ -3451,13 +3454,13 @@ pub impl Parser { // parse visiility: PUB, PRIV, or nothing fn parse_visibility(&self) -> visibility { - if self.eat_keyword(&~"pub") { public } - else if self.eat_keyword(&~"priv") { private } + if self.eat_keyword("pub") { public } + else if self.eat_keyword("priv") { private } else { inherited } } fn parse_staticness(&self) -> bool { - if self.eat_keyword(&~"static") { + if self.eat_keyword("static") { self.obsolete(*self.last_span, ObsoleteStaticMethod); true } else { @@ -3677,10 +3680,10 @@ pub impl Parser { let lo = self.span.lo; // XXX: Obsolete; remove after snap. - if self.eat_keyword(&~"const") { + if self.eat_keyword("const") { self.obsolete(*self.last_span, ObsoleteConstItem); } else { - self.expect_keyword(&~"static"); + self.expect_keyword("static"); } let ident = self.parse_ident(); @@ -3698,14 +3701,14 @@ pub impl Parser { // parse safe/unsafe and fn fn parse_fn_purity(&self) -> purity { - if self.eat_keyword(&~"fn") { impure_fn } - else if self.eat_keyword(&~"pure") { + if self.eat_keyword("fn") { impure_fn } + else if self.eat_keyword("pure") { self.obsolete(*self.last_span, ObsoletePurity); - self.expect_keyword(&~"fn"); + self.expect_keyword("fn"); // NB: We parse this as impure for bootstrapping purposes. impure_fn - } else if self.eat_keyword(&~"unsafe") { - self.expect_keyword(&~"fn"); + } else if self.eat_keyword("unsafe") { + self.expect_keyword("fn"); unsafe_fn } else { self.unexpected(); } @@ -3743,9 +3746,9 @@ pub impl Parser { items_allowed: bool) -> item_or_view_item { let mut must_be_named_mod = false; - if self.is_keyword(&~"mod") { + if self.is_keyword("mod") { must_be_named_mod = true; - self.expect_keyword(&~"mod"); + self.expect_keyword("mod"); } else if *self.token != token::LBRACE { self.span_fatal( copy *self.span, @@ -4030,7 +4033,7 @@ pub impl Parser { let visibility = self.parse_visibility(); // must be a view item: - if self.eat_keyword(&~"use") { + if self.eat_keyword("use") { // USE ITEM (iovi_view_item) let view_item = self.parse_use(); self.expect(&token::SEMI); @@ -4042,10 +4045,10 @@ pub impl Parser { }); } // either a view item or an item: - if self.eat_keyword(&~"extern") { + if self.eat_keyword("extern") { let opt_abis = self.parse_opt_abis(); - if self.eat_keyword(&~"fn") { + if self.eat_keyword("fn") { // EXTERN FUNCTION ITEM let abis = opt_abis.get_or_default(AbiSet::C()); let (ident, item_, extra_attrs) = @@ -4061,11 +4064,11 @@ pub impl Parser { } } // the rest are all guaranteed to be items: - if (self.is_keyword(&~"const") || - (self.is_keyword(&~"static") && - !self.token_is_keyword(&~"fn", &self.look_ahead(1)))) { + if (self.is_keyword("const") || + (self.is_keyword("static") && + !self.token_is_keyword("fn", &self.look_ahead(1)))) { // CONST / STATIC ITEM - if self.is_keyword(&~"const") { + if self.is_keyword("const") { self.obsolete(*self.span, ObsoleteConstItem); } self.bump(); @@ -4074,7 +4077,7 @@ pub impl Parser { visibility, maybe_append(attrs, extra_attrs))); } - if self.is_keyword(&~"fn") && + if self.is_keyword("fn") && !self.fn_expr_lookahead(self.look_ahead(1u)) { // FUNCTION ITEM self.bump(); @@ -4084,28 +4087,28 @@ pub impl Parser { visibility, maybe_append(attrs, extra_attrs))); } - if self.eat_keyword(&~"pure") { + if self.eat_keyword("pure") { // PURE FUNCTION ITEM (obsolete) self.obsolete(*self.last_span, ObsoletePurity); - self.expect_keyword(&~"fn"); + self.expect_keyword("fn"); let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn, AbiSet::Rust()); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } - if self.is_keyword(&~"unsafe") + if self.is_keyword("unsafe") && self.look_ahead(1u) != token::LBRACE { // UNSAFE FUNCTION ITEM self.bump(); - self.expect_keyword(&~"fn"); + self.expect_keyword("fn"); let (ident, item_, extra_attrs) = self.parse_item_fn(unsafe_fn, AbiSet::Rust()); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } - if self.eat_keyword(&~"mod") { + if self.eat_keyword("mod") { // MODULE ITEM let (ident, item_, extra_attrs) = self.parse_item_mod(/*bad*/ copy attrs); @@ -4113,28 +4116,28 @@ pub impl Parser { visibility, maybe_append(attrs, extra_attrs))); } - if self.eat_keyword(&~"type") { + if self.eat_keyword("type") { // TYPE ITEM let (ident, item_, extra_attrs) = self.parse_item_type(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } - if self.eat_keyword(&~"enum") { + if self.eat_keyword("enum") { // ENUM ITEM let (ident, item_, extra_attrs) = self.parse_item_enum(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } - if self.eat_keyword(&~"trait") { + if self.eat_keyword("trait") { // TRAIT ITEM let (ident, item_, extra_attrs) = self.parse_item_trait(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); } - if self.eat_keyword(&~"impl") { + if self.eat_keyword("impl") { // IMPL ITEM let (ident, item_, extra_attrs) = self.parse_item_impl(visibility); @@ -4142,7 +4145,7 @@ pub impl Parser { visibility, maybe_append(attrs, extra_attrs))); } - if self.eat_keyword(&~"struct") { + if self.eat_keyword("struct") { // STRUCT ITEM let (ident, item_, extra_attrs) = self.parse_item_struct(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, @@ -4163,13 +4166,13 @@ pub impl Parser { let visibility = self.parse_visibility(); - if (self.is_keyword(&~"const") || self.is_keyword(&~"static")) { + if (self.is_keyword("const") || self.is_keyword("static")) { // FOREIGN CONST ITEM let item = self.parse_item_foreign_const(visibility, attrs); return iovi_foreign_item(item); } - if (self.is_keyword(&~"fn") || self.is_keyword(&~"pure") || - self.is_keyword(&~"unsafe")) { + if (self.is_keyword("fn") || self.is_keyword("pure") || + self.is_keyword("unsafe")) { // FOREIGN FUNCTION ITEM let item = self.parse_item_foreign_fn(attrs); return iovi_foreign_item(item); @@ -4360,16 +4363,16 @@ pub impl Parser { fn is_view_item(&self) -> bool { let tok, next_tok; - if !self.is_keyword(&~"pub") && !self.is_keyword(&~"priv") { + if !self.is_keyword("pub") && !self.is_keyword("priv") { tok = copy *self.token; next_tok = self.look_ahead(1); } else { tok = self.look_ahead(1); next_tok = self.look_ahead(2); }; - self.token_is_keyword(&~"use", &tok) - || (self.token_is_keyword(&~"extern", &tok) && - self.token_is_keyword(&~"mod", &next_tok)) + self.token_is_keyword("use", &tok) + || (self.token_is_keyword("extern", &tok) && + self.token_is_keyword("mod", &next_tok)) } // parse a view item. @@ -4379,10 +4382,10 @@ pub impl Parser { vis: visibility ) -> @view_item { let lo = self.span.lo; - let node = if self.eat_keyword(&~"use") { + let node = if self.eat_keyword("use") { self.parse_use() - } else if self.eat_keyword(&~"extern") { - self.expect_keyword(&~"mod"); + } else if self.eat_keyword("extern") { + self.expect_keyword("mod"); let ident = self.parse_ident(); let metadata = self.parse_optional_meta(); view_item_extern_mod(ident, metadata, self.get_id()) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fe479ab81f7..36f241b6427 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -18,9 +18,7 @@ use core::cmp::Equiv; use core::hashmap::HashSet; use core::to_bytes; -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Encodable, Decodable, Eq)] pub enum binop { PLUS, MINUS, @@ -34,9 +32,7 @@ pub enum binop { SHR, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Encodable, Decodable, Eq)] pub enum Token { /* Expression-operator symbols. */ EQ, @@ -97,9 +93,7 @@ pub enum Token { EOF, } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Encodable, Decodable, Eq)] /// For interpolation during macro expansion. pub enum nonterminal { nt_item(@ast::item), diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 8deca72779e..565a8a18c6f 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -78,6 +78,7 @@ pub mod ext { pub mod fmt; pub mod env; + pub mod bytes; pub mod concat_idents; pub mod log_syntax; pub mod auto_encode; diff --git a/src/libuv b/src/libuv -Subproject 218ab86721eefd7b7e97fa6d9f95a80a1fa8686 +Subproject dfae9c3e958dc086d9c0ab068cd76d196c95a43 diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 8c081858d60..9e44abe081c 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -553,7 +553,7 @@ extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B, li->setVolatile(true); li->setAtomic(order); li->setAlignment(sizeof(intptr_t)); - return wrap(unwrap(B)->Insert(li)); + return wrap(unwrap(B)->Insert(li, Name)); } extern "C" LLVMValueRef LLVMBuildAtomicStore(LLVMBuilderRef B, diff --git a/src/test/compile-fail/borrowck-rvalues-mutable-bad.rs b/src/test/compile-fail/borrowck-rvalues-mutable-bad.rs new file mode 100644 index 00000000000..10bef907a28 --- /dev/null +++ b/src/test/compile-fail/borrowck-rvalues-mutable-bad.rs @@ -0,0 +1,38 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that rvalue lifetimes is limited to the enclosing trans +// cleanup scope. It is unclear that this is the correct lifetime for +// rvalues, but that's what it is right now. + +struct Counter { + value: uint +} + +impl Counter { + fn new(v: uint) -> Counter { + Counter {value: v} + } + + fn inc<'a>(&'a mut self) -> &'a mut Counter { + self.value += 1; + self + } + + fn get(&self) -> uint { + self.value + } +} + +pub fn main() { + let v = Counter::new(22).inc().inc().get(); + //~^ ERROR borrowed value does not live long enough + assert_eq!(v, 24);; +} diff --git a/src/test/compile-fail/closure-bounds-not-builtin.rs b/src/test/compile-fail/closure-bounds-not-builtin.rs new file mode 100644 index 00000000000..a3484cb33dc --- /dev/null +++ b/src/test/compile-fail/closure-bounds-not-builtin.rs @@ -0,0 +1,8 @@ + +trait Foo {} + +fn take(f: &fn:Foo()) { + //~^ ERROR only the builtin traits can be used as closure or object bounds +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/closure-bounds-subtype.rs b/src/test/compile-fail/closure-bounds-subtype.rs new file mode 100644 index 00000000000..ebec113cedc --- /dev/null +++ b/src/test/compile-fail/closure-bounds-subtype.rs @@ -0,0 +1,34 @@ +fn take_any(_: &fn()) { +} + +fn take_copyable(_: &fn:Copy()) { +} + +fn take_copyable_owned(_: &fn:Copy+Owned()) { +} + +fn give_any(f: &fn()) { + take_any(f); + take_copyable(f); //~ ERROR expected bounds `Copy` but found no bounds + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found no bounds +} + +fn give_copyable(f: &fn:Copy()) { + take_any(f); + take_copyable(f); + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Copy` +} + +fn give_owned(f: &fn:Owned()) { + take_any(f); + take_copyable(f); //~ ERROR expected bounds `Copy` but found bounds `Owned` + take_copyable_owned(f); //~ ERROR expected bounds `Copy+Owned` but found bounds `Owned` +} + +fn give_copyable_owned(f: &fn:Copy+Owned()) { + take_any(f); + take_copyable(f); + take_copyable_owned(f); +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/deriving-obsolete.rs b/src/test/compile-fail/deprecated-auto-code.rs index 298dced1e21..1f7cbfe9807 100644 --- a/src/test/compile-fail/deriving-obsolete.rs +++ b/src/test/compile-fail/deprecated-auto-code.rs @@ -8,10 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[deriving_clone] //~ ERROR `#[deriving_clone]` is obsolete; use `#[deriving(Clone)]` instead -#[deriving_eq] //~ ERROR `#[deriving_eq]` is obsolete; use `#[deriving(Eq)]` instead -#[deriving_iter_bytes] -//~^ ERROR `#[deriving_iter_bytes]` is obsolete; use `#[deriving(IterBytes)]` instead -struct Foo; +#[auto_encode] //~ ERROR: `#[auto_encode]` is deprecated +#[auto_decode] //~ ERROR: `#[auto_decode]` is deprecated +struct A; -pub fn main() { } +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/lint-impl-fn.rs b/src/test/compile-fail/lint-impl-fn.rs new file mode 100644 index 00000000000..3cc0495206d --- /dev/null +++ b/src/test/compile-fail/lint-impl-fn.rs @@ -0,0 +1,37 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[allow(while_true)]; + +struct A(int); + +impl A { + fn foo(&self) { while true {} } + + #[deny(while_true)] + fn bar(&self) { while true {} } //~ ERROR: infinite loops +} + +#[deny(while_true)] +mod foo { + struct B(int); + + impl B { + fn foo(&self) { while true {} } //~ ERROR: infinite loops + + #[allow(while_true)] + fn bar(&self) { while true {} } + } +} + +#[deny(while_true)] +fn main() { + while true {} //~ ERROR: infinite loops +} diff --git a/src/test/compile-fail/unused-imports-warn.rs b/src/test/compile-fail/lint-unused-imports.rs index f3b0a1f73f9..f3b0a1f73f9 100644 --- a/src/test/compile-fail/unused-imports-warn.rs +++ b/src/test/compile-fail/lint-unused-imports.rs diff --git a/src/test/compile-fail/unused-mut-variables.rs b/src/test/compile-fail/lint-unused-mut-variables.rs index d1223cd8893..d1223cd8893 100644 --- a/src/test/compile-fail/unused-mut-variables.rs +++ b/src/test/compile-fail/lint-unused-mut-variables.rs diff --git a/src/test/compile-fail/unused-unsafe.rs b/src/test/compile-fail/lint-unused-unsafe.rs index 465e5548f67..465e5548f67 100644 --- a/src/test/compile-fail/unused-unsafe.rs +++ b/src/test/compile-fail/lint-unused-unsafe.rs diff --git a/src/test/compile-fail/liveness-dead.rs b/src/test/compile-fail/liveness-dead.rs index 1d6a7426045..2ab3cb4568a 100644 --- a/src/test/compile-fail/liveness-dead.rs +++ b/src/test/compile-fail/liveness-dead.rs @@ -8,12 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[deny(dead_assignment)]; + fn f1(x: &mut int) { *x = 1; // no error } fn f2() { - let mut x = 3; //~ WARNING value assigned to `x` is never read + let mut x = 3; //~ ERROR: value assigned to `x` is never read x = 4; copy x; } @@ -21,10 +23,7 @@ fn f2() { fn f3() { let mut x = 3; copy x; - x = 4; //~ WARNING value assigned to `x` is never read + x = 4; //~ ERROR: value assigned to `x` is never read } -fn main() { // leave this in here just to trigger compile-fail: - let x: int; - copy x; //~ ERROR use of possibly uninitialized variable: `x` -} +fn main() {} diff --git a/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs b/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs new file mode 100644 index 00000000000..8bdc643f288 --- /dev/null +++ b/src/test/compile-fail/syntax-extension-bytes-non-ascii-char-literal.rs @@ -0,0 +1,13 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let vec = bytes!('λ'); //~ ERROR Non-ascii char literal in bytes! +} diff --git a/src/test/compile-fail/syntax-extension-bytes-non-literal.rs b/src/test/compile-fail/syntax-extension-bytes-non-literal.rs new file mode 100644 index 00000000000..fed6bdc9470 --- /dev/null +++ b/src/test/compile-fail/syntax-extension-bytes-non-literal.rs @@ -0,0 +1,13 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let vec = bytes!(foo); //~ ERROR Non-literal in bytes! +} diff --git a/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs new file mode 100644 index 00000000000..8acb280dfde --- /dev/null +++ b/src/test/compile-fail/syntax-extension-bytes-too-large-integer-literal.rs @@ -0,0 +1,13 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let vec = bytes!(1024); //~ ERROR Too large integer literal in bytes! +} diff --git a/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs new file mode 100644 index 00000000000..b7d69a3054f --- /dev/null +++ b/src/test/compile-fail/syntax-extension-bytes-too-large-u8-literal.rs @@ -0,0 +1,13 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let vec = bytes!(1024u8); //~ ERROR Too large u8 literal in bytes! +} diff --git a/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs new file mode 100644 index 00000000000..cec2dc0a8e0 --- /dev/null +++ b/src/test/compile-fail/syntax-extension-bytes-too-small-integer-literal.rs @@ -0,0 +1,13 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let vec = bytes!(-1024); //~ ERROR Non-literal in bytes +} diff --git a/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs b/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs new file mode 100644 index 00000000000..2df55a6436c --- /dev/null +++ b/src/test/compile-fail/syntax-extension-bytes-too-small-u8-literal.rs @@ -0,0 +1,13 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let vec = bytes!(-1024u8); //~ ERROR Non-literal in bytes +} diff --git a/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs b/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs new file mode 100644 index 00000000000..b7d55385d1c --- /dev/null +++ b/src/test/compile-fail/syntax-extension-bytes-unsupported-literal.rs @@ -0,0 +1,13 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let vec = bytes!(45f); //~ ERROR Unsupported literal in bytes! +} diff --git a/src/test/run-pass/borrowck-rvalues-mutable.rs b/src/test/run-pass/borrowck-rvalues-mutable.rs new file mode 100644 index 00000000000..cf5a9341c9d --- /dev/null +++ b/src/test/run-pass/borrowck-rvalues-mutable.rs @@ -0,0 +1,30 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Counter { + value: uint +} + +impl Counter { + fn new(v: uint) -> Counter { + Counter {value: v} + } + + fn get_and_inc(&mut self) -> uint { + let v = self.value; + self.value += 1; + v + } +} + +pub fn main() { + let v = Counter::new(22).get_and_inc(); + assert_eq!(v, 22); +} diff --git a/src/test/run-pass/deriving-clone-enum.rs b/src/test/run-pass/deriving-clone-enum.rs index 969e1fb5dd6..9ce965aa49f 100644 --- a/src/test/run-pass/deriving-clone-enum.rs +++ b/src/test/run-pass/deriving-clone-enum.rs @@ -8,11 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[deriving(Clone)] +#[deriving(Clone, DeepClone)] enum E { A, B(()), C } -pub fn main() {} +pub fn main() { + let _ = A.clone(); + let _ = B(()).deep_clone(); +} diff --git a/src/test/run-pass/deriving-clone-generic-enum.rs b/src/test/run-pass/deriving-clone-generic-enum.rs index 23841017e93..78abbf504f3 100644 --- a/src/test/run-pass/deriving-clone-generic-enum.rs +++ b/src/test/run-pass/deriving-clone-generic-enum.rs @@ -1,8 +1,21 @@ -#[deriving(Clone)] +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Clone, DeepClone)] enum E<T,U> { A(T), B(T,U), C } -fn main() {} +fn main() { + let _ = A::<int, int>(1i).clone(); + let _ = B(1i, 1.234).deep_clone(); +} diff --git a/src/test/run-pass/deriving-clone-generic-struct.rs b/src/test/run-pass/deriving-clone-generic-struct.rs index 0a7a5a3aa75..fd300cbc8b7 100644 --- a/src/test/run-pass/deriving-clone-generic-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-struct.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[deriving(Clone)] +#[deriving(Clone, DeepClone)] struct S<T> { foo: (), bar: (), baz: T, } -pub fn main() {} +pub fn main() { + let _ = S { foo: (), bar: (), baz: 1i }.clone().deep_clone(); +} diff --git a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs index d6a69e8e6ac..c082a11eab8 100644 --- a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs @@ -1,4 +1,16 @@ -#[deriving(Clone)] +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Clone, DeepClone)] struct S<T>(T, ()); -fn main() {} +fn main() { + let _ = S(1i, ()).clone().deep_clone(); +} diff --git a/src/test/run-pass/deriving-clone-struct.rs b/src/test/run-pass/deriving-clone-struct.rs index 4dcbadbb3ef..d540b047af7 100644 --- a/src/test/run-pass/deriving-clone-struct.rs +++ b/src/test/run-pass/deriving-clone-struct.rs @@ -1,4 +1,14 @@ -#[deriving(Clone)] +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Clone, DeepClone)] struct S { _int: int, _i8: i8, diff --git a/src/test/run-pass/issue-6130.rs b/src/test/run-pass/issue-6130.rs new file mode 100644 index 00000000000..642308c0ca1 --- /dev/null +++ b/src/test/run-pass/issue-6130.rs @@ -0,0 +1,20 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deny(type_limits)]; + +fn main() { + let i: uint = 0; + assert!(i <= 0xFFFF_FFFF_u); + + let i: int = 0; + assert!(i >= -0x8000_0000_i); + assert!(i <= 0x7FFF_FFFF_i); +} diff --git a/src/test/run-pass/syntax-extension-bytes.rs b/src/test/run-pass/syntax-extension-bytes.rs new file mode 100644 index 00000000000..bdaae65bc3c --- /dev/null +++ b/src/test/run-pass/syntax-extension-bytes.rs @@ -0,0 +1,24 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static static_vec: &'static [u8] = bytes!("abc", 0xFF, '!'); + +fn main() { + let vec = bytes!("abc"); + assert_eq!(vec, &[97_u8, 98_u8, 99_u8]); + + let vec = bytes!("null", 0); + assert_eq!(vec, &[110_u8, 117_u8, 108_u8, 108_u8, 0_u8]); + + let vec = bytes!(' ', " ", 32, 32u8); + assert_eq!(vec, &[32_u8, 32_u8, 32_u8, 32_u8]); + + assert_eq!(static_vec, &[97_u8, 98_u8, 99_u8, 255_u8, 33_u8]); +} |
