diff --git a/.gitignore b/.gitignore index 83d6186c9e19b..b48c5de8931a8 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,8 @@ .valgrindrc lexer.ml TAGS +TAGS.emacs +TAGS.vim version.ml version.texi /Makefile @@ -60,6 +62,7 @@ config.mk /inst/ /mingw-build/ src/.DS_Store +/tmp/ /stage0/ /dl/ /stage1/ @@ -75,6 +78,8 @@ version.md rust.tex keywords.md x86_64-apple-darwin/ +x86_64-unknown-linux-gnu/ +i686-unknown-linux-gnu/ doc/core/ tmp.*.rs config.stamp diff --git a/.gitmodules b/.gitmodules index 4c61c7e409bd7..52ece628c573f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "src/llvm"] path = src/llvm - url = git://github.com/brson/llvm.git + url = https://github.com/brson/llvm.git [submodule "src/libuv"] path = src/libuv - url = git://github.com/brson/libuv.git + url = https://github.com/brson/libuv.git diff --git a/AUTHORS.txt b/AUTHORS.txt index ae583d6409e23..2f80341e21a06 100644 --- a/AUTHORS.txt +++ b/AUTHORS.txt @@ -31,6 +31,7 @@ Bilal Husain Bill Fallon Brendan Eich Brendan Zabarauskas +Brett Cannon Brian Anderson Brian J. Burg Brian Leibig @@ -50,6 +51,7 @@ Dave Herman David Forsythe David Klein David Rajchenbach-Teller +Diggory Hardy Dimitri Krassovski Donovan Preston Drew Willcoxon @@ -76,9 +78,11 @@ Ian D. Bollinger Ilyong Cho Isaac Aggrey Ivano Coppola +Jack Moffitt Jacob Harris Cryer Kragh Jacob Parker Jakub Wieczorek +James Miller Jason Orendorff Jed Davis Jeff Balogh diff --git a/RELEASES.txt b/RELEASES.txt index 19ba7d3466dc2..13e4e0c2039cc 100644 --- a/RELEASES.txt +++ b/RELEASES.txt @@ -1,5 +1,17 @@ +Version 0.7 (July 2013) +----------------------- + + * ??? changes, numerous bugfixes + + * Semantic changes + * The `self` parameter no longer implicitly means `&'self self`, and can be explicitly marked + with a lifetime. + + * Libraries + * New `core::iterator` module for external iterator objects + Version 0.6 (April 2013) ---------------------------- +------------------------ * ~2100 changes, numerous bugfixes diff --git a/configure b/configure index 71beb8214b9da..884ececa24b1e 100755 --- a/configure +++ b/configure @@ -237,7 +237,7 @@ need_cmd uname need_cmd date need_cmd tr need_cmd sed - +need_cmd file msg "inspecting environment" @@ -533,7 +533,7 @@ then LLVM_VERSION=$($LLVM_CONFIG --version) case $LLVM_VERSION in - (3.2svn|3.2|3.1svn|3.1|3.0svn|3.0) + (3.3|3.3svn|3.2|3.2svn) msg "found ok version of LLVM: $LLVM_VERSION" ;; (*) @@ -859,7 +859,7 @@ do LDFLAGS=$LLVM_LDFLAGS LLVM_FLAGS="$LLVM_TARGETS $LLVM_OPTS $LLVM_BUILD \ - $LLVM_HOST $LLVM_TARGET" + $LLVM_HOST $LLVM_TARGET --with-python=$CFG_PYTHON" msg "configuring LLVM with:" msg "$LLVM_FLAGS" diff --git a/doc/rust.md b/doc/rust.md index c6dba96267679..e9c88fc34121c 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -441,10 +441,10 @@ expression context, the final namespace qualifier is omitted. Two examples of paths with type arguments: ~~~~ -# use core::hashmap::linear::LinearMap; +# use core::hashmap::HashMap; # fn f() { # fn id(t: T) -> T { t } -type t = LinearMap; // Type arguments used in a type expression +type t = HashMap; // Type arguments used in a type expression let x = id::(10); // Type arguments used in a call expression # } ~~~~ @@ -1653,11 +1653,12 @@ Path expressions are [lvalues](#lvalues-rvalues-and-temporaries). ### Tuple expressions -Tuples are written by enclosing two or more comma-separated +Tuples are written by enclosing one or more comma-separated expressions in parentheses. They are used to create [tuple-typed](#tuple-types) values. ~~~~~~~~ {.tuple} +(0,); (0f, 4.5f); ("a", 4u, true); ~~~~~~~~ @@ -2578,7 +2579,7 @@ to the record type-constructor. The differences are as follows: Tuple types and values are denoted by listing the types or values of their elements, respectively, in a parenthesized, comma-separated -list. Single-element tuples are not legal; all tuples have two or more values. +list. The members of a tuple are laid out in memory contiguously, like a record, in order specified by the tuple type. @@ -3251,6 +3252,28 @@ of runtime logging modules follows. * `::rt::backtrace` Log a backtrace on task failure * `::rt::callback` Unused +#### Logging Expressions + +Rust provides several macros to log information. Here's a simple Rust program +that demonstrates all four of them: + +```rust +fn main() { + error!("This is an error log") + warn!("This is a warn log") + info!("this is an info log") + debug!("This is a debug log") +} +``` + +These four log levels correspond to levels 1-4, as controlled by `RUST_LOG`: + +```bash +$ RUST_LOG=rust=3 ./rust +rust: ~"\"This is an error log\"" +rust: ~"\"This is a warn log\"" +rust: ~"\"this is an info log\"" +``` # Appendix: Rationales and design tradeoffs diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index 4a93eecac0da5..6bebc6fd33a77 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -2,255 +2,200 @@ # Introduction -Because Rust is a systems programming language, one of its goals is to -interoperate well with C code. +This tutorial will use the [snappy](https://code.google.com/p/snappy/) +compression/decompression library as an introduction to writing bindings for +foreign code. Rust is currently unable to call directly into a C++ library, but +snappy includes a C interface (documented in +[`snappy-c.h`](https://code.google.com/p/snappy/source/browse/trunk/snappy-c.h)). -We'll start with an example, which is a bit bigger than usual. We'll -go over it one piece at a time. This is a program that uses OpenSSL's -`SHA1` function to compute the hash of its first command-line -argument, which it then converts to a hexadecimal string and prints to -standard output. If you have the OpenSSL libraries installed, it -should compile and run without any extra effort. +The following is a minimal example of calling a foreign function which will compile if snappy is +installed: ~~~~ {.xfail-test} -extern mod std; -use core::libc::c_uint; +use core::libc::size_t; -extern mod crypto { - fn SHA1(src: *u8, sz: c_uint, out: *u8) -> *u8; -} - -fn as_hex(data: ~[u8]) -> ~str { - let mut acc = ~""; - for data.each |&byte| { acc += fmt!("%02x", byte as uint); } - return acc; -} - -fn sha1(data: ~str) -> ~str { - unsafe { - let bytes = str::to_bytes(data); - let hash = crypto::SHA1(vec::raw::to_ptr(bytes), - vec::len(bytes) as c_uint, - ptr::null()); - return as_hex(vec::from_buf(hash, 20)); - } +#[link_args = "-lsnappy"] +extern { + fn snappy_max_compressed_length(source_length: size_t) -> size_t; } fn main() { - io::println(sha1(core::os::args()[1])); + let x = unsafe { snappy_max_compressed_length(100) }; + println(fmt!("max compressed length of a 100 byte buffer: %?", x)); } ~~~~ -# Foreign modules - -Before we can call the `SHA1` function defined in the OpenSSL library, we have -to declare it. That is what this part of the program does: +The `extern` block is a list of function signatures in a foreign library, in this case with the +platform's C ABI. The `#[link_args]` attribute is used to instruct the linker to link against the +snappy library so the symbols are resolved. -~~~~ {.xfail-test} -extern mod crypto { - fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; } -~~~~ +Foreign functions are assumed to be unsafe so calls to them need to be wrapped with `unsafe {}` as a +promise to the compiler that everything contained within truly is safe. C libraries often expose +interfaces that aren't thread-safe, and almost any function that takes a pointer argument isn't +valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of +Rust's safe memory model. -An `extern` module declaration containing function signatures introduces the -functions listed as _foreign functions_. Foreign functions differ from regular -Rust functions in that they are implemented in some other language (usually C) -and called through Rust's foreign function interface (FFI). An extern module -like this is called a foreign module, and implicitly tells the compiler to -link with a library that contains the listed foreign functions, and has the -same name as the module. +When declaring the argument types to a foreign function, the Rust compiler will not check if the +declaration is correct, so specifying it correctly is part of keeping the binding correct at +runtime. -In this case, the Rust compiler changes the name `crypto` to a shared library -name in a platform-specific way (`libcrypto.so` on Linux, for example), -searches for the shared library with that name, and links the library into the -program. If you want the module to have a different name from the actual -library, you can use the `"link_name"` attribute, like: +The `extern` block can be extended to cover the entire snappy API: ~~~~ {.xfail-test} -#[link_name = "crypto"] -extern mod something { - fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8; +use core::libc::{c_int, size_t}; + +#[link_args = "-lsnappy"] +extern { + fn snappy_compress(input: *u8, + input_length: size_t, + compressed: *mut u8, + compressed_length: *mut size_t) -> c_int; + fn snappy_uncompress(compressed: *u8, + compressed_length: size_t, + uncompressed: *mut u8, + uncompressed_length: *mut size_t) -> c_int; + fn snappy_max_compressed_length(source_length: size_t) -> size_t; + fn snappy_uncompressed_length(compressed: *u8, + compressed_length: size_t, + result: *mut size_t) -> c_int; + fn snappy_validate_compressed_buffer(compressed: *u8, + compressed_length: size_t) -> c_int; } ~~~~ -# Foreign calling conventions +# Creating a safe interface -Most foreign code is C code, which usually uses the `cdecl` calling -convention, so that is what Rust uses by default when calling foreign -functions. Some foreign functions, most notably the Windows API, use other -calling conventions. Rust provides the `"abi"` attribute as a way to hint to -the compiler which calling convention to use: +The raw C API needs to be wrapped to provide memory safety and make use of higher-level concepts +like vectors. A library can choose to expose only the safe, high-level interface and hide the unsafe +internal details. -~~~~ -#[cfg(target_os = "win32")] -#[abi = "stdcall"] -extern mod kernel32 { - fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int; +Wrapping the functions which expect buffers involves using the `vec::raw` module to manipulate Rust +vectors as pointers to memory. Rust's vectors are guaranteed to be a contiguous block of memory. The +length is number of elements currently contained, and the capacity is the total size in elements of +the allocated memory. The length is less than or equal to the capacity. + +~~~~ {.xfail-test} +pub fn validate_compressed_buffer(src: &[u8]) -> bool { + unsafe { + snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0 + } } ~~~~ -The `"abi"` attribute applies to a foreign module (it cannot be applied -to a single function within a module), and must be either `"cdecl"` -or `"stdcall"`. We may extend the compiler in the future to support other -calling conventions. +The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, but it makes the +guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function +signature. -# Unsafe pointers +The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be +allocated to hold the output too. -The foreign `SHA1` function takes three arguments, and returns a pointer. +The `snappy_max_compressed_length` function can be used to allocate a vector with the maximum +required capacity to hold the compressed output. The vector can then be passed to the +`snappy_compress` function as an output parameter. An output parameter is also passed to retrieve +the true length after compression for setting the length. ~~~~ {.xfail-test} -# extern mod crypto { -fn SHA1(src: *u8, sz: libc::c_uint, out: *u8) -> *u8; -# } -~~~~ +pub fn compress(src: &[u8]) -> ~[u8] { + unsafe { + let srclen = src.len() as size_t; + let psrc = vec::raw::to_ptr(src); -When declaring the argument types to a foreign function, the Rust -compiler has no way to check whether your declaration is correct, so -you have to be careful. If you get the number or types of the -arguments wrong, you're likely to cause a segmentation fault. Or, -probably even worse, your code will work on one platform, but break on -another. + let mut dstlen = snappy_max_compressed_length(srclen); + let mut dst = vec::with_capacity(dstlen as uint); + let pdst = vec::raw::to_mut_ptr(dst); -In this case, we declare that `SHA1` takes two `unsigned char*` -arguments and one `unsigned long`. The Rust equivalents are `*u8` -unsafe pointers and an `uint` (which, like `unsigned long`, is a -machine-word-sized type). + snappy_compress(psrc, srclen, pdst, &mut dstlen); + vec::raw::set_len(&mut dst, dstlen as uint); + dst + } +} +~~~~ -The standard library provides various functions to create unsafe pointers, -such as those in `core::cast`. Most of these functions have `unsafe` in their -name. You can dereference an unsafe pointer with the `*` operator, but use -caution: unlike Rust's other pointer types, unsafe pointers are completely -unmanaged, so they might point at invalid memory, or be null pointers. +Decompression is similar, because snappy stores the uncompressed size as part of the compression +format and `snappy_uncompressed_length` will retrieve the exact buffer size required. -# Unsafe blocks +~~~~ {.xfail-test} +pub fn uncompress(src: &[u8]) -> Option<~[u8]> { + unsafe { + let srclen = src.len() as size_t; + let psrc = vec::raw::to_ptr(src); -The `sha1` function is the most obscure part of the program. + let mut dstlen: size_t = 0; + snappy_uncompressed_length(psrc, srclen, &mut dstlen); -~~~~ -# pub mod crypto { -# pub fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out } -# } -# fn as_hex(data: ~[u8]) -> ~str { ~"hi" } -fn sha1(data: ~str) -> ~str { - unsafe { - let bytes = str::to_bytes(data); - let hash = crypto::SHA1(vec::raw::to_ptr(bytes), - vec::len(bytes), ptr::null()); - return as_hex(vec::from_buf(hash, 20)); + let mut dst = vec::with_capacity(dstlen as uint); + let pdst = vec::raw::to_mut_ptr(dst); + + if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 { + vec::raw::set_len(&mut dst, dstlen as uint); + Some(dst) + } else { + None // SNAPPY_INVALID_INPUT + } } } ~~~~ -First, what does the `unsafe` keyword at the top of the function -mean? `unsafe` is a block modifier—it declares the block following it -to be known to be unsafe. +For reference, the examples used here are also available as an [library on +GitHub](https://github.com/thestinger/rust-snappy). -Some operations, like dereferencing unsafe pointers or calling -functions that have been marked unsafe, are only allowed inside unsafe -blocks. With the `unsafe` keyword, you're telling the compiler 'I know -what I'm doing'. The main motivation for such an annotation is that -when you have a memory error (and you will, if you're using unsafe -constructs), you have some idea where to look—it will most likely be -caused by some unsafe code. +# Linking -Unsafe blocks isolate unsafety. Unsafe functions, on the other hand, -advertise it to the world. An unsafe function is written like this: - -~~~~ -unsafe fn kaboom() { ~"I'm harmless!"; } -~~~~ +In addition to the `#[link_args]` attribute for explicitly passing arguments to the linker, an +`extern mod` block will pass `-lmodname` to the linker by default unless it has a `#[nolink]` +attribute applied. -This function can only be called from an `unsafe` block or another -`unsafe` function. - -# Pointer fiddling +# Unsafe blocks -The standard library defines a number of helper functions for dealing -with unsafe data, casting between types, and generally subverting -Rust's safety mechanisms. +Some operations, like dereferencing unsafe pointers or calling functions that have been marked +unsafe are only allowed inside unsafe blocks. Unsafe blocks isolate unsafety and are a promise to +the compiler that the unsafety does not leak out of the block. -Let's look at our `sha1` function again. +Unsafe functions, on the other hand, advertise it to the world. An unsafe function is written like +this: ~~~~ -# pub mod crypto { -# pub fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8 { out } -# } -# fn as_hex(data: ~[u8]) -> ~str { ~"hi" } -# fn x(data: ~str) -> ~str { -# unsafe { -let bytes = str::to_bytes(data); -let hash = crypto::SHA1(vec::raw::to_ptr(bytes), - vec::len(bytes), ptr::null()); -return as_hex(vec::from_buf(hash, 20)); -# } -# } +unsafe fn kaboom(ptr: *int) -> int { *ptr } ~~~~ -The `str::to_bytes` function is perfectly safe: it converts a string to a -`~[u8]`. The program then feeds this byte array to `vec::raw::to_ptr`, which -returns an unsafe pointer to its contents. - -This pointer will become invalid at the end of the scope in which the vector -it points to (`bytes`) is valid, so you should be very careful how you use -it. In this case, the local variable `bytes` outlives the pointer, so we're -good. - -Passing a null pointer as the third argument to `SHA1` makes it use a -static buffer, and thus save us the effort of allocating memory -ourselves. `ptr::null` is a generic function that, in this case, returns an -unsafe null pointer of type `*u8`. (Rust generics are awesome -like that: they can take the right form depending on the type that they -are expected to return.) - -Finally, `vec::from_buf` builds up a new `~[u8]` from the -unsafe pointer that `SHA1` returned. SHA1 digests are always -twenty bytes long, so we can pass `20` for the length of the new -vector. - -# Passing structures +This function can only be called from an `unsafe` block or another `unsafe` function. -C functions often take pointers to structs as arguments. Since Rust -`struct`s are binary-compatible with C structs, Rust programs can call -such functions directly. +# Foreign calling conventions -This program uses the POSIX function `gettimeofday` to get a -microsecond-resolution timer. +Most foreign code exposes a C ABI, and Rust uses the platform's C calling convention by default when +calling foreign functions. Some foreign functions, most notably the Windows API, use other calling +conventions. Rust provides the `abi` attribute as a way to hint to the compiler which calling +convention to use: ~~~~ -extern mod std; -use core::libc::c_ulonglong; - -struct timeval { - tv_sec: c_ulonglong, - tv_usec: c_ulonglong +#[cfg(target_os = "win32")] +#[abi = "stdcall"] +extern mod kernel32 { + fn SetEnvironmentVariableA(n: *u8, v: *u8) -> int; } +~~~~ -#[nolink] -extern mod lib_c { - fn gettimeofday(tv: *mut timeval, tz: *()) -> i32; -} -fn unix_time_in_microseconds() -> u64 { - unsafe { - let mut x = timeval { - tv_sec: 0 as c_ulonglong, - tv_usec: 0 as c_ulonglong - }; - lib_c::gettimeofday(&mut x, ptr::null()); - return (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64); - } -} +The `abi` attribute applies to a foreign module (it cannot be applied to a single function within a +module), and must be either `"cdecl"` or `"stdcall"`. The compiler may eventually support other +calling conventions. -# fn main() { assert!(fmt!("%?", unix_time_in_microseconds()) != ~""); } -~~~~ +# Interoperability with foreign code -The `#[nolink]` attribute indicates that there's no foreign library to -link in. The standard C library is already linked with Rust programs. +Rust guarantees that the layout of a `struct` is compatible with the platform's representation in C. +A `#[packed]` attribute is available, which will lay out the struct members without padding. +However, there are currently no guarantees about the layout of an `enum`. -In C, a `timeval` is a struct with two 32-bit integer fields. Thus, we -define a `struct` type with the same contents, and declare -`gettimeofday` to take a pointer to such a `struct`. +Rust's owned and managed boxes use non-nullable pointers as handles which point to the contained +object. However, they should not be manually created because they are managed by internal +allocators. Borrowed pointers can safely be assumed to be non-nullable pointers directly to the +type. However, breaking the borrow checking or mutability rules is not guaranteed to be safe, so +prefer using raw pointers (`*`) if that's needed because the compiler can't make as many assumptions +about them. -This program does not use the second argument to `gettimeofday` (the time - zone), so the `extern mod` declaration for it simply declares this argument - to be a pointer to the unit type (written `()`). Since all null pointers have - the same representation regardless of their referent type, this is safe. +Vectors and strings share the same basic memory layout, and utilities are available in the `vec` and +`str` modules for working with C APIs. Strings are terminated with `\0` for interoperability with C, +but it should not be assumed because a slice will not always be nul-terminated. Instead, the +`str::as_c_str` function should be used. +The standard library includes type aliases and function definitions for the C standard library in +the `libc` module, and Rust links against `libc` and `libm` by default. diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index 5168809e9aab7..7831dc1d80fc0 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -2,66 +2,56 @@ # Introduction -The designers of Rust designed the language from the ground up to support pervasive -and safe concurrency through lightweight, memory-isolated tasks and -message passing. - -Rust tasks are not the same as traditional threads: rather, they are more like -_green threads_. The Rust runtime system schedules tasks cooperatively onto a -small number of operating system threads. Because tasks are significantly +Rust provides safe concurrency through a combination +of lightweight, memory-isolated tasks and message passing. +This tutorial will describe the concurrency model in Rust, how it +relates to the Rust type system, and introduce +the fundamental library abstractions for constructing concurrent programs. + +Rust tasks are not the same as traditional threads: rather, +they are considered _green threads_, lightweight units of execution that the Rust +runtime schedules cooperatively onto a small number of operating system threads. +On a multi-core system Rust tasks will be scheduled in parallel by default. +Because tasks are significantly cheaper to create than traditional threads, Rust can create hundreds of thousands of concurrent tasks on a typical 32-bit system. +In general, all Rust code executes inside a task, including the `main` function. + +In order to make efficient use of memory Rust tasks have dynamically sized stacks. +A task begins its life with a small +amount of stack space (currently in the low thousands of bytes, depending on +platform), and acquires more stack as needed. +Unlike in languages such as C, a Rust task cannot accidentally write to +memory beyond the end of the stack, causing crashes or worse. -Tasks provide failure isolation and recovery. When an exception occurs in Rust -code (as a result of an explicit call to `fail!()`, an assertion failure, or -another invalid operation), the runtime system destroys the entire +Tasks provide failure isolation and recovery. When a fatal error occurs in Rust +code as a result of an explicit call to `fail!()`, an assertion failure, or +another invalid operation, the runtime system destroys the entire task. Unlike in languages such as Java and C++, there is no way to `catch` an exception. Instead, tasks may monitor each other for failure. -Rust tasks have dynamically sized stacks. A task begins its life with a small -amount of stack space (currently in the low thousands of bytes, depending on -platform), and acquires more stack as needed. Unlike in languages such as C, a -Rust task cannot run off the end of the stack. However, tasks do have a stack -budget. If a Rust task exceeds its stack budget, then it will fail safely: -with a checked exception. - Tasks use Rust's type system to provide strong memory safety guarantees. In particular, the type system guarantees that tasks cannot share mutable state with each other. Tasks communicate with each other by transferring _owned_ data through the global _exchange heap_. -This tutorial explains the basics of tasks and communication in Rust, -explores some typical patterns in concurrent Rust code, and finally -discusses some of the more unusual synchronization types in the standard -library. - -> ***Warning:*** This tutorial is incomplete - ## A note about the libraries While Rust's type system provides the building blocks needed for safe and efficient tasks, all of the task functionality itself is implemented in the core and standard libraries, which are still under development -and do not always present a consistent interface. - -In particular, there are currently two independent modules that provide a -message passing interface to Rust code: `core::comm` and `core::pipes`. -`core::comm` is an older, less efficient system that is being phased out in -favor of `pipes`. At some point, we will remove the existing `core::comm` API -and move the user-facing portions of `core::pipes` to `core::comm`. In this -tutorial, we discuss `pipes` and ignore the `comm` API. +and do not always present a consistent or complete interface. For your reference, these are the standard modules involved in Rust concurrency at this writing. * [`core::task`] - All code relating to tasks and task scheduling -* [`core::comm`] - The deprecated message passing API -* [`core::pipes`] - The new message passing infrastructure and API -* [`std::comm`] - Higher level messaging types based on `core::pipes` +* [`core::comm`] - The message passing interface +* [`core::pipes`] - The underlying messaging infrastructure +* [`std::comm`] - Additional messaging types based on `core::pipes` * [`std::sync`] - More exotic synchronization tools, including locks -* [`std::arc`] - The ARC (atomic reference counted) type, for safely sharing - immutable data -* [`std::par`] - Some basic tools for implementing parallel algorithms +* [`std::arc`] - The ARC (atomically reference counted) type, + for safely sharing immutable data [`core::task`]: core/task.html [`core::comm`]: core/comm.html @@ -69,7 +59,6 @@ concurrency at this writing. [`std::comm`]: std/comm.html [`std::sync`]: std/sync.html [`std::arc`]: std/arc.html -[`std::par`]: std/par.html # Basics diff --git a/doc/tutorial.md b/doc/tutorial.md index 42b0d5a585aee..18bc94bdba534 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -495,7 +495,11 @@ omitted. A powerful application of pattern matching is *destructuring*: matching in order to bind names to the contents of data -types. Remember that `(float, float)` is a tuple of two floats: +types. + +> ***Note:*** The following code makes use of tuples (`(float, float)`) which +> are explained in section 5.3. For now you can think of tuples as a list of +> items. ~~~~ fn angle(vector: (float, float)) -> float { @@ -747,7 +751,7 @@ fn area(sh: Shape) -> float { Tuples in Rust behave exactly like structs, except that their fields do not have names. Thus, you cannot access their fields with dot notation. -Tuples can have any arity except for 0 or 1 (though you may consider +Tuples can have any arity except for 0 (though you may consider unit, `()`, as the empty tuple if you like). ~~~~ @@ -988,7 +992,7 @@ custom destructors. # Boxes -Many modern languages represent values as as pointers to heap memory by +Many modern languages represent values as pointers to heap memory by default. In contrast, Rust, like C and C++, represents such types directly. Another way to say this is that aggregate data in Rust are *unboxed*. This means that if you `let x = Point { x: 1f, y: 1f };`, you are creating a struct @@ -1067,6 +1071,28 @@ let mut d = @mut 5; // mutable variable, mutable box d = @mut 15; ~~~~ +A mutable variable and an immutable variable can refer to the same box, given +that their types are compatible. Mutability of a box is a property of its type, +however, so for example a mutable handle to an immutable box cannot be +assigned a reference to a mutable box. + +~~~~ +let a = @1; // immutable box +let b = @mut 2; // mutable box + +let mut c : @int; // declare a variable with type managed immutable int +let mut d : @mut int; // and one of type managed mutable int + +c = a; // box type is the same, okay +d = b; // box type is the same, okay +~~~~ + +~~~~ {.xfail-test} +// but b cannot be assigned to c, or a to d +c = b; // error +~~~~ + + # Move semantics Rust uses a shallow copy for parameter passing, assignment and returning values @@ -1081,6 +1107,16 @@ let y = x.clone(); // y is a newly allocated box let z = x; // no new memory allocated, x can no longer be used ~~~~ +Since in owned boxes mutability is a property of the owner, not the +box, mutable boxes may become immutable when they are moved, and vice-versa. + +~~~~ +let r = ~13; +let mut s = r; // box becomes mutable +*s += 1; +let t = s; // box becomes immutable +~~~~ + # Borrowed pointers Rust's borrowed pointers are a general purpose reference type. In contrast with @@ -1191,7 +1227,7 @@ they are frozen: let x = @mut 5; let y = x; { - let y = &*y; // the managed box is now frozen + let z = &*y; // the managed box is now frozen // modifying it through x or y will cause a task failure } // the box is now unfrozen again @@ -1888,8 +1924,8 @@ illegal to copy and pass by value. Generic `type`, `struct`, and `enum` declarations follow the same pattern: ~~~~ -# use core::hashmap::linear::LinearMap; -type Set = LinearMap; +# use core::hashmap::HashMap; +type Set = HashMap; struct Stack { elements: ~[T] @@ -2288,7 +2324,7 @@ impl Shape for CircleStruct { Notice that methods of `Circle` can call methods on `Shape`, as our `radius` implementation calls the `area` method. This is a silly way to compute the radius of a circle -(since we could just return the `circle` field), but you get the idea. +(since we could just return the `radius` field), but you get the idea. In type-parameterized functions, methods of the supertrait may be called on values of subtrait-bound type parameters. diff --git a/man/rustc.1 b/man/rustc.1 index 14d2cad86d017..9ed98c142943b 100644 --- a/man/rustc.1 +++ b/man/rustc.1 @@ -170,5 +170,5 @@ See \fBAUTHORS.txt\fR in the rust source distribution. Graydon Hoare <\fIgraydon@mozilla.com\fR> is the project leader. .SH "COPYRIGHT" -This work is licensed under MIT-like terms. See \fBLICENSE.txt\fR -in the rust source distribution. +This work is dual-licensed under Apache 2.0 and MIT terms. See \fBCOPYRIGHT\fR +file in the rust source distribution. diff --git a/mk/dist.mk b/mk/dist.mk index 92989d157b429..f71abc48620d1 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -18,6 +18,7 @@ PKG_FILES := \ $(S)COPYRIGHT \ $(S)LICENSE-APACHE \ $(S)LICENSE-MIT \ + $(S)AUTHORS.txt \ $(S)README.md \ $(S)configure $(S)Makefile.in \ $(S)man \ diff --git a/mk/install.mk b/mk/install.mk index fd7f44ddae57c..a84f527a165b4 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -119,6 +119,8 @@ install-host: $(CSREQ$(ISTAGE)_T_$(CFG_BUILD_TRIPLE)_H_$(CFG_BUILD_TRIPLE)) $(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBSYNTAX_GLOB_$(CFG_BUILD_TRIPLE))) $(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTI_GLOB_$(CFG_BUILD_TRIPLE))) $(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUST_GLOB_$(CFG_BUILD_TRIPLE))) + $(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTPKG_GLOB_$(CFG_BUILD_TRIPLE))) + $(Q)$(call INSTALL_LIB,$(HL),$(PHL),$(LIBRUSTDOC_GLOB_$(CFG_BUILD_TRIPLE))) $(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUNTIME_$(CFG_BUILD_TRIPLE))) $(Q)$(call INSTALL,$(HL),$(PHL),$(CFG_RUSTLLVM_$(CFG_BUILD_TRIPLE))) $(Q)$(call INSTALL,$(S)/man, \ diff --git a/mk/platform.mk b/mk/platform.mk index 16b5ba452f4c9..1e102587bf4a0 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -239,6 +239,31 @@ CFG_RUN_arm-linux-androideabi= CFG_RUN_TARG_arm-linux-androideabi= RUSTC_FLAGS_arm-linux-androideabi :=--android-cross-path=$(CFG_ANDROID_CROSS_PATH) +# mips-unknown-linux-gnu configuration +CC_mips-unknown-linux-gnu=mips-linux-gnu-gcc +CXX_mips-unknown-linux-gnu=mips-linux-gnu-g++ +CPP_mips-unknown-linux-gnu=mips-linux-gnu-gcc -E +AR_mips-unknown-linux-gnu=mips-linux-gnu-ar +CFG_LIB_NAME_mips-unknown-linux-gnu=lib$(1).so +CFG_LIB_GLOB_mips-unknown-linux-gnu=lib$(1)-*.so +CFG_LIB_DSYM_GLOB_mips-unknown-linux-gnu=lib$(1)-*.dylib.dSYM +CFG_GCCISH_CFLAGS_mips-unknown-linux-gnu := -Wall -g -fPIC -mips32r2 -msoft-float -mabi=32 +CFG_GCCISH_CXXFLAGS_mips-unknown-linux-gnu := -fno-rtti +CFG_GCCISH_LINK_FLAGS_mips-unknown-linux-gnu := -shared -fPIC -g -mips32r2 -msoft-float -mabi=32 +CFG_GCCISH_DEF_FLAG_mips-unknown-linux-gnu := -Wl,--export-dynamic,--dynamic-list= +CFG_GCCISH_PRE_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-whole-archive +CFG_GCCISH_POST_LIB_FLAGS_mips-unknown-linux-gnu := -Wl,-no-whole-archive -Wl,-znoexecstack +CFG_DEF_SUFFIX_mips-unknown-linux-gnu := .linux.def +CFG_INSTALL_NAME_mips-unknown-linux-gnu = +CFG_LIBUV_LINK_FLAGS_mips-unknown-linux-gnu = +CFG_EXE_SUFFIX_mips-unknown-linux-gnu := +CFG_WINDOWSY_mips-unknown-linux-gnu := +CFG_UNIXY_mips-unknown-linux-gnu := 1 +CFG_PATH_MUNGE_mips-unknown-linux-gnu := true +CFG_LDPATH_mips-unknown-linux-gnu := +CFG_RUN_mips-unknown-linux-gnu= +CFG_RUN_TARG_mips-unknown-linux-gnu= + # i686-pc-mingw32 configuration CC_i686-pc-mingw32=$(CC) CXX_i686-pc-mingw32=$(CXX) diff --git a/mk/rt.mk b/mk/rt.mk index 15712b91a1e47..b2c282e207fbc 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -27,6 +27,7 @@ LIBUV_FLAGS_i386 = -m32 -fPIC LIBUV_FLAGS_x86_64 = -m64 -fPIC LIBUV_FLAGS_arm = -fPIC -DANDROID -std=gnu99 +LIBUV_FLAGS_mips = -fPIC -mips32r2 -msoft-float -mabi=32 # when we're doing a snapshot build, we intentionally degrade as many # features in libuv and the runtime as possible, to ease portability. @@ -180,6 +181,10 @@ else $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ + LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \ + CC="$$(CC_$(1))" \ + CXX="$$(CXX_$(1))" \ + AR="$$(AR_$(1))" \ builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \ V=$$(VERBOSE) endif diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index 585fd1271a8fa..6626bc039f902 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -17,8 +17,8 @@ #[allow(deprecated_mode)]; #[allow(deprecated_pattern)]; -extern mod core(vers = "0.6"); -extern mod std(vers = "0.6"); +extern mod core(vers = "0.7-pre"); +extern mod std(vers = "0.7-pre"); use core::*; diff --git a/src/compiletest/errors.rs b/src/compiletest/errors.rs index 63b5c64c6d4a6..5a5c091d9570a 100644 --- a/src/compiletest/errors.rs +++ b/src/compiletest/errors.rs @@ -30,36 +30,34 @@ pub fn load_errors(testfile: &Path) -> ~[ExpectedError] { } fn parse_expected(line_num: uint, line: ~str) -> ~[ExpectedError] { - unsafe { - let error_tag = ~"//~"; - let mut idx; - match str::find_str(line, error_tag) { - None => return ~[], - Some(nn) => { idx = (nn as uint) + str::len(error_tag); } - } + let error_tag = ~"//~"; + let mut idx; + match str::find_str(line, error_tag) { + None => return ~[], + Some(nn) => { idx = (nn as uint) + str::len(error_tag); } + } - // "//~^^^ kind msg" denotes a message expected - // three lines above current line: - let mut adjust_line = 0u; - let len = str::len(line); - while idx < len && line[idx] == ('^' as u8) { - adjust_line += 1u; - idx += 1u; - } + // "//~^^^ kind msg" denotes a message expected + // three lines above current line: + let mut adjust_line = 0u; + let len = str::len(line); + while idx < len && line[idx] == ('^' as u8) { + adjust_line += 1u; + idx += 1u; + } - // Extract kind: - while idx < len && line[idx] == (' ' as u8) { idx += 1u; } - let start_kind = idx; - while idx < len && line[idx] != (' ' as u8) { idx += 1u; } - let kind = str::to_lower(str::slice(line, start_kind, idx).to_owned()); + // Extract kind: + while idx < len && line[idx] == (' ' as u8) { idx += 1u; } + let start_kind = idx; + while idx < len && line[idx] != (' ' as u8) { idx += 1u; } + let kind = str::to_lower(str::slice(line, start_kind, idx).to_owned()); - // Extract msg: - while idx < len && line[idx] == (' ' as u8) { idx += 1u; } - let msg = str::slice(line, idx, len).to_owned(); + // Extract msg: + while idx < len && line[idx] == (' ' as u8) { idx += 1u; } + let msg = str::slice(line, idx, len).to_owned(); - debug!("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg); + debug!("line=%u kind=%s msg=%s", line_num - adjust_line, kind, msg); - return ~[ExpectedError{line: line_num - adjust_line, kind: kind, - msg: msg}]; - } + return ~[ExpectedError{line: line_num - adjust_line, kind: kind, + msg: msg}]; } diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 5a35c56c075a7..2b36518833888 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -171,16 +171,14 @@ fn parse_name_directive(line: ~str, directive: ~str) -> bool { fn parse_name_value_directive(line: ~str, directive: ~str) -> Option<~str> { - unsafe { - let keycolon = directive + ~":"; - match str::find_str(line, keycolon) { - Some(colon) => { - let value = str::slice(line, colon + str::len(keycolon), - str::len(line)).to_owned(); - debug!("%s: %s", directive, value); - Some(value) - } - None => None + let keycolon = directive + ~":"; + match str::find_str(line, keycolon) { + Some(colon) => { + let value = str::slice(line, colon + str::len(keycolon), + str::len(line)).to_owned(); + debug!("%s: %s", directive, value); + Some(value) } + None => None } } diff --git a/src/compiletest/procsrv.rs b/src/compiletest/procsrv.rs index a96f36f5e702c..ca10aa0da7d45 100644 --- a/src/compiletest/procsrv.rs +++ b/src/compiletest/procsrv.rs @@ -26,7 +26,7 @@ fn target_env(lib_path: ~str, prog: ~str) -> ~[(~str,~str)] { // Make sure we include the aux directory in the path assert!(prog.ends_with(~".exe")); - let aux_path = prog.slice(0u, prog.len() - 4u) + ~".libaux"; + let aux_path = prog.slice(0u, prog.len() - 4u).to_owned() + ~".libaux"; env = do vec::map(env) |pair| { let (k,v) = *pair; diff --git a/src/driver/driver.rs b/src/driver/driver.rs index 2fc50eb6e7579..d3ab066929731 100644 --- a/src/driver/driver.rs +++ b/src/driver/driver.rs @@ -9,24 +9,24 @@ // except according to those terms. #[no_core]; -extern mod core(vers = "0.6"); +extern mod core(vers = "0.7-pre"); #[cfg(rustpkg)] -extern mod this(name = "rustpkg", vers = "0.6"); +extern mod this(name = "rustpkg", vers = "0.7-pre"); #[cfg(fuzzer)] -extern mod this(name = "fuzzer", vers = "0.6"); +extern mod this(name = "fuzzer", vers = "0.7-pre"); #[cfg(rustdoc)] -extern mod this(name = "rustdoc", vers = "0.6"); +extern mod this(name = "rustdoc", vers = "0.7-pre"); #[cfg(rusti)] -extern mod this(name = "rusti", vers = "0.6"); +extern mod this(name = "rusti", vers = "0.7-pre"); #[cfg(rust)] -extern mod this(name = "rust", vers = "0.6"); +extern mod this(name = "rust", vers = "0.7-pre"); #[cfg(rustc)] -extern mod this(name = "rustc", vers = "0.6"); +extern mod this(name = "rustc", vers = "0.7-pre"); fn main() { this::main() } diff --git a/src/etc/kate/rust.xml b/src/etc/kate/rust.xml index f0c057ff25b49..59f8c164588b3 100644 --- a/src/etc/kate/rust.xml +++ b/src/etc/kate/rust.xml @@ -7,7 +7,7 @@ ]> - + fn diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 5dabf34953b01..864cf3daee07e 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -112,7 +112,49 @@ def escape_char(c): return "'\\u%4.4x'" % c return "'\\U%8.8x'" % c +def ch_prefix(ix): + if ix == 0: + return " " + if ix % 2 == 0: + return ",\n " + else: + return ", " + +def emit_bsearch_range_table(f): + f.write(""" + pure fn bsearch_range_table(c: char, r: &[(char,char)]) -> bool { + use cmp::{EQ, LT, GT}; + use vec::bsearch; + use option::None; + (do bsearch(r) |&(lo,hi)| { + if lo <= c && c <= hi { EQ } + else if hi < c { LT } + else { GT } + }) != None + }\n\n +"""); + def emit_property_module(f, mod, tbl): + f.write("pub mod %s {\n" % mod) + keys = tbl.keys() + keys.sort() + emit_bsearch_range_table(f); + for cat in keys: + f.write(" const %s_table : &[(char,char)] = &[\n" % cat) + ix = 0 + for pair in tbl[cat]: + f.write(ch_prefix(ix)) + f.write("(%s, %s)" % (escape_char(pair[0]), escape_char(pair[1]))) + ix += 1 + f.write("\n ];\n\n") + + f.write(" pub pure fn %s(c: char) -> bool {\n" % cat) + f.write(" bsearch_range_table(c, %s_table)\n" % cat) + f.write(" }\n\n") + f.write("}\n") + + +def emit_property_module_old(f, mod, tbl): f.write("mod %s {\n" % mod) keys = tbl.keys() keys.sort() @@ -193,8 +235,9 @@ def emit_decomp_module(f, canon, compat): rf = open(r, "w") (canon_decomp, compat_decomp, gencats) = load_unicode_data("UnicodeData.txt") -emit_decomp_module(rf, canon_decomp, compat_decomp) emit_property_module(rf, "general_category", gencats) +#emit_decomp_module(rf, canon_decomp, compat_decomp) + derived = load_derived_core_properties("DerivedCoreProperties.txt") emit_property_module(rf, "derived_property", derived) diff --git a/src/etc/vim/syntax/rust.vim b/src/etc/vim/syntax/rust.vim index 87f4059716b35..3e6c11c6238b1 100644 --- a/src/etc/vim/syntax/rust.vim +++ b/src/etc/vim/syntax/rust.vim @@ -110,8 +110,11 @@ syn match rustFloat display "\<[0-9][0-9_]*\.[0-9_]\+\%([eE][+-]\=[0-9 syn match rustLifetime display "\'\%([^[:cntrl:][:space:][:punct:][:digit:]]\|_\)\%([^[:cntrl:][:punct:][:space:]]\|_\)*" syn match rustCharacter "'\([^'\\]\|\\\(['nrt\\\"]\|x\x\{2}\|u\x\{4}\|U\x\{8}\)\)'" -syn region rustComment start="/\*" end="\*/" contains=rustComment,rustTodo -syn region rustComment start="//" skip="\\$" end="$" contains=rustTodo keepend +syn region rustCommentDoc start="/\*[\*!]" end="\*/" +syn region rustCommentDoc start="//[/!]" skip="\\$" end="$" keepend +syn match rustComment "/\*\*/" +syn region rustComment start="/\*\([^\*!]\|$\)" end="\*/" contains=rustTodo +syn region rustComment start="//\([^/!]\|$\)" skip="\\$" end="$" contains=rustTodo keepend syn keyword rustTodo contained TODO FIXME XXX NB @@ -134,6 +137,7 @@ hi def link rustConditional Conditional hi def link rustIdentifier Identifier hi def link rustModPath Include hi def link rustFuncName Function +hi def link rustCommentDoc SpecialComment hi def link rustComment Comment hi def link rustMacro Macro hi def link rustType Type diff --git a/src/etc/x86.supp b/src/etc/x86.supp index 95508fa12d236..028bde2e73ff8 100644 --- a/src/etc/x86.supp +++ b/src/etc/x86.supp @@ -565,3 +565,100 @@ fun:__gxx_personality_v0 ... } + +{ + llvm-optimization-reads-uninitialized-memory-1 + Memcheck:Cond + fun:_ZN4test17run_tests_console4anon13expr_fn* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-2 + Memcheck:Cond + fun:_ZN4test17run_tests_console* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-3 + Memcheck:Cond + fun:_ZN4test9run_tests4anon13expr_fn_* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-4 + Memcheck:Cond + fun:_ZN5parse6parser14__extensions__10meth_*parse_item_fn* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-5 + Memcheck:Cond + fun:_ZN4fold25noop_fold_item_underscore* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-6 + Memcheck:Cond + fun:_ZN5parse6parser14__extensions__10meth_*parse_item_fn17* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-9 + Memcheck:Cond + fun:_ZN5parse6parser14__extensions__10meth_*parse_item_foreign_fn* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-11 + Memcheck:Cond + fun:_ZN4fold22noop_fold_foreign_item17_* + ... +} + + +{ + llvm-optimization-reads-uninitialized-memory-12 + Memcheck:Cond + fun:_ZN5parse6parser14__extensions__10meth_*parse_item_struct* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-13 + Memcheck:Cond + fun:_ZN5parse6parser14__extensions__10meth_*parse_item_type* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-14 + Memcheck:Cond + fun:_ZN7ast_map6map_fn16_* + fun:_ZN5visit30visit_struct_dtor_helper_* + obj:* + fun:_ZN8unstable6extfmt2rt14__extensions__10meth_* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-15 + Memcheck:Cond + fun:_ZN7ast_map6map_fn16_* + fun:_ZN5visit30visit_struct_dtor_helper_* + ... +} + +{ + llvm-optimization-reads-uninitialized-memory-16 + Memcheck:Cond + fun:_ZN7ast_map6map_fn* + fun:_ZN5visit30visit_struct_dtor_helper* + ... +} diff --git a/src/libcore/at_vec.rs b/src/libcore/at_vec.rs index 3e3d70530dd35..532dcf6157b54 100644 --- a/src/libcore/at_vec.rs +++ b/src/libcore/at_vec.rs @@ -208,7 +208,7 @@ pub mod raw { */ #[inline(always)] pub unsafe fn set_len(v: @[T], new_len: uint) { - let repr: **VecRepr = ::cast::reinterpret_cast(&addr_of(&v)); + let repr: **mut VecRepr = ::cast::reinterpret_cast(&addr_of(&v)); (**repr).unboxed.fill = new_len * sys::size_of::(); } @@ -226,7 +226,7 @@ pub mod raw { #[inline(always)] // really pretty please pub unsafe fn push_fast(v: &mut @[T], initval: T) { - let repr: **VecRepr = ::cast::reinterpret_cast(&v); + let repr: **mut VecRepr = ::cast::reinterpret_cast(&v); let fill = (**repr).unboxed.fill; (**repr).unboxed.fill += sys::size_of::(); let p = addr_of(&((**repr).unboxed.data)); @@ -277,45 +277,49 @@ pub mod raw { pub unsafe fn reserve_at_least(v: &mut @[T], n: uint) { reserve(v, uint::next_power_of_two(n)); } - } -#[test] -pub fn test() { - // Some code that could use that, then: - fn seq_range(lo: uint, hi: uint) -> @[uint] { - do build |push| { - for uint::range(lo, hi) |i| { - push(i); +#[cfg(test)] +mod test { + use super::*; + use prelude::*; + + #[test] + fn test() { + // Some code that could use that, then: + fn seq_range(lo: uint, hi: uint) -> @[uint] { + do build |push| { + for uint::range(lo, hi) |i| { + push(i); + } } } - } - assert_eq!(seq_range(10, 15), @[10, 11, 12, 13, 14]); - assert!(from_fn(5, |x| x+1) == @[1, 2, 3, 4, 5]); - assert!(from_elem(5, 3.14) == @[3.14, 3.14, 3.14, 3.14, 3.14]); -} - -#[test] -pub fn append_test() { - assert!(@[1,2,3] + @[4,5,6] == @[1,2,3,4,5,6]); -} + assert_eq!(seq_range(10, 15), @[10, 11, 12, 13, 14]); + assert!(from_fn(5, |x| x+1) == @[1, 2, 3, 4, 5]); + assert!(from_elem(5, 3.14) == @[3.14, 3.14, 3.14, 3.14, 3.14]); + } -#[test] -pub fn test_from_owned() { - assert!(from_owned::(~[]) == @[]); - 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]]); -} + #[test] + fn append_test() { + assert!(@[1,2,3] + @[4,5,6] == @[1,2,3,4,5,6]); + } -#[test] -pub fn test_from_slice() { - assert!(from_slice::([]) == @[]); - 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]]); -} + #[test] + fn test_from_owned() { + assert!(from_owned::(~[]) == @[]); + 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]]); + } + #[test] + fn test_from_slice() { + assert!(from_slice::([]) == @[]); + 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]]); + } +} \ No newline at end of file diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs index a30cb92693748..6c60cec2595ef 100644 --- a/src/libcore/bool.rs +++ b/src/libcore/bool.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - //! Boolean logic +#[cfg(notest)] +use cmp::{Eq, Ord, TotalOrd, Ordering}; use option::{None, Option, Some}; use from_str::FromStr; -#[cfg(notest)] use cmp; - /// Negation / inverse pub fn not(v: bool) -> bool { !v } @@ -73,40 +72,86 @@ pub fn all_values(blk: &fn(v: bool)) { } /// converts truth value to an 8 bit byte +#[inline(always)] pub fn to_bit(v: bool) -> u8 { if v { 1u8 } else { 0u8 } } #[cfg(notest)] -impl cmp::Eq for bool { +impl Ord for bool { + #[inline(always)] + fn lt(&self, other: &bool) -> bool { to_bit(*self) < to_bit(*other) } + #[inline(always)] + fn le(&self, other: &bool) -> bool { to_bit(*self) <= to_bit(*other) } + #[inline(always)] + fn gt(&self, other: &bool) -> bool { to_bit(*self) > to_bit(*other) } + #[inline(always)] + fn ge(&self, other: &bool) -> bool { to_bit(*self) >= to_bit(*other) } +} + +#[cfg(notest)] +impl TotalOrd for bool { + #[inline(always)] + fn cmp(&self, other: &bool) -> Ordering { to_bit(*self).cmp(&to_bit(*other)) } +} + +#[cfg(notest)] +impl Eq for bool { + #[inline(always)] fn eq(&self, other: &bool) -> bool { (*self) == (*other) } + #[inline(always)] fn ne(&self, other: &bool) -> bool { (*self) != (*other) } } -#[test] -pub fn test_bool_from_str() { - use from_str::FromStr; +#[cfg(test)] +mod tests { + use super::*; + use prelude::*; - do all_values |v| { - assert!(Some(v) == FromStr::from_str(to_str(v))) + #[test] + fn test_bool_from_str() { + use from_str::FromStr; + + do all_values |v| { + assert!(Some(v) == FromStr::from_str(to_str(v))) + } } -} -#[test] -pub fn test_bool_to_str() { - assert!(to_str(false) == ~"false"); - assert!(to_str(true) == ~"true"); -} + #[test] + fn test_bool_to_str() { + assert!(to_str(false) == ~"false"); + assert!(to_str(true) == ~"true"); + } -#[test] -pub fn test_bool_to_bit() { - do all_values |v| { - assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 }); + #[test] + fn test_bool_to_bit() { + do all_values |v| { + assert!(to_bit(v) == if is_true(v) { 1u8 } else { 0u8 }); + } } -} -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: + #[test] + fn test_bool_ord() { + assert!(true > false); + assert!(!(false > true)); + + assert!(false < true); + assert!(!(true < false)); + + assert!(false <= false); + assert!(false >= false); + assert!(true <= true); + assert!(true >= true); + + assert!(false <= true); + assert!(!(false >= true)); + assert!(true >= false); + assert!(!(true <= false)); + } + + #[test] + fn test_bool_totalord() { + assert_eq!(true.cmp(&true), Equal); + assert_eq!(false.cmp(&false), Equal); + assert_eq!(true.cmp(&false), Greater); + assert_eq!(false.cmp(&true), Less); + } +} diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index 42464c848efb3..1d214f402f5ac 100644 --- a/src/libcore/cast.rs +++ b/src/libcore/cast.rs @@ -111,16 +111,16 @@ pub unsafe fn copy_lifetime_vec<'a,S,T>(_ptr: &'a [S], ptr: &T) -> &'a T { ****************************************************************************/ #[cfg(test)] -pub mod tests { +mod tests { use cast::{bump_box_refcount, reinterpret_cast, transmute}; #[test] - pub fn test_reinterpret_cast() { + fn test_reinterpret_cast() { assert!(1u == unsafe { reinterpret_cast(&1) }); } #[test] - pub fn test_bump_box_refcount() { + fn test_bump_box_refcount() { unsafe { let box = @~"box box box"; // refcount 1 bump_box_refcount(box); // refcount 2 @@ -135,7 +135,7 @@ pub mod tests { } #[test] - pub fn test_transmute() { + fn test_transmute() { use managed::raw::BoxRepr; unsafe { let x = @100u8; @@ -146,7 +146,7 @@ pub mod tests { } #[test] - pub fn test_transmute2() { + fn test_transmute2() { unsafe { assert!(~[76u8, 0u8] == transmute(~"L")); } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 28b3ebe4484c7..1707bddc2b9d4 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -10,7 +10,7 @@ //! A mutable, nullable memory location -use cast::transmute; +use cast::transmute_mut; use prelude::*; /* @@ -20,16 +20,12 @@ Similar to a mutable option type, but friendlier. */ pub struct Cell { - mut value: Option + value: Option } impl cmp::Eq for Cell { fn eq(&self, other: &Cell) -> bool { - unsafe { - let frozen_self: &Option = transmute(&mut self.value); - let frozen_other: &Option = transmute(&mut other.value); - frozen_self == frozen_other - } + (self.value) == (other.value) } fn ne(&self, other: &Cell) -> bool { !self.eq(other) } } @@ -46,6 +42,7 @@ pub fn empty_cell() -> Cell { pub impl Cell { /// Yields the value, failing if the cell is empty. fn take(&self) -> T { + let mut self = unsafe { transmute_mut(self) }; if self.is_empty() { fail!(~"attempt to take an empty cell"); } @@ -57,6 +54,7 @@ pub impl Cell { /// Returns the value, failing if the cell is full. fn put_back(&self, value: T) { + let mut self = unsafe { transmute_mut(self) }; if !self.is_empty() { fail!(~"attempt to put a value back into a full cell"); } @@ -75,6 +73,14 @@ pub impl Cell { self.put_back(v); r } + + // Calls a closure with a mutable reference to the value. + fn with_mut_ref(&self, op: &fn(v: &mut T) -> R) -> R { + let mut v = self.take(); + let r = op(&mut v); + self.put_back(v); + r + } } #[test] @@ -103,3 +109,21 @@ fn test_put_back_non_empty() { let value_cell = Cell(~10); value_cell.put_back(~20); } + +#[test] +fn test_with_ref() { + let good = 6; + let c = Cell(~[1, 2, 3, 4, 5, 6]); + let l = do c.with_ref() |v| { v.len() }; + assert!(l == good); +} + +#[test] +fn test_with_mut_ref() { + let good = ~[1, 2, 3]; + let mut v = ~[1, 2]; + let c = Cell(v); + do c.with_mut_ref() |v| { v.push(3); } + let v = c.take(); + assert!(v == good); +} diff --git a/src/libcore/char.rs b/src/libcore/char.rs index 4f1dbe6ab7f23..6ca33540ceef6 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -202,12 +202,10 @@ pub fn escape_unicode(c: char) -> ~str { else { ('U', 8u) }); assert!(str::len(s) <= pad); let mut out = ~"\\"; - unsafe { - str::push_str(&mut out, str::from_char(c)); - for uint::range(str::len(s), pad) |_i| - { str::push_str(&mut out, ~"0"); } - str::push_str(&mut out, s); - } + str::push_str(&mut out, str::from_char(c)); + for uint::range(str::len(s), pad) |_i| + { str::push_str(&mut out, ~"0"); } + str::push_str(&mut out, s); out } diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index 7b86355c91e50..9da970918b0d5 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -14,7 +14,7 @@ In Rust, some simple types are "implicitly copyable" and when you assign them or pass them as arguments, the receiver will get a copy, leaving the original value in place. These types do not require allocation to copy and do not have finalizers (i.e. they do not -contain owned pointers or implement `Drop`), so the compiler considers +contain owned boxes or implement `Drop`), so the compiler considers them cheap and safe to copy and automatically implements the `Copy` trait for them. For other types copies must be made explicitly, by convention implementing the `Clone` trait and calling the @@ -23,22 +23,38 @@ by convention implementing the `Clone` trait and calling the */ pub trait Clone { + /// Return a deep copy of the owned object tree. 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 Clone for ~T { + /// Return a deep copy of the owned box. #[inline(always)] fn clone(&self) -> ~T { ~(**self).clone() } } +impl Clone for @T { + /// Return a shallow copy of the managed box. + #[inline(always)] + fn clone(&self) -> @T { *self } +} + +impl Clone for @mut T { + /// Return a shallow copy of the managed box. + #[inline(always)] + fn clone(&self) -> @mut T { *self } +} + macro_rules! clone_impl( ($t:ty) => { impl Clone for $t { + /// Return a copy of the value. #[inline(always)] fn clone(&self) -> $t { *self } } @@ -63,3 +79,26 @@ clone_impl!(f64) clone_impl!(bool) clone_impl!(char) + +#[test] +fn test_owned_clone() { + let a: ~int = ~5i; + let b: ~int = a.clone(); + assert!(a == b); +} + +#[test] +fn test_managed_clone() { + let a: @int = @5i; + let b: @int = a.clone(); + assert!(a == b); +} + +#[test] +fn test_managed_mut_clone() { + let a: @mut int = @mut 5i; + let b: @mut int = a.clone(); + assert!(a == b); + *b = 10; + assert!(a == b); +} diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index a928d3bb2af1f..b5a5ed7c9f41e 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -64,14 +64,32 @@ totaleq_impl!(i64) totaleq_impl!(int) totaleq_impl!(uint) -#[deriving(Eq)] -pub enum Ordering { Less, Equal, Greater } +#[deriving(Clone, Eq)] +pub enum Ordering { Less = -1, Equal = 0, Greater = 1 } /// Trait for types that form a total order pub trait TotalOrd: TotalEq { fn cmp(&self, other: &Self) -> Ordering; } +impl TotalOrd for Ordering { + #[inline(always)] + fn cmp(&self, other: &Ordering) -> Ordering { + (*self as int).cmp(&(*other as int)) + } +} + +impl Ord for Ordering { + #[inline(always)] + fn lt(&self, other: &Ordering) -> bool { (*self as int) < (*other as int) } + #[inline(always)] + fn le(&self, other: &Ordering) -> bool { (*self as int) <= (*other as int) } + #[inline(always)] + fn gt(&self, other: &Ordering) -> bool { (*self as int) > (*other as int) } + #[inline(always)] + fn ge(&self, other: &Ordering) -> bool { (*self as int) >= (*other as int) } +} + macro_rules! totalord_impl( ($t:ty) => { impl TotalOrd for $t { @@ -98,6 +116,32 @@ totalord_impl!(i64) totalord_impl!(int) totalord_impl!(uint) +pub fn cmp2( + a1: &A, b1: &B, + a2: &A, b2: &B) -> Ordering +{ + //! Compares (a1, b1) against (a2, b2), where the a values are more significant. + + match a1.cmp(a2) { + Less => Less, + Greater => Greater, + Equal => b1.cmp(b2) + } +} + +/** +Return `o1` if it is not `Equal`, otherwise `o2`. Simulates the +lexical ordering on a type `(int, int)`. +*/ +// used in deriving code in libsyntax +#[inline(always)] +pub fn lexical_ordering(o1: Ordering, o2: Ordering) -> Ordering { + match o1 { + Equal => o2, + _ => o1 + } +} + /** * Trait for values that can be compared for a sort-order. * @@ -166,6 +210,8 @@ pub fn max(v1: T, v2: T) -> T { #[cfg(test)] mod test { + use super::lexical_ordering; + #[test] fn test_int_totalord() { assert_eq!(5.cmp(&10), Less); @@ -175,9 +221,35 @@ mod test { assert_eq!(12.cmp(-5), Greater); } + #[test] + fn test_cmp2() { + assert_eq!(cmp2(1, 2, 3, 4), Less); + assert_eq!(cmp2(3, 2, 3, 4), Less); + assert_eq!(cmp2(5, 2, 3, 4), Greater); + assert_eq!(cmp2(5, 5, 5, 4), Greater); + } + #[test] fn test_int_totaleq() { assert!(5.equals(&5)); assert!(!2.equals(&17)); } + + #[test] + fn test_ordering_order() { + assert!(Less < Equal); + assert_eq!(Greater.cmp(&Less), Greater); + } + + #[test] + fn test_lexical_ordering() { + fn t(o1: Ordering, o2: Ordering, e: Ordering) { + assert_eq!(lexical_ordering(o1, o2), e); + } + for [Less, Equal, Greater].each |&o| { + t(Less, o, Less); + t(Equal, o, o); + t(Greater, o, Greater); + } + } } diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs index 9fd6f1db793b0..f8b046e5b8c4f 100644 --- a/src/libcore/comm.rs +++ b/src/libcore/comm.rs @@ -188,16 +188,14 @@ impl Peekable for Port { #[inline(always)] fn port_peek(self: &Port) -> bool { - unsafe { - let mut endp = None; - endp <-> self.endp; - let peek = match &endp { - &Some(ref endp) => peek(endp), - &None => fail!(~"peeking empty stream") - }; - self.endp <-> endp; - peek - } + let mut endp = None; + endp <-> self.endp; + let peek = match &endp { + &Some(ref endp) => peek(endp), + &None => fail!(~"peeking empty stream") + }; + self.endp <-> endp; + peek } impl Selectable for Port { @@ -428,12 +426,12 @@ pub fn try_send_one(chan: ChanOne, data: T) } #[cfg(test)] -pub mod test { +mod test { use either::Right; use super::{Chan, Port, oneshot, recv_one, stream}; #[test] - pub fn test_select2() { + fn test_select2() { let (p1, c1) = stream(); let (p2, c2) = stream(); @@ -448,7 +446,7 @@ pub mod test { } #[test] - pub fn test_oneshot() { + fn test_oneshot() { let (c, p) = oneshot::init(); oneshot::client::send(c, ()); diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs index ed94f2ef2c45c..dc6c80228dd74 100644 --- a/src/libcore/condition.rs +++ b/src/libcore/condition.rs @@ -28,7 +28,7 @@ pub struct Condition<'self, T, U> { } pub impl<'self, T, U> Condition<'self, T, U> { - fn trap(&self, h: &'self fn(T) -> U) -> Trap<'self, T, U> { + fn trap(&'self self, h: &'self fn(T) -> U) -> Trap<'self, T, U> { unsafe { let p : *RustClosure = ::cast::transmute(&h); let prev = task::local_data::local_data_get(self.key); diff --git a/src/libcore/container.rs b/src/libcore/container.rs index e20821b919b6c..88c78aebfc5c7 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -25,10 +25,14 @@ pub trait Mutable: Container { fn clear(&mut self); } +#[cfg(stage0)] pub trait Map: Mutable { /// Return true if the map contains a value for the specified key fn contains_key(&self, key: &K) -> bool; + // Visits all keys and values + fn each(&self, f: &fn(&K, &V) -> bool); + /// Visit all keys fn each_key(&self, f: &fn(&K) -> bool); @@ -54,6 +58,41 @@ pub trait Map: Mutable { fn remove(&mut self, key: &K) -> bool; } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub trait Map: Mutable { + /// Return true if the map contains a value for the specified key + fn contains_key(&self, key: &K) -> bool; + + // Visits all keys and values + fn each<'a>(&'a self, f: &fn(&K, &'a V) -> bool); + + /// Visit all keys + fn each_key(&self, f: &fn(&K) -> bool); + + /// Visit all values + fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool); + + /// Iterate over the map and mutate the contained values + fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool); + + /// Return a reference to the value corresponding to the key + fn find<'a>(&'a self, key: &K) -> Option<&'a V>; + + /// Return a mutable reference to the value corresponding to the key + fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V>; + + /// Insert a key-value pair into the map. An existing value for a + /// key is replaced by the new value. Return true if the key did + /// not already exist in the map. + fn insert(&mut self, key: K, value: V) -> bool; + + /// Remove a key-value pair from the map. Return true if the key + /// was present in the map, otherwise false. + fn remove(&mut self, key: &K) -> bool; +} + pub trait Set: Mutable { /// Return true if the set contains a value fn contains(&self, value: &T) -> bool; diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f7c64e3f37445..e7a5cfbaf4b25 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -48,7 +48,7 @@ they contained the following prologue: #[link(name = "core", - vers = "0.6", + vers = "0.7-pre", uuid = "c70c24a7-5551-4f73-8e37-380b11d80be8", url = "https://github.com/mozilla/rust/tree/master/src/libcore")]; @@ -66,7 +66,7 @@ they contained the following prologue: #[allow(deprecated_drop)]; // Make core testable by not duplicating lang items. See #2912 -#[cfg(test)] extern mod realcore(name = "core", vers = "0.6"); +#[cfg(test)] extern mod realcore(name = "core", vers = "0.7-pre"); #[cfg(test)] pub use kinds = realcore::kinds; #[cfg(test)] pub use ops = realcore::ops; #[cfg(test)] pub use cmp = realcore::cmp; @@ -99,7 +99,7 @@ pub use vec::{OwnedVector, OwnedCopyableVector}; pub use iter::{BaseIter, ExtendedIter, EqIter, CopyableIter}; pub use iter::{CopyableOrderedIter, CopyableNonstrictIter, Times}; -pub use num::NumCast; +pub use num::{Num, NumCast}; pub use ptr::Ptr; pub use to_str::ToStr; pub use clone::Clone; @@ -176,6 +176,7 @@ pub mod from_str; #[path = "num/num.rs"] pub mod num; pub mod iter; +pub mod iterator; pub mod to_str; pub mod to_bytes; pub mod clone; diff --git a/src/libcore/gc.rs b/src/libcore/gc.rs index 2f35c1e0bb15e..9fd9ac3a8c8ec 100644 --- a/src/libcore/gc.rs +++ b/src/libcore/gc.rs @@ -43,7 +43,7 @@ use io; use libc::{size_t, uintptr_t}; use option::{None, Option, Some}; use ptr; -use hashmap::linear::LinearSet; +use hashmap::HashSet; use stackwalk; use sys; @@ -344,7 +344,7 @@ pub fn cleanup_stack_for_failure() { ptr::null() }; - let mut roots = LinearSet::new(); + let mut roots = HashSet::new(); for walk_gc_roots(need_cleanup, sentinel) |root, tydesc| { // Track roots to avoid double frees. if roots.contains(&*root) { diff --git a/src/libcore/hash.rs b/src/libcore/hash.rs index d31f35b011508..ba1f8cebdb01c 100644 --- a/src/libcore/hash.rs +++ b/src/libcore/hash.rs @@ -76,36 +76,30 @@ pub trait Streaming { impl Hash for A { #[inline(always)] fn hash_keyed(&self, k0: u64, k1: u64) -> u64 { - unsafe { - let s = &State(k0, k1); - for self.iter_bytes(true) |bytes| { - s.input(bytes); - } - s.result_u64() + let s = &State(k0, k1); + for self.iter_bytes(true) |bytes| { + s.input(bytes); } + s.result_u64() } } fn hash_keyed_2(a: &A, b: &B, k0: u64, k1: u64) -> u64 { - unsafe { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } - s.result_u64() - } + let s = &State(k0, k1); + for a.iter_bytes(true) |bytes| { s.input(bytes); } + for b.iter_bytes(true) |bytes| { s.input(bytes); } + s.result_u64() } fn hash_keyed_3(a: &A, b: &B, c: &C, k0: u64, k1: u64) -> u64 { - unsafe { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } - for c.iter_bytes(true) |bytes| { s.input(bytes); } - s.result_u64() - } + let s = &State(k0, k1); + for a.iter_bytes(true) |bytes| { s.input(bytes); } + for b.iter_bytes(true) |bytes| { s.input(bytes); } + for c.iter_bytes(true) |bytes| { s.input(bytes); } + s.result_u64() } fn hash_keyed_4(a: &A, b: &B, c: &C, d: &D, k0: u64, k1: u64) -> u64 { - unsafe { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } - for c.iter_bytes(true) |bytes| { s.input(bytes); } - for d.iter_bytes(true) |bytes| { s.input(bytes); } - s.result_u64() - } + let s = &State(k0, k1); + for a.iter_bytes(true) |bytes| { s.input(bytes); } + for b.iter_bytes(true) |bytes| { s.input(bytes); } + for c.iter_bytes(true) |bytes| { s.input(bytes); } + for d.iter_bytes(true) |bytes| { s.input(bytes); } + s.result_u64() } fn hash_keyed_5(a: &A, b: &B, c: &C, d: &D, e: &E, k0: u64, k1: u64) -> u64 { - unsafe { - let s = &State(k0, k1); - for a.iter_bytes(true) |bytes| { s.input(bytes); } - for b.iter_bytes(true) |bytes| { s.input(bytes); } - for c.iter_bytes(true) |bytes| { s.input(bytes); } - for d.iter_bytes(true) |bytes| { s.input(bytes); } - for e.iter_bytes(true) |bytes| { s.input(bytes); } - s.result_u64() - } + let s = &State(k0, k1); + for a.iter_bytes(true) |bytes| { s.input(bytes); } + for b.iter_bytes(true) |bytes| { s.input(bytes); } + for c.iter_bytes(true) |bytes| { s.input(bytes); } + for d.iter_bytes(true) |bytes| { s.input(bytes); } + for e.iter_bytes(true) |bytes| { s.input(bytes); } + s.result_u64() } // Implement State as SipState @@ -367,170 +357,176 @@ impl Streaming for SipState { } } -#[test] -pub fn test_siphash() { - let vecs : [[u8, ..8], ..64] = [ - [ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ], - [ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ], - [ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ], - [ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ], - [ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ], - [ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ], - [ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ], - [ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ], - [ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ], - [ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ], - [ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ], - [ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ], - [ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ], - [ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ], - [ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ], - [ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ], - [ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ], - [ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ], - [ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ], - [ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ], - [ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ], - [ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ], - [ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ], - [ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ], - [ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ], - [ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ], - [ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ], - [ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ], - [ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ], - [ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ], - [ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ], - [ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ], - [ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ], - [ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ], - [ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ], - [ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ], - [ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ], - [ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ], - [ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ], - [ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ], - [ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ], - [ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ], - [ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ], - [ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ], - [ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ], - [ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ], - [ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ], - [ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ], - [ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ], - [ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ], - [ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ], - [ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ], - [ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ], - [ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ], - [ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ], - [ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ], - [ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ], - [ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ], - [ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ], - [ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ], - [ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ], - [ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ], - [ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ], - [ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ] - ]; - - let k0 = 0x_07_06_05_04_03_02_01_00_u64; - let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64; - let mut buf : ~[u8] = ~[]; - let mut t = 0; - let stream_inc = &State(k0,k1); - let stream_full = &State(k0,k1); - - fn to_hex_str(r: &[u8, ..8]) -> ~str { - let mut s = ~""; - for vec::each(*r) |b| { - s += uint::to_str_radix(*b as uint, 16u); +#[cfg(test)] +mod tests { + use super::*; + use prelude::*; + + #[test] + fn test_siphash() { + let vecs : [[u8, ..8], ..64] = [ + [ 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, ], + [ 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, ], + [ 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, ], + [ 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, ], + [ 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, ], + [ 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, ], + [ 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, ], + [ 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, ], + [ 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, ], + [ 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, ], + [ 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, ], + [ 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, ], + [ 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, ], + [ 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, ], + [ 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, ], + [ 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, ], + [ 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, ], + [ 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, ], + [ 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, ], + [ 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, ], + [ 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, ], + [ 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, ], + [ 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, ], + [ 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, ], + [ 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, ], + [ 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, ], + [ 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, ], + [ 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, ], + [ 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, ], + [ 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, ], + [ 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, ], + [ 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, ], + [ 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, ], + [ 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, ], + [ 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, ], + [ 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, ], + [ 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, ], + [ 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, ], + [ 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, ], + [ 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, ], + [ 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, ], + [ 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, ], + [ 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, ], + [ 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, ], + [ 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, ], + [ 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, ], + [ 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, ], + [ 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, ], + [ 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, ], + [ 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, ], + [ 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, ], + [ 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, ], + [ 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, ], + [ 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, ], + [ 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, ], + [ 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, ], + [ 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, ], + [ 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, ], + [ 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, ], + [ 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, ], + [ 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, ], + [ 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, ], + [ 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, ], + [ 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, ] + ]; + + let k0 = 0x_07_06_05_04_03_02_01_00_u64; + let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08_u64; + let mut buf : ~[u8] = ~[]; + let mut t = 0; + let stream_inc = &State(k0,k1); + let stream_full = &State(k0,k1); + + fn to_hex_str(r: &[u8, ..8]) -> ~str { + let mut s = ~""; + for vec::each(*r) |b| { + s += uint::to_str_radix(*b as uint, 16u); + } + s } - s - } - while t < 64 { - debug!("siphash test %?", t); - let vec = u8to64_le!(vecs[t], 0); - let out = buf.hash_keyed(k0, k1); - debug!("got %?, expected %?", out, vec); - assert!(vec == out); + while t < 64 { + debug!("siphash test %?", t); + let vec = u8to64_le!(vecs[t], 0); + let out = buf.hash_keyed(k0, k1); + debug!("got %?, expected %?", out, vec); + assert!(vec == out); - stream_full.reset(); - stream_full.input(buf); - let f = stream_full.result_str(); - let i = stream_inc.result_str(); - let v = to_hex_str(&vecs[t]); - debug!("%d: (%s) => inc=%s full=%s", t, v, i, f); + stream_full.reset(); + stream_full.input(buf); + let f = stream_full.result_str(); + let i = stream_inc.result_str(); + let v = to_hex_str(&vecs[t]); + debug!("%d: (%s) => inc=%s full=%s", t, v, i, f); - assert!(f == i && f == v); + assert!(f == i && f == v); - buf += ~[t as u8]; - stream_inc.input(~[t as u8]); + buf += ~[t as u8]; + stream_inc.input(~[t as u8]); - t += 1; + t += 1; + } } -} -#[test] #[cfg(target_arch = "arm")] -pub fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!((val as u64).hash() != (val as uint).hash()); - assert!((val as u32).hash() == (val as uint).hash()); -} -#[test] #[cfg(target_arch = "x86_64")] -pub fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!((val as u64).hash() == (val as uint).hash()); - assert!((val as u32).hash() != (val as uint).hash()); -} -#[test] #[cfg(target_arch = "x86")] -pub fn test_hash_uint() { - let val = 0xdeadbeef_deadbeef_u64; - assert!((val as u64).hash() != (val as uint).hash()); - assert!((val as u32).hash() == (val as uint).hash()); -} + #[test] #[cfg(target_arch = "arm")] + fn test_hash_uint() { + let val = 0xdeadbeef_deadbeef_u64; + assert!((val as u64).hash() != (val as uint).hash()); + assert!((val as u32).hash() == (val as uint).hash()); + } + #[test] #[cfg(target_arch = "x86_64")] + fn test_hash_uint() { + let val = 0xdeadbeef_deadbeef_u64; + assert!((val as u64).hash() == (val as uint).hash()); + assert!((val as u32).hash() != (val as uint).hash()); + } + #[test] #[cfg(target_arch = "x86")] + fn test_hash_uint() { + let val = 0xdeadbeef_deadbeef_u64; + assert!((val as u64).hash() != (val as uint).hash()); + assert!((val as u32).hash() == (val as uint).hash()); + } -#[test] -pub fn test_hash_idempotent() { - let val64 = 0xdeadbeef_deadbeef_u64; - val64.hash() == val64.hash(); - let val32 = 0xdeadbeef_u32; - val32.hash() == val32.hash(); -} + #[test] + fn test_hash_idempotent() { + let val64 = 0xdeadbeef_deadbeef_u64; + val64.hash() == val64.hash(); + let val32 = 0xdeadbeef_u32; + val32.hash() == val32.hash(); + } -#[test] -pub fn test_hash_no_bytes_dropped_64() { - let val = 0xdeadbeef_deadbeef_u64; - - assert!(val.hash() != zero_byte(val, 0).hash()); - assert!(val.hash() != zero_byte(val, 1).hash()); - assert!(val.hash() != zero_byte(val, 2).hash()); - assert!(val.hash() != zero_byte(val, 3).hash()); - assert!(val.hash() != zero_byte(val, 4).hash()); - assert!(val.hash() != zero_byte(val, 5).hash()); - assert!(val.hash() != zero_byte(val, 6).hash()); - assert!(val.hash() != zero_byte(val, 7).hash()); - - fn zero_byte(val: u64, byte: uint) -> u64 { - assert!(byte < 8); - val & !(0xff << (byte * 8)) + #[test] + fn test_hash_no_bytes_dropped_64() { + let val = 0xdeadbeef_deadbeef_u64; + + assert!(val.hash() != zero_byte(val, 0).hash()); + assert!(val.hash() != zero_byte(val, 1).hash()); + assert!(val.hash() != zero_byte(val, 2).hash()); + assert!(val.hash() != zero_byte(val, 3).hash()); + assert!(val.hash() != zero_byte(val, 4).hash()); + assert!(val.hash() != zero_byte(val, 5).hash()); + assert!(val.hash() != zero_byte(val, 6).hash()); + assert!(val.hash() != zero_byte(val, 7).hash()); + + fn zero_byte(val: u64, byte: uint) -> u64 { + assert!(byte < 8); + val & !(0xff << (byte * 8)) + } } -} -#[test] -pub fn test_hash_no_bytes_dropped_32() { - let val = 0xdeadbeef_u32; + #[test] + fn test_hash_no_bytes_dropped_32() { + let val = 0xdeadbeef_u32; - assert!(val.hash() != zero_byte(val, 0).hash()); - assert!(val.hash() != zero_byte(val, 1).hash()); - assert!(val.hash() != zero_byte(val, 2).hash()); - assert!(val.hash() != zero_byte(val, 3).hash()); + assert!(val.hash() != zero_byte(val, 0).hash()); + assert!(val.hash() != zero_byte(val, 1).hash()); + assert!(val.hash() != zero_byte(val, 2).hash()); + assert!(val.hash() != zero_byte(val, 3).hash()); - fn zero_byte(val: u32, byte: uint) -> u32 { - assert!(byte < 4); - val & !(0xff << (byte * 8)) + fn zero_byte(val: u32, byte: uint) -> u32 { + assert!(byte < 4); + val & !(0xff << (byte * 8)) + } } -} +} \ No newline at end of file diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 9387ec4f43209..3efe21fc42cdb 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -13,1013 +13,1171 @@ //! The tables use a keyed hash with new random keys generated for each container, so the ordering //! of a set of keys in a hash table is randomized. -/// Open addressing with linear probing. -pub mod linear { - use container::{Container, Mutable, Map, Set}; - use cmp::{Eq, Equiv}; - use hash::Hash; - use to_bytes::IterBytes; - use iter::BaseIter; - use hash::Hash; - use iter; - use option::{None, Option, Some}; - use rand::RngUtil; - use rand; - use uint; - use vec; - use util::unreachable; +use container::{Container, Mutable, Map, Set}; +use cmp::{Eq, Equiv}; +use hash::Hash; +use to_bytes::IterBytes; +use iter::BaseIter; +use hash::Hash; +use iter; +use option::{None, Option, Some}; +use rand::RngUtil; +use rand; +use uint; +use vec; +use util::unreachable; + +static INITIAL_CAPACITY: uint = 32u; // 2^5 + +struct Bucket { + hash: uint, + key: K, + value: V, +} - static INITIAL_CAPACITY: uint = 32u; // 2^5 +pub struct HashMap { + priv k0: u64, + priv k1: u64, + priv resize_at: uint, + priv size: uint, + priv buckets: ~[Option>], +} - struct Bucket { - hash: uint, - key: K, - value: V, - } +// We could rewrite FoundEntry to have type Option<&Bucket> +// which would be nifty +enum SearchResult { + FoundEntry(uint), FoundHole(uint), TableFull +} - pub struct LinearMap { - priv k0: u64, - priv k1: u64, - priv resize_at: uint, - priv size: uint, - priv buckets: ~[Option>], - } +#[inline(always)] +fn resize_at(capacity: uint) -> uint { + ((capacity as float) * 3. / 4.) as uint +} - // We could rewrite FoundEntry to have type Option<&Bucket> - // which would be nifty - enum SearchResult { - FoundEntry(uint), FoundHole(uint), TableFull +pub fn linear_map_with_capacity( + initial_capacity: uint) -> HashMap { + let r = rand::task_rng(); + linear_map_with_capacity_and_keys(r.gen_u64(), r.gen_u64(), + initial_capacity) +} + +fn linear_map_with_capacity_and_keys( + k0: u64, k1: u64, + initial_capacity: uint) -> HashMap { + HashMap { + k0: k0, k1: k1, + resize_at: resize_at(initial_capacity), + size: 0, + buckets: vec::from_fn(initial_capacity, |_| None) } +} +priv impl HashMap { #[inline(always)] - fn resize_at(capacity: uint) -> uint { - ((capacity as float) * 3. / 4.) as uint + fn to_bucket(&self, h: uint) -> uint { + // A good hash function with entropy spread over all of the + // bits is assumed. SipHash is more than good enough. + h % self.buckets.len() } - pub fn linear_map_with_capacity( - initial_capacity: uint) -> LinearMap { - let r = rand::task_rng(); - linear_map_with_capacity_and_keys(r.gen_u64(), r.gen_u64(), - initial_capacity) + #[inline(always)] + fn next_bucket(&self, idx: uint, len_buckets: uint) -> uint { + let n = (idx + 1) % len_buckets; + debug!("next_bucket(%?, %?) = %?", idx, len_buckets, n); + n } - fn linear_map_with_capacity_and_keys( - k0: u64, k1: u64, - initial_capacity: uint) -> LinearMap { - LinearMap { - k0: k0, k1: k1, - resize_at: resize_at(initial_capacity), - size: 0, - buckets: vec::from_fn(initial_capacity, |_| None) + #[inline(always)] + fn bucket_sequence(&self, hash: uint, + op: &fn(uint) -> bool) -> uint { + let start_idx = self.to_bucket(hash); + let len_buckets = self.buckets.len(); + let mut idx = start_idx; + loop { + if !op(idx) { + return idx; + } + idx = self.next_bucket(idx, len_buckets); + if idx == start_idx { + return start_idx; + } } } - priv impl LinearMap { - #[inline(always)] - fn to_bucket(&self, h: uint) -> uint { - // A good hash function with entropy spread over all of the - // bits is assumed. SipHash is more than good enough. - h % self.buckets.len() - } + #[inline(always)] + fn bucket_for_key(&self, k: &K) -> SearchResult { + let hash = k.hash_keyed(self.k0, self.k1) as uint; + self.bucket_for_key_with_hash(hash, k) + } - #[inline(always)] - fn next_bucket(&self, idx: uint, len_buckets: uint) -> uint { - let n = (idx + 1) % len_buckets; - debug!("next_bucket(%?, %?) = %?", idx, len_buckets, n); - n - } + #[inline(always)] + fn bucket_for_key_equiv>(&self, + k: &Q) + -> SearchResult { + let hash = k.hash_keyed(self.k0, self.k1) as uint; + self.bucket_for_key_with_hash_equiv(hash, k) + } - #[inline(always)] - fn bucket_sequence(&self, hash: uint, - op: &fn(uint) -> bool) -> uint { - let start_idx = self.to_bucket(hash); - let len_buckets = self.buckets.len(); - let mut idx = start_idx; - loop { - if !op(idx) { - return idx; - } - idx = self.next_bucket(idx, len_buckets); - if idx == start_idx { - return start_idx; - } + #[inline(always)] + fn bucket_for_key_with_hash(&self, + hash: uint, + k: &K) + -> SearchResult { + let _ = for self.bucket_sequence(hash) |i| { + match self.buckets[i] { + Some(ref bkt) => if bkt.hash == hash && *k == bkt.key { + return FoundEntry(i); + }, + None => return FoundHole(i) } - } - - #[inline(always)] - fn bucket_for_key(&self, k: &K) -> SearchResult { - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.bucket_for_key_with_hash(hash, k) - } - - #[inline(always)] - fn bucket_for_key_equiv>(&self, - k: &Q) - -> SearchResult { - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.bucket_for_key_with_hash_equiv(hash, k) - } + }; + TableFull + } - #[inline(always)] - fn bucket_for_key_with_hash(&self, - hash: uint, - k: &K) - -> SearchResult { - let _ = for self.bucket_sequence(hash) |i| { - match self.buckets[i] { - Some(ref bkt) => if bkt.hash == hash && *k == bkt.key { + #[inline(always)] + fn bucket_for_key_with_hash_equiv>(&self, + hash: uint, + k: &Q) + -> SearchResult { + let _ = for self.bucket_sequence(hash) |i| { + match self.buckets[i] { + Some(ref bkt) => { + if bkt.hash == hash && k.equiv(&bkt.key) { return FoundEntry(i); - }, - None => return FoundHole(i) - } - }; - TableFull - } + } + }, + None => return FoundHole(i) + } + }; + TableFull + } - #[inline(always)] - fn bucket_for_key_with_hash_equiv>(&self, - hash: uint, - k: &Q) - -> SearchResult { - let _ = for self.bucket_sequence(hash) |i| { - match self.buckets[i] { - Some(ref bkt) => { - if bkt.hash == hash && k.equiv(&bkt.key) { - return FoundEntry(i); - } - }, - None => return FoundHole(i) - } - }; - TableFull - } + /// Expand the capacity of the array to the next power of two + /// and re-insert each of the existing buckets. + #[inline(always)] + fn expand(&mut self) { + let new_capacity = self.buckets.len() * 2; + self.resize(new_capacity); + } - /// Expand the capacity of the array to the next power of two - /// and re-insert each of the existing buckets. - #[inline(always)] - fn expand(&mut self) { - let new_capacity = self.buckets.len() * 2; - self.resize(new_capacity); - } + /// Expands the capacity of the array and re-insert each of the + /// existing buckets. + fn resize(&mut self, new_capacity: uint) { + let old_capacity = self.buckets.len(); + self.resize_at = resize_at(new_capacity); - /// Expands the capacity of the array and re-insert each of the - /// existing buckets. - fn resize(&mut self, new_capacity: uint) { - let old_capacity = self.buckets.len(); - self.resize_at = resize_at(new_capacity); + let mut old_buckets = vec::from_fn(new_capacity, |_| None); + self.buckets <-> old_buckets; - let mut old_buckets = vec::from_fn(new_capacity, |_| None); - self.buckets <-> old_buckets; + self.size = 0; + for uint::range(0, old_capacity) |i| { + let mut bucket = None; + bucket <-> old_buckets[i]; + self.insert_opt_bucket(bucket); + } + } - self.size = 0; - for uint::range(0, old_capacity) |i| { - let mut bucket = None; - bucket <-> old_buckets[i]; - self.insert_opt_bucket(bucket); + fn insert_opt_bucket(&mut self, bucket: Option>) { + match bucket { + Some(Bucket{hash: hash, key: key, value: value}) => { + self.insert_internal(hash, key, value); } + None => {} } + } - fn insert_opt_bucket(&mut self, bucket: Option>) { - match bucket { - Some(Bucket{hash: hash, key: key, value: value}) => { - self.insert_internal(hash, key, value); - } - None => {} - } + #[cfg(stage0)] + #[inline(always)] + fn value_for_bucket(&self, idx: uint) -> &'self V { + match self.buckets[idx] { + Some(ref bkt) => &bkt.value, + None => fail!(~"HashMap::find: internal logic error"), } + } - #[inline(always)] - fn value_for_bucket(&self, idx: uint) -> &'self V { - match self.buckets[idx] { - Some(ref bkt) => &bkt.value, - None => fail!(~"LinearMap::find: internal logic error"), - } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V { + match self.buckets[idx] { + Some(ref bkt) => &bkt.value, + None => fail!(~"HashMap::find: internal logic error"), } + } - #[inline(always)] - fn mut_value_for_bucket(&mut self, idx: uint) -> &'self mut V { - match self.buckets[idx] { - Some(ref mut bkt) => &mut bkt.value, - None => unreachable() - } + #[cfg(stage0)] + #[inline(always)] + fn mut_value_for_bucket(&mut self, idx: uint) -> &'self mut V { + match self.buckets[idx] { + Some(ref mut bkt) => &mut bkt.value, + None => unreachable() } + } - /// Inserts the key value pair into the buckets. - /// Assumes that there will be a bucket. - /// True if there was no previous entry with that key - fn insert_internal(&mut self, hash: uint, k: K, v: V) -> bool { - match self.bucket_for_key_with_hash(hash, &k) { - TableFull => { fail!(~"Internal logic error"); } - FoundHole(idx) => { - debug!("insert fresh (%?->%?) at idx %?, hash %?", - k, v, idx, hash); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - true - } - FoundEntry(idx) => { - debug!("insert overwrite (%?->%?) at idx %?, hash %?", - k, v, idx, hash); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - false - } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V { + match self.buckets[idx] { + Some(ref mut bkt) => &mut bkt.value, + None => unreachable() + } + } + + /// Inserts the key value pair into the buckets. + /// Assumes that there will be a bucket. + /// True if there was no previous entry with that key + fn insert_internal(&mut self, hash: uint, k: K, v: V) -> bool { + match self.bucket_for_key_with_hash(hash, &k) { + TableFull => { fail!(~"Internal logic error"); } + FoundHole(idx) => { + debug!("insert fresh (%?->%?) at idx %?, hash %?", + k, v, idx, hash); + self.buckets[idx] = Some(Bucket{hash: hash, key: k, + value: v}); + self.size += 1; + true + } + FoundEntry(idx) => { + debug!("insert overwrite (%?->%?) at idx %?, hash %?", + k, v, idx, hash); + self.buckets[idx] = Some(Bucket{hash: hash, key: k, + value: v}); + false } } + } - fn pop_internal(&mut self, hash: uint, k: &K) -> Option { - // Removing from an open-addressed hashtable - // is, well, painful. The problem is that - // the entry may lie on the probe path for other - // entries, so removing it would make you think that - // those probe paths are empty. - // - // To address this we basically have to keep walking, - // re-inserting entries we find until we reach an empty - // bucket. We know we will eventually reach one because - // we insert one ourselves at the beginning (the removed - // entry). - // - // I found this explanation elucidating: - // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf - let mut idx = match self.bucket_for_key_with_hash(hash, k) { - TableFull | FoundHole(_) => return None, - FoundEntry(idx) => idx - }; - - let len_buckets = self.buckets.len(); + fn pop_internal(&mut self, hash: uint, k: &K) -> Option { + // Removing from an open-addressed hashtable + // is, well, painful. The problem is that + // the entry may lie on the probe path for other + // entries, so removing it would make you think that + // those probe paths are empty. + // + // To address this we basically have to keep walking, + // re-inserting entries we find until we reach an empty + // bucket. We know we will eventually reach one because + // we insert one ourselves at the beginning (the removed + // entry). + // + // I found this explanation elucidating: + // http://www.maths.lse.ac.uk/Courses/MA407/del-hash.pdf + let mut idx = match self.bucket_for_key_with_hash(hash, k) { + TableFull | FoundHole(_) => return None, + FoundEntry(idx) => idx + }; + + let len_buckets = self.buckets.len(); + let mut bucket = None; + self.buckets[idx] <-> bucket; + + let value = match bucket { + None => None, + Some(bucket) => { + let Bucket{value: value, _} = bucket; + Some(value) + }, + }; + + /* re-inserting buckets may cause changes in size, so remember + what our new size is ahead of time before we start insertions */ + let size = self.size - 1; + idx = self.next_bucket(idx, len_buckets); + while self.buckets[idx].is_some() { let mut bucket = None; - self.buckets[idx] <-> bucket; - - let value = match bucket { - None => None, - Some(bucket) => { - let Bucket{value: value, _} = bucket; - Some(value) - }, - }; - - /* re-inserting buckets may cause changes in size, so remember - what our new size is ahead of time before we start insertions */ - let size = self.size - 1; + bucket <-> self.buckets[idx]; + self.insert_opt_bucket(bucket); idx = self.next_bucket(idx, len_buckets); - while self.buckets[idx].is_some() { - let mut bucket = None; - bucket <-> self.buckets[idx]; - self.insert_opt_bucket(bucket); - idx = self.next_bucket(idx, len_buckets); - } - self.size = size; - - value } + self.size = size; - fn search(&self, hash: uint, - op: &fn(x: &Option>) -> bool) { - let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i])); - } + value } - impl<'self,K:Hash + IterBytes + Eq,V> - BaseIter<(&'self K, &'self V)> for LinearMap { - /// Visit all key-value pairs - fn each(&self, blk: &fn(&(&'self K, &'self V)) -> bool) { - for uint::range(0, self.buckets.len()) |i| { - let mut broke = false; - do self.buckets[i].map |bucket| { - if !blk(&(&bucket.key, &bucket.value)) { - broke = true; // FIXME(#3064) just write "break;" - } - }; - if broke { break; } - } - } - fn size_hint(&self) -> Option { Some(self.len()) } + fn search(&self, hash: uint, + op: &fn(x: &Option>) -> bool) { + let _ = self.bucket_sequence(hash, |i| op(&self.buckets[i])); } +} +impl Container for HashMap { + /// Return the number of elements in the map + fn len(&const self) -> uint { self.size } - impl Container for LinearMap { - /// Return the number of elements in the map - fn len(&const self) -> uint { self.size } + /// Return true if the map contains no elements + fn is_empty(&const self) -> bool { self.len() == 0 } +} - /// Return true if the map contains no elements - fn is_empty(&const self) -> bool { self.len() == 0 } +impl Mutable for HashMap { + /// Clear the map, removing all key-value pairs. + fn clear(&mut self) { + for uint::range(0, self.buckets.len()) |idx| { + self.buckets[idx] = None; + } + self.size = 0; } +} - impl Mutable for LinearMap { - /// Clear the map, removing all key-value pairs. - fn clear(&mut self) { - for uint::range(0, self.buckets.len()) |idx| { - self.buckets[idx] = None; - } - self.size = 0; +impl Map for HashMap { + /// Return true if the map contains a value for the specified key + fn contains_key(&self, k: &K) -> bool { + match self.bucket_for_key(k) { + FoundEntry(_) => {true} + TableFull | FoundHole(_) => {false} } } - impl<'self,K:Hash + IterBytes + Eq,V> Map for LinearMap { - /// Return true if the map contains a value for the specified key - fn contains_key(&self, k: &K) -> bool { - match self.bucket_for_key(k) { - FoundEntry(_) => {true} - TableFull | FoundHole(_) => {false} + /// Visit all key-value pairs + #[cfg(stage0)] + fn each(&self, blk: &fn(&'self K, &'self V) -> bool) { + for uint::range(0, self.buckets.len()) |i| { + for self.buckets[i].each |bucket| { + if !blk(&bucket.key, &bucket.value) { + return; + } } } + } - /// Visit all keys - fn each_key(&self, blk: &fn(k: &K) -> bool) { - self.each(|&(k, _)| blk(k)) - } - - /// Visit all values - fn each_value(&self, blk: &fn(v: &V) -> bool) { - self.each(|&(_, v)| blk(v)) - } - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, blk: &fn(&'self K, - &'self mut V) -> bool) { - for uint::range(0, self.buckets.len()) |i| { - match self.buckets[i] { - Some(Bucket{key: ref key, value: ref mut value, _}) => { - if !blk(key, value) { return } - } - None => () + /// Visit all key-value pairs + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each<'a>(&'a self, blk: &fn(&'a K, &'a V) -> bool) { + for uint::range(0, self.buckets.len()) |i| { + for self.buckets[i].each |bucket| { + if !blk(&bucket.key, &bucket.value) { + return; } } } + } - /// Return a reference to the value corresponding to the key - fn find(&self, k: &K) -> Option<&'self V> { - match self.bucket_for_key(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } - } + /// Visit all keys + fn each_key(&self, blk: &fn(k: &K) -> bool) { + self.each(|k, _| blk(k)) + } - /// Return a mutable reference to the value corresponding to the key - fn find_mut(&mut self, k: &K) -> Option<&'self mut V> { - let idx = match self.bucket_for_key(k) { - FoundEntry(idx) => idx, - TableFull | FoundHole(_) => return None - }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx))) - } - } + /// Visit all values + #[cfg(stage0)] + fn each_value(&self, blk: &fn(v: &V) -> bool) { + self.each(|_, v| blk(v)) + } - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - fn insert(&mut self, k: K, v: V) -> bool { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } + /// Visit all values + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) { + self.each(|_, v| blk(v)) + } - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.insert_internal(hash, k, v) + /// Iterate over the map and mutate the contained values + fn mutate_values(&mut self, blk: &fn(&K, &mut V) -> bool) { + for uint::range(0, self.buckets.len()) |i| { + match self.buckets[i] { + Some(Bucket{key: ref key, value: ref mut value, _}) => { + if !blk(key, value) { return } + } + None => () + } } + } - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - fn remove(&mut self, k: &K) -> bool { - self.pop(k).is_some() + /// Return a reference to the value corresponding to the key + #[cfg(stage0)] + fn find(&self, k: &K) -> Option<&'self V> { + match self.bucket_for_key(k) { + FoundEntry(idx) => Some(self.value_for_bucket(idx)), + TableFull | FoundHole(_) => None, } } - pub impl LinearMap { - /// Create an empty LinearMap - fn new() -> LinearMap { - LinearMap::with_capacity(INITIAL_CAPACITY) + /// Return a reference to the value corresponding to the key + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn find<'a>(&'a self, k: &K) -> Option<&'a V> { + match self.bucket_for_key(k) { + FoundEntry(idx) => Some(self.value_for_bucket(idx)), + TableFull | FoundHole(_) => None, } + } - /// Create an empty LinearMap with space for at least `n` elements in - /// the hash table. - fn with_capacity(capacity: uint) -> LinearMap { - linear_map_with_capacity(capacity) + /// Return a mutable reference to the value corresponding to the key + #[cfg(stage0)] + fn find_mut(&mut self, k: &K) -> Option<&'self mut V> { + let idx = match self.bucket_for_key(k) { + FoundEntry(idx) => idx, + TableFull | FoundHole(_) => return None + }; + unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx))) } + } - /// Reserve space for at least `n` elements in the hash table. - fn reserve_at_least(&mut self, n: uint) { - if n > self.buckets.len() { - let buckets = n * 4 / 3 + 1; - self.resize(uint::next_power_of_two(buckets)); - } + /// Return a mutable reference to the value corresponding to the key + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { + let idx = match self.bucket_for_key(k) { + FoundEntry(idx) => idx, + TableFull | FoundHole(_) => return None + }; + unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx))) } + } - fn pop(&mut self, k: &K) -> Option { - let hash = k.hash_keyed(self.k0, self.k1) as uint; - self.pop_internal(hash, k) - } + /// Insert a key-value pair into the map. An existing value for a + /// key is replaced by the new value. Return true if the key did + /// not already exist in the map. + fn insert(&mut self, k: K, v: V) -> bool { + if self.size >= self.resize_at { + // n.b.: We could also do this after searching, so + // that we do not resize if this call to insert is + // simply going to update a key in place. My sense + // though is that it's worse to have to search through + // buckets to find the right spot twice than to just + // resize in this corner case. + self.expand(); + } + + let hash = k.hash_keyed(self.k0, self.k1) as uint; + self.insert_internal(hash, k, v) + } - fn swap(&mut self, k: K, v: V) -> Option { - // this could be faster. - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let old_value = self.pop_internal(hash, &k); - - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } + /// Remove a key-value pair from the map. Return true if the key + /// was present in the map, otherwise false. + fn remove(&mut self, k: &K) -> bool { + self.pop(k).is_some() + } +} + +pub impl HashMap { + /// Create an empty HashMap + fn new() -> HashMap { + HashMap::with_capacity(INITIAL_CAPACITY) + } - self.insert_internal(hash, k, v); + /// Create an empty HashMap with space for at least `n` elements in + /// the hash table. + fn with_capacity(capacity: uint) -> HashMap { + linear_map_with_capacity(capacity) + } - old_value + /// Reserve space for at least `n` elements in the hash table. + fn reserve_at_least(&mut self, n: uint) { + if n > self.buckets.len() { + let buckets = n * 4 / 3 + 1; + self.resize(uint::next_power_of_two(buckets)); } + } - /// Return the value corresponding to the key in the map, or insert - /// and return the value if it doesn't exist. - fn find_or_insert(&mut self, k: K, v: V) -> &'self V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } + fn pop(&mut self, k: &K) -> Option { + let hash = k.hash_keyed(self.k0, self.k1) as uint; + self.pop_internal(hash, k) + } - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!(~"Internal logic error"), - FoundEntry(idx) => idx, - FoundHole(idx) => { - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; + fn swap(&mut self, k: K, v: V) -> Option { + // this could be faster. + let hash = k.hash_keyed(self.k0, self.k1) as uint; + let old_value = self.pop_internal(hash, &k); - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } + if self.size >= self.resize_at { + // n.b.: We could also do this after searching, so + // that we do not resize if this call to insert is + // simply going to update a key in place. My sense + // though is that it's worse to have to search through + // buckets to find the right spot twice than to just + // resize in this corner case. + self.expand(); } - /// Return the value corresponding to the key in the map, or create, - /// insert, and return a new value if it doesn't exist. - fn find_or_insert_with(&mut self, k: K, f: &fn(&K) -> V) -> &'self V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!(~"Internal logic error"), - FoundEntry(idx) => idx, - FoundHole(idx) => { - let v = f(&k); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; + self.insert_internal(hash, k, v); - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } - } + old_value + } - fn consume(&mut self, f: &fn(K, V)) { - let mut buckets = ~[]; - self.buckets <-> buckets; - self.size = 0; - - do vec::consume(buckets) |_, bucket| { - match bucket { - None => {}, - Some(bucket) => { - let Bucket{key: key, value: value, _} = bucket; - f(key, value) - } - } - } + /// Return the value corresponding to the key in the map, or insert + /// and return the value if it doesn't exist. + #[cfg(stage0)] + fn find_or_insert(&mut self, k: K, v: V) -> &'self V { + if self.size >= self.resize_at { + // n.b.: We could also do this after searching, so + // that we do not resize if this call to insert is + // simply going to update a key in place. My sense + // though is that it's worse to have to search through + // buckets to find the right spot twice than to just + // resize in this corner case. + self.expand(); + } + + let hash = k.hash_keyed(self.k0, self.k1) as uint; + let idx = match self.bucket_for_key_with_hash(hash, &k) { + TableFull => fail!(~"Internal logic error"), + FoundEntry(idx) => idx, + FoundHole(idx) => { + self.buckets[idx] = Some(Bucket{hash: hash, key: k, + value: v}); + self.size += 1; + idx + }, + }; + + unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + ::cast::transmute_region(self.value_for_bucket(idx)) } + } - fn get(&self, k: &K) -> &'self V { - match self.find(k) { - Some(v) => v, - None => fail!(fmt!("No entry found for key: %?", k)), - } + /// Return the value corresponding to the key in the map, or insert + /// and return the value if it doesn't exist. + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V { + if self.size >= self.resize_at { + // n.b.: We could also do this after searching, so + // that we do not resize if this call to insert is + // simply going to update a key in place. My sense + // though is that it's worse to have to search through + // buckets to find the right spot twice than to just + // resize in this corner case. + self.expand(); + } + + let hash = k.hash_keyed(self.k0, self.k1) as uint; + let idx = match self.bucket_for_key_with_hash(hash, &k) { + TableFull => fail!(~"Internal logic error"), + FoundEntry(idx) => idx, + FoundHole(idx) => { + self.buckets[idx] = Some(Bucket{hash: hash, key: k, + value: v}); + self.size += 1; + idx + }, + }; + + unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + ::cast::transmute_region(self.value_for_bucket(idx)) } + } - /// Return true if the map contains a value for the specified key, - /// using equivalence - fn contains_key_equiv>(&self, key: &Q) - -> bool { - match self.bucket_for_key_equiv(key) { - FoundEntry(_) => {true} - TableFull | FoundHole(_) => {false} - } + /// Return the value corresponding to the key in the map, or create, + /// insert, and return a new value if it doesn't exist. + #[cfg(stage0)] + fn find_or_insert_with(&mut self, k: K, f: &fn(&K) -> V) -> &'self V { + if self.size >= self.resize_at { + // n.b.: We could also do this after searching, so + // that we do not resize if this call to insert is + // simply going to update a key in place. My sense + // though is that it's worse to have to search through + // buckets to find the right spot twice than to just + // resize in this corner case. + self.expand(); + } + + let hash = k.hash_keyed(self.k0, self.k1) as uint; + let idx = match self.bucket_for_key_with_hash(hash, &k) { + TableFull => fail!(~"Internal logic error"), + FoundEntry(idx) => idx, + FoundHole(idx) => { + let v = f(&k); + self.buckets[idx] = Some(Bucket{hash: hash, key: k, + value: v}); + self.size += 1; + idx + }, + }; + + unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + ::cast::transmute_region(self.value_for_bucket(idx)) } + } - /// Return the value corresponding to the key in the map, using - /// equivalence - fn find_equiv>(&self, k: &Q) - -> Option<&'self V> { - match self.bucket_for_key_equiv(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } + /// Return the value corresponding to the key in the map, or create, + /// insert, and return a new value if it doesn't exist. + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a V { + if self.size >= self.resize_at { + // n.b.: We could also do this after searching, so + // that we do not resize if this call to insert is + // simply going to update a key in place. My sense + // though is that it's worse to have to search through + // buckets to find the right spot twice than to just + // resize in this corner case. + self.expand(); + } + + let hash = k.hash_keyed(self.k0, self.k1) as uint; + let idx = match self.bucket_for_key_with_hash(hash, &k) { + TableFull => fail!(~"Internal logic error"), + FoundEntry(idx) => idx, + FoundHole(idx) => { + let v = f(&k); + self.buckets[idx] = Some(Bucket{hash: hash, key: k, + value: v}); + self.size += 1; + idx + }, + }; + + unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker + ::cast::transmute_region(self.value_for_bucket(idx)) } } - impl Eq for LinearMap { - fn eq(&self, other: &LinearMap) -> bool { - if self.len() != other.len() { return false; } + fn consume(&mut self, f: &fn(K, V)) { + let mut buckets = ~[]; + self.buckets <-> buckets; + self.size = 0; - for self.each |&(key, value)| { - match other.find(key) { - None => return false, - Some(v) => if value != v { return false }, + do vec::consume(buckets) |_, bucket| { + match bucket { + None => {}, + Some(bucket) => { + let Bucket{key: key, value: value, _} = bucket; + f(key, value) } } + } + } - true + #[cfg(stage0)] + fn get(&self, k: &K) -> &'self V { + match self.find(k) { + Some(v) => v, + None => fail!(fmt!("No entry found for key: %?", k)), } + } - fn ne(&self, other: &LinearMap) -> bool { !self.eq(other) } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get<'a>(&'a self, k: &K) -> &'a V { + match self.find(k) { + Some(v) => v, + None => fail!(fmt!("No entry found for key: %?", k)), + } } - pub struct LinearSet { - priv map: LinearMap + /// Return true if the map contains a value for the specified key, + /// using equivalence + fn contains_key_equiv>(&self, key: &Q) + -> bool { + match self.bucket_for_key_equiv(key) { + FoundEntry(_) => {true} + TableFull | FoundHole(_) => {false} + } } - impl BaseIter for LinearSet { - /// Visit all values in order - fn each(&self, f: &fn(&T) -> bool) { self.map.each_key(f) } - fn size_hint(&self) -> Option { Some(self.len()) } + /// Return the value corresponding to the key in the map, using + /// equivalence + #[cfg(stage0)] + fn find_equiv>(&self, k: &Q) + -> Option<&'self V> { + match self.bucket_for_key_equiv(k) { + FoundEntry(idx) => Some(self.value_for_bucket(idx)), + TableFull | FoundHole(_) => None, + } } - impl Eq for LinearSet { - fn eq(&self, other: &LinearSet) -> bool { self.map == other.map } - fn ne(&self, other: &LinearSet) -> bool { self.map != other.map } + /// Return the value corresponding to the key in the map, using + /// equivalence + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn find_equiv<'a, Q:Hash + IterBytes + Equiv>( + &'a self, k: &Q) -> Option<&'a V> + { + match self.bucket_for_key_equiv(k) { + FoundEntry(idx) => Some(self.value_for_bucket(idx)), + TableFull | FoundHole(_) => None, + } } +} - impl Container for LinearSet { - /// Return the number of elements in the set - fn len(&const self) -> uint { self.map.len() } +impl Eq for HashMap { + fn eq(&self, other: &HashMap) -> bool { + if self.len() != other.len() { return false; } - /// Return true if the set contains no elements - fn is_empty(&const self) -> bool { self.map.is_empty() } - } + for self.each |key, value| { + match other.find(key) { + None => return false, + Some(v) => if value != v { return false }, + } + } - impl Mutable for LinearSet { - /// Clear the set, removing all values. - fn clear(&mut self) { self.map.clear() } + true } - impl Set for LinearSet { - /// Return true if the set contains a value - fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } + fn ne(&self, other: &HashMap) -> bool { !self.eq(other) } +} - /// Add a value to the set. Return true if the value was not already - /// present in the set. - fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } +pub struct HashSet { + priv map: HashMap +} - /// Remove a value from the set. Return true if the value was - /// present in the set. - fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } +impl BaseIter for HashSet { + /// Visit all values in order + fn each(&self, f: &fn(&T) -> bool) { self.map.each_key(f) } + fn size_hint(&self) -> Option { Some(self.len()) } +} - /// Return true if the set has no elements in common with `other`. - /// This is equivalent to checking for an empty intersection. - fn is_disjoint(&self, other: &LinearSet) -> bool { - iter::all(self, |v| !other.contains(v)) - } +impl Eq for HashSet { + fn eq(&self, other: &HashSet) -> bool { self.map == other.map } + fn ne(&self, other: &HashSet) -> bool { self.map != other.map } +} - /// Return true if the set is a subset of another - fn is_subset(&self, other: &LinearSet) -> bool { - iter::all(self, |v| other.contains(v)) - } +impl Container for HashSet { + /// Return the number of elements in the set + fn len(&const self) -> uint { self.map.len() } - /// Return true if the set is a superset of another - fn is_superset(&self, other: &LinearSet) -> bool { - other.is_subset(self) - } + /// Return true if the set contains no elements + fn is_empty(&const self) -> bool { self.map.is_empty() } +} - /// Visit the values representing the difference - fn difference(&self, other: &LinearSet, f: &fn(&T) -> bool) { - for self.each |v| { - if !other.contains(v) { - if !f(v) { return } - } - } - } +impl Mutable for HashSet { + /// Clear the set, removing all values. + fn clear(&mut self) { self.map.clear() } +} - /// Visit the values representing the symmetric difference - fn symmetric_difference(&self, - other: &LinearSet, - f: &fn(&T) -> bool) { - self.difference(other, f); - other.difference(self, f); - } +impl Set for HashSet { + /// Return true if the set contains a value + fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } - /// Visit the values representing the intersection - fn intersection(&self, other: &LinearSet, f: &fn(&T) -> bool) { - for self.each |v| { - if other.contains(v) { - if !f(v) { return } - } - } - } + /// Add a value to the set. Return true if the value was not already + /// present in the set. + fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } - /// Visit the values representing the union - fn union(&self, other: &LinearSet, f: &fn(&T) -> bool) { - for self.each |v| { + /// Remove a value from the set. Return true if the value was + /// present in the set. + fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } + + /// Return true if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + fn is_disjoint(&self, other: &HashSet) -> bool { + iter::all(self, |v| !other.contains(v)) + } + + /// Return true if the set is a subset of another + fn is_subset(&self, other: &HashSet) -> bool { + iter::all(self, |v| other.contains(v)) + } + + /// Return true if the set is a superset of another + fn is_superset(&self, other: &HashSet) -> bool { + other.is_subset(self) + } + + /// Visit the values representing the difference + fn difference(&self, other: &HashSet, f: &fn(&T) -> bool) { + for self.each |v| { + if !other.contains(v) { if !f(v) { return } } + } + } - for other.each |v| { - if !self.contains(v) { - if !f(v) { return } - } + /// Visit the values representing the symmetric difference + fn symmetric_difference(&self, + other: &HashSet, + f: &fn(&T) -> bool) { + self.difference(other, f); + other.difference(self, f); + } + + /// Visit the values representing the intersection + fn intersection(&self, other: &HashSet, f: &fn(&T) -> bool) { + for self.each |v| { + if other.contains(v) { + if !f(v) { return } } } } - pub impl LinearSet { - /// Create an empty LinearSet - fn new() -> LinearSet { - LinearSet::with_capacity(INITIAL_CAPACITY) + /// Visit the values representing the union + fn union(&self, other: &HashSet, f: &fn(&T) -> bool) { + for self.each |v| { + if !f(v) { return } } - /// Create an empty LinearSet with space for at least `n` elements in - /// the hash table. - fn with_capacity(capacity: uint) -> LinearSet { - LinearSet { map: LinearMap::with_capacity(capacity) } + for other.each |v| { + if !self.contains(v) { + if !f(v) { return } + } } + } +} - /// Reserve space for at least `n` elements in the hash table. - fn reserve_at_least(&mut self, n: uint) { - self.map.reserve_at_least(n) - } +pub impl HashSet { + /// Create an empty HashSet + fn new() -> HashSet { + HashSet::with_capacity(INITIAL_CAPACITY) + } - /// Consumes all of the elements in the set, emptying it out - fn consume(&mut self, f: &fn(T)) { - self.map.consume(|k, _| f(k)) - } + /// Create an empty HashSet with space for at least `n` elements in + /// the hash table. + fn with_capacity(capacity: uint) -> HashSet { + HashSet { map: HashMap::with_capacity(capacity) } } + /// Reserve space for at least `n` elements in the hash table. + fn reserve_at_least(&mut self, n: uint) { + self.map.reserve_at_least(n) + } + + /// Consumes all of the elements in the set, emptying it out + fn consume(&mut self, f: &fn(T)) { + self.map.consume(|k, _| f(k)) + } +} + +#[test] +mod test_map { + use container::{Container, Map, Set}; + use option::{None, Some}; + use super::*; + use uint; + #[test] - mod test_map { - use container::{Container, Map, Set}; - use option::{None, Some}; - use hashmap::linear::LinearMap; - use hashmap::linear; - use uint; - - #[test] - pub fn test_insert() { - let mut m = LinearMap::new(); - assert!(m.insert(1, 2)); - assert!(m.insert(2, 4)); - assert!(*m.get(&1) == 2); - assert!(*m.get(&2) == 4); - } + fn test_insert() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2)); + assert!(m.insert(2, 4)); + assert!(*m.get(&1) == 2); + assert!(*m.get(&2) == 4); + } - #[test] - fn test_find_mut() { - let mut m = LinearMap::new(); - assert!(m.insert(1, 12)); - assert!(m.insert(2, 8)); - assert!(m.insert(5, 14)); - let new = 100; - match m.find_mut(&5) { - None => fail!(), Some(x) => *x = new - } - assert_eq!(m.find(&5), Some(&new)); - } + #[test] + fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12)); + assert!(m.insert(2, 8)); + assert!(m.insert(5, 14)); + let new = 100; + match m.find_mut(&5) { + None => fail!(), Some(x) => *x = new + } + assert_eq!(m.find(&5), Some(&new)); + } - #[test] - pub fn test_insert_overwrite() { - let mut m = LinearMap::new(); - assert!(m.insert(1, 2)); - assert!(*m.get(&1) == 2); - assert!(!m.insert(1, 3)); - assert!(*m.get(&1) == 3); - } + #[test] + fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2)); + assert!(*m.get(&1) == 2); + assert!(!m.insert(1, 3)); + assert!(*m.get(&1) == 3); + } - #[test] - pub fn test_insert_conflicts() { - let mut m = linear::linear_map_with_capacity(4); - assert!(m.insert(1, 2)); - assert!(m.insert(5, 3)); - assert!(m.insert(9, 4)); - assert!(*m.get(&9) == 4); - assert!(*m.get(&5) == 3); - assert!(*m.get(&1) == 2); - } + #[test] + fn test_insert_conflicts() { + let mut m = linear_map_with_capacity(4); + assert!(m.insert(1, 2)); + assert!(m.insert(5, 3)); + assert!(m.insert(9, 4)); + assert!(*m.get(&9) == 4); + assert!(*m.get(&5) == 3); + assert!(*m.get(&1) == 2); + } - #[test] - pub fn test_conflict_remove() { - let mut m = linear::linear_map_with_capacity(4); - assert!(m.insert(1, 2)); - assert!(m.insert(5, 3)); - assert!(m.insert(9, 4)); - assert!(m.remove(&1)); - assert!(*m.get(&9) == 4); - assert!(*m.get(&5) == 3); - } + #[test] + fn test_conflict_remove() { + let mut m = linear_map_with_capacity(4); + assert!(m.insert(1, 2)); + assert!(m.insert(5, 3)); + assert!(m.insert(9, 4)); + assert!(m.remove(&1)); + assert!(*m.get(&9) == 4); + assert!(*m.get(&5) == 3); + } - #[test] - pub fn test_is_empty() { - let mut m = linear::linear_map_with_capacity(4); - assert!(m.insert(1, 2)); - assert!(!m.is_empty()); - assert!(m.remove(&1)); - assert!(m.is_empty()); - } + #[test] + fn test_is_empty() { + let mut m = linear_map_with_capacity(4); + assert!(m.insert(1, 2)); + assert!(!m.is_empty()); + assert!(m.remove(&1)); + assert!(m.is_empty()); + } - #[test] - pub fn test_pop() { - let mut m = LinearMap::new(); - m.insert(1, 2); - assert!(m.pop(&1) == Some(2)); - assert!(m.pop(&1) == None); - } + #[test] + fn test_pop() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert!(m.pop(&1) == Some(2)); + assert!(m.pop(&1) == None); + } - #[test] - pub fn test_swap() { - let mut m = LinearMap::new(); - assert!(m.swap(1, 2) == None); - assert!(m.swap(1, 3) == Some(2)); - assert!(m.swap(1, 4) == Some(3)); - } + #[test] + fn test_swap() { + let mut m = HashMap::new(); + assert!(m.swap(1, 2) == None); + assert!(m.swap(1, 3) == Some(2)); + assert!(m.swap(1, 4) == Some(3)); + } - #[test] - pub fn test_find_or_insert() { - let mut m = LinearMap::new::(); - assert!(m.find_or_insert(1, 2) == &2); - assert!(m.find_or_insert(1, 3) == &2); - } + #[test] + fn test_find_or_insert() { + let mut m = HashMap::new::(); + assert!(m.find_or_insert(1, 2) == &2); + assert!(m.find_or_insert(1, 3) == &2); + } - #[test] - pub fn test_find_or_insert_with() { - let mut m = LinearMap::new::(); - assert!(m.find_or_insert_with(1, |_| 2) == &2); - assert!(m.find_or_insert_with(1, |_| 3) == &2); - } + #[test] + fn test_find_or_insert_with() { + let mut m = HashMap::new::(); + assert!(m.find_or_insert_with(1, |_| 2) == &2); + assert!(m.find_or_insert_with(1, |_| 3) == &2); + } - #[test] - pub fn test_consume() { - let mut m = LinearMap::new(); - assert!(m.insert(1, 2)); - assert!(m.insert(2, 3)); - let mut m2 = LinearMap::new(); - do m.consume |k, v| { - m2.insert(k, v); - } - assert!(m.len() == 0); - assert!(m2.len() == 2); - assert!(m2.get(&1) == &2); - assert!(m2.get(&2) == &3); - } + #[test] + fn test_consume() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2)); + assert!(m.insert(2, 3)); + let mut m2 = HashMap::new(); + do m.consume |k, v| { + m2.insert(k, v); + } + assert!(m.len() == 0); + assert!(m2.len() == 2); + assert!(m2.get(&1) == &2); + assert!(m2.get(&2) == &3); + } - #[test] - pub fn test_iterate() { - let mut m = linear::linear_map_with_capacity(4); - for uint::range(0, 32) |i| { - assert!(m.insert(i, i*2)); - } - let mut observed = 0; - for m.each |&(k, v)| { - assert!(*v == *k * 2); - observed |= (1 << *k); - } - assert!(observed == 0xFFFF_FFFF); + #[test] + fn test_iterate() { + let mut m = linear_map_with_capacity(4); + for uint::range(0, 32) |i| { + assert!(m.insert(i, i*2)); } - - #[test] - pub fn test_find() { - let mut m = LinearMap::new(); - assert!(m.find(&1).is_none()); - m.insert(1, 2); - match m.find(&1) { - None => fail!(), - Some(v) => assert!(*v == 2) - } + let mut observed = 0; + for m.each |k, v| { + assert!(*v == *k * 2); + observed |= (1 << *k); } + assert!(observed == 0xFFFF_FFFF); + } - #[test] - pub fn test_eq() { - let mut m1 = LinearMap::new(); - m1.insert(1, 2); - m1.insert(2, 3); - m1.insert(3, 4); + #[test] + fn test_find() { + let mut m = HashMap::new(); + assert!(m.find(&1).is_none()); + m.insert(1, 2); + match m.find(&1) { + None => fail!(), + Some(v) => assert!(*v == 2) + } + } - let mut m2 = LinearMap::new(); - m2.insert(1, 2); - m2.insert(2, 3); + #[test] + fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); - assert!(m1 != m2); + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); - m2.insert(3, 4); + assert!(m1 != m2); - assert!(m1 == m2); - } + m2.insert(3, 4); - #[test] - pub fn test_expand() { - let mut m = LinearMap::new(); + assert!(m1 == m2); + } - assert!(m.len() == 0); - assert!(m.is_empty()); + #[test] + fn test_expand() { + let mut m = HashMap::new(); - let mut i = 0u; - let old_resize_at = m.resize_at; - while old_resize_at == m.resize_at { - m.insert(i, i); - i += 1; - } + assert!(m.len() == 0); + assert!(m.is_empty()); - assert!(m.len() == i); - assert!(!m.is_empty()); + let mut i = 0u; + let old_resize_at = m.resize_at; + while old_resize_at == m.resize_at { + m.insert(i, i); + i += 1; } + + assert!(m.len() == i); + assert!(!m.is_empty()); } +} #[test] - mod test_set { - use hashmap::linear; - use container::{Container, Map, Set}; - use vec; - - #[test] - fn test_disjoint() { - let mut xs = linear::LinearSet::new(); - let mut ys = linear::LinearSet::new(); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(5)); - assert!(ys.insert(11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(7)); - assert!(xs.insert(19)); - assert!(xs.insert(4)); - assert!(ys.insert(2)); - assert!(ys.insert(-11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(ys.insert(7)); - assert!(!xs.is_disjoint(&ys)); - assert!(!ys.is_disjoint(&xs)); - } +mod test_set { + use super::*; + use container::{Container, Map, Set}; + use vec; - #[test] - fn test_subset_and_superset() { - let mut a = linear::LinearSet::new(); - assert!(a.insert(0)); - assert!(a.insert(5)); - assert!(a.insert(11)); - assert!(a.insert(7)); - - let mut b = linear::LinearSet::new(); - assert!(b.insert(0)); - assert!(b.insert(7)); - assert!(b.insert(19)); - assert!(b.insert(250)); - assert!(b.insert(11)); - assert!(b.insert(200)); - - assert!(!a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(!b.is_superset(&a)); - - assert!(b.insert(5)); - - assert!(a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(b.is_superset(&a)); - } + #[test] + fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); + } - #[test] - fn test_intersection() { - let mut a = linear::LinearSet::new(); - let mut b = linear::LinearSet::new(); - - assert!(a.insert(11)); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(77)); - assert!(a.insert(103)); - assert!(a.insert(5)); - assert!(a.insert(-5)); - - assert!(b.insert(2)); - assert!(b.insert(11)); - assert!(b.insert(77)); - assert!(b.insert(-9)); - assert!(b.insert(-42)); - assert!(b.insert(5)); - assert!(b.insert(3)); - - let mut i = 0; - let expected = [3, 5, 11, 77]; - for a.intersection(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert!(i == expected.len()); - } + #[test] + fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); + } - #[test] - fn test_difference() { - let mut a = linear::LinearSet::new(); - let mut b = linear::LinearSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(3)); - assert!(b.insert(9)); - - let mut i = 0; - let expected = [1, 5, 11]; - for a.difference(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert!(i == expected.len()); - } + #[test] + fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for a.intersection(&b) |x| { + assert!(vec::contains(expected, x)); + i += 1 + } + assert!(i == expected.len()); + } - #[test] - fn test_symmetric_difference() { - let mut a = linear::LinearSet::new(); - let mut b = linear::LinearSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(-2)); - assert!(b.insert(3)); - assert!(b.insert(9)); - assert!(b.insert(14)); - assert!(b.insert(22)); - - let mut i = 0; - let expected = [-2, 1, 5, 11, 14, 22]; - for a.symmetric_difference(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert!(i == expected.len()); - } + #[test] + fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for a.difference(&b) |x| { + assert!(vec::contains(expected, x)); + i += 1 + } + assert!(i == expected.len()); + } - #[test] - fn test_union() { - let mut a = linear::LinearSet::new(); - let mut b = linear::LinearSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - assert!(a.insert(16)); - assert!(a.insert(19)); - assert!(a.insert(24)); - - assert!(b.insert(-2)); - assert!(b.insert(1)); - assert!(b.insert(5)); - assert!(b.insert(9)); - assert!(b.insert(13)); - assert!(b.insert(19)); - - let mut i = 0; - let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; - for a.union(&b) |x| { - assert!(vec::contains(expected, x)); - i += 1 - } - assert!(i == expected.len()); - } + #[test] + fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for a.symmetric_difference(&b) |x| { + assert!(vec::contains(expected, x)); + i += 1 + } + assert!(i == expected.len()); + } + + #[test] + fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for a.union(&b) |x| { + assert!(vec::contains(expected, x)); + i += 1 + } + assert!(i == expected.len()); } } diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 60a0ee4fa9713..3c5900f51a247 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -49,29 +49,89 @@ pub mod rustrt { // FIXME (#2004): This is all buffered. We might need an unbuffered variant // as well +/** +* The SeekStyle enum describes the relationship between the position +* we'd like to seek to from our current position. It's used as an argument +* to the `seek` method defined on the `Reader` trait. +* +* There are three seek styles: +* +* 1. `SeekSet` means that the new position should become our position. +* 2. `SeekCur` means that we should seek from the current position. +* 3. `SeekEnd` means that we should seek from the end. +* +* # Examples +* +* None right now. +*/ pub enum SeekStyle { SeekSet, SeekEnd, SeekCur, } -/// The raw underlying reader trait. All readers must implement this. +/** +* The core Reader trait. All readers must implement this trait. +* +* # Examples +* +* None right now. +*/ pub trait Reader { // FIXME (#2004): Seekable really should be orthogonal. - /// Read up to len bytes (or EOF) and put them into bytes (which - /// must be at least len bytes long). Return number of bytes read. // FIXME (#2982): This should probably return an error. + /** + * Reads bytes and puts them into `bytes`. Returns the number of + * bytes read. + * + * The number of bytes to be read is `len` or the end of the file, + * whichever comes first. + * + * The buffer must be at least `len` bytes long. + * + * # Examples + * + * None right now. + */ fn read(&self, bytes: &mut [u8], len: uint) -> uint; - /// Read a single byte, returning a negative value for EOF or read error. + /** + * Reads a single byte. + * + * In the case of an EOF or an error, returns a negative value. + * + * # Examples + * + * None right now. + */ fn read_byte(&self) -> int; - /// Return whether the stream is currently at EOF position. + /** + * Returns a boolean value: are we currently at EOF? + * + * # Examples + * + * None right now. + */ fn eof(&self) -> bool; - /// Move the current position within the stream. The second parameter - /// determines the position that the first parameter is relative to. + /** + * Seek to a given `position` in the stream. + * + * Takes an optional SeekStyle, which affects how we seek from the + * position. See `SeekStyle` docs for more details. + * + * # Examples + * + * None right now. + */ fn seek(&self, position: int, style: SeekStyle); - /// Return the current position within the stream. + /** + * Returns the current position within the stream. + * + * # Examples + * + * None right now. + */ fn tell(&self) -> uint; } @@ -93,120 +153,415 @@ impl Reader for @Reader { } } -/// Generic utility functions defined on readers. +/** +* The `ReaderUtil` trait is a home for many of the utility functions +* a particular Reader should implement. +* +* The default `Reader` trait is focused entirely on bytes. `ReaderUtil` is based +* on higher-level concepts like 'chars' and 'lines.' +* +* # Examples: +* +* None right now. +*/ pub trait ReaderUtil { - /// Read len bytes into a new vec. + /** + * Reads `len` number of bytes, and gives you a new vector back. + * + * # Examples + * + * None right now. + */ fn read_bytes(&self, len: uint) -> ~[u8]; - /// Read up until a specified character (which is optionally included) or EOF. + /** + * Reads up until a specific character or EOF. + * + * The `include` parameter specifies if the character should be included + * in the returned string. + * + * # Examples + * + * None right now. + */ fn read_until(&self, c: char, include: bool) -> ~str; - /// Read up until the first '\n' char (which is not returned), or EOF. + /** + * Reads up until the first '\n' or EOF. + * + * The '\n' is not included in the result. + * + * # Examples + * + * None right now. + */ fn read_line(&self) -> ~str; - /// Read n utf-8 encoded chars. + /** + * Reads `n` chars. + * + * Assumes that those chars are UTF-8 encoded. + * + * The '\n' is not included in the result. + * + * # Examples + * + * None right now. + */ fn read_chars(&self, n: uint) -> ~[char]; - /// Read a single utf-8 encoded char. + /** + * Reads a single UTF-8 encoded char. + * + * # Examples + * + * None right now. + */ fn read_char(&self) -> char; - /// Read up until the first null byte (which is not returned), or EOF. + /** + * Reads up until the first null byte or EOF. + * + * The null byte is not returned. + * + * # Examples + * + * None right now. + */ fn read_c_str(&self) -> ~str; - /// Read all the data remaining in the stream in one go. + /** + * Reads all remaining data in the stream. + * + * # Examples + * + * None right now. + */ fn read_whole_stream(&self) -> ~[u8]; - /// Iterate over every byte until the iterator breaks or EOF. + /** + * Iterate over every byte until EOF or the iterator breaks. + * + * # Examples + * + * None right now. + */ fn each_byte(&self, it: &fn(int) -> bool); - /// Iterate over every char until the iterator breaks or EOF. + /** + * Iterate over every char until EOF or the iterator breaks. + * + * # Examples + * + * None right now. + */ fn each_char(&self, it: &fn(char) -> bool); - /// Iterate over every line until the iterator breaks or EOF. + /** + * Iterate over every line until EOF or the iterator breaks. + * + * # Examples + * + * None right now. + */ fn each_line(&self, it: &fn(&str) -> bool); - /// Read all the lines of the file into a vector. + /** + * Reads all of the lines in the stream. + * + * Returns a vector of those lines. + * + * # Examples + * + * None right now. + */ fn read_lines(&self) -> ~[~str]; - /// Read n (between 1 and 8) little-endian unsigned integer bytes. + /** + * Reads `n` little-endian unsigned integer bytes. + * + * `n` must be between 1 and 8, inclusive. + * + * # Examples + * + * None right now. + */ fn read_le_uint_n(&self, nbytes: uint) -> u64; - /// Read n (between 1 and 8) little-endian signed integer bytes. + /** + * Reads `n` little-endian signed integer bytes. + * + * `n` must be between 1 and 8, inclusive. + * + * # Examples + * + * None right now. + */ fn read_le_int_n(&self, nbytes: uint) -> i64; - /// Read n (between 1 and 8) big-endian unsigned integer bytes. + /** + * Reads `n` big-endian unsigned integer bytes. + * + * `n` must be between 1 and 8, inclusive. + * + * # Examples + * + * None right now. + */ fn read_be_uint_n(&self, nbytes: uint) -> u64; - /// Read n (between 1 and 8) big-endian signed integer bytes. + /** + * Reads `n` big-endian signed integer bytes. + * + * `n` must be between 1 and 8, inclusive. + * + * # Examples + * + * None right now. + */ fn read_be_int_n(&self, nbytes: uint) -> i64; - /// Read a little-endian uint (number of bytes depends on system). + /** + * Reads a little-endian unsigned integer. + * + * The number of bytes returned is system-dependant. + * + * # Examples + * + * None right now. + */ fn read_le_uint(&self) -> uint; - /// Read a little-endian int (number of bytes depends on system). + /** + * Reads a little-endian integer. + * + * The number of bytes returned is system-dependant. + * + * # Examples + * + * None right now. + */ fn read_le_int(&self) -> int; - /// Read a big-endian uint (number of bytes depends on system). + /** + * Reads a big-endian unsigned integer. + * + * The number of bytes returned is system-dependant. + * + * # Examples + * + * None right now. + */ fn read_be_uint(&self) -> uint; - /// Read a big-endian int (number of bytes depends on system). + /** + * Reads a big-endian integer. + * + * The number of bytes returned is system-dependant. + * + * # Examples + * + * None right now. + */ fn read_be_int(&self) -> int; - /// Read a big-endian u64 (8 bytes). + /** + * Reads a big-endian `u64`. + * + * `u64`s are 8 bytes long. + * + * # Examples + * + * None right now. + */ fn read_be_u64(&self) -> u64; - /// Read a big-endian u32 (4 bytes). + /** + * Reads a big-endian `u32`. + * + * `u32`s are 4 bytes long. + * + * # Examples + * + * None right now. + */ fn read_be_u32(&self) -> u32; - /// Read a big-endian u16 (2 bytes). + /** + * Reads a big-endian `u16`. + * + * `u16`s are 2 bytes long. + * + * # Examples + * + * None right now. + */ fn read_be_u16(&self) -> u16; - /// Read a big-endian i64 (8 bytes). + /** + * Reads a big-endian `i64`. + * + * `i64`s are 8 bytes long. + * + * # Examples + * + * None right now. + */ fn read_be_i64(&self) -> i64; - /// Read a big-endian i32 (4 bytes). + /** + * Reads a big-endian `i32`. + * + * `i32`s are 4 bytes long. + * + * # Examples + * + * None right now. + */ fn read_be_i32(&self) -> i32; - /// Read a big-endian i16 (2 bytes). + /** + * Reads a big-endian `i16`. + * + * `i16`s are 2 bytes long. + * + * # Examples + * + * None right now. + */ fn read_be_i16(&self) -> i16; - /// Read a big-endian IEEE754 double-precision floating-point (8 bytes). + /** + * Reads a big-endian `f64`. + * + * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. + * + * # Examples + * + * None right now. + */ fn read_be_f64(&self) -> f64; - /// Read a big-endian IEEE754 single-precision floating-point (4 bytes). + /** + * Reads a big-endian `f32`. + * + * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. + * + * # Examples + * + * None right now. + */ fn read_be_f32(&self) -> f32; - /// Read a little-endian u64 (8 bytes). + /** + * Reads a little-endian `u64`. + * + * `u64`s are 8 bytes long. + * + * # Examples + * + * None right now. + */ fn read_le_u64(&self) -> u64; - /// Read a little-endian u32 (4 bytes). + /** + * Reads a little-endian `u32`. + * + * `u32`s are 4 bytes long. + * + * # Examples + * + * None right now. + */ fn read_le_u32(&self) -> u32; - /// Read a little-endian u16 (2 bytes). + /** + * Reads a little-endian `u16`. + * + * `u16`s are 2 bytes long. + * + * # Examples + * + * None right now. + */ fn read_le_u16(&self) -> u16; - /// Read a litle-endian i64 (8 bytes). + /** + * Reads a little-endian `i64`. + * + * `i64`s are 8 bytes long. + * + * # Examples + * + * None right now. + */ fn read_le_i64(&self) -> i64; - /// Read a litle-endian i32 (4 bytes). + /** + * Reads a little-endian `i32`. + * + * `i32`s are 4 bytes long. + * + * # Examples + * + * None right now. + */ fn read_le_i32(&self) -> i32; - /// Read a litle-endian i16 (2 bytes). + /** + * Reads a little-endian `i16`. + * + * `i16`s are 2 bytes long. + * + * # Examples + * + * None right now. + */ fn read_le_i16(&self) -> i16; - /// Read a litten-endian IEEE754 double-precision floating-point - /// (8 bytes). + /** + * Reads a little-endian `f64`. + * + * `f64`s are 8 byte, IEEE754 double-precision floating point numbers. + * + * # Examples + * + * None right now. + */ fn read_le_f64(&self) -> f64; - /// Read a litten-endian IEEE754 single-precision floating-point - /// (4 bytes). + /** + * Reads a little-endian `f32`. + * + * `f32`s are 4 byte, IEEE754 single-precision floating point numbers. + * + * # Examples + * + * None right now. + */ fn read_le_f32(&self) -> f32; - /// Read a u8 (1 byte). + /** + * Read a u8. + * + * `u8`s are 1 byte. + * + * # Examples + * + * None right now. + */ fn read_u8(&self) -> u8; - /// Read a i8 (1 byte). + /** + * Read an i8. + * + * `i8`s are 1 byte. + * + * # Examples + * + * None right now. + */ fn read_i8(&self) -> i8; } @@ -1181,11 +1536,8 @@ pub fn with_bytes_writer(f: &fn(@Writer)) -> ~[u8] { pub fn with_str_writer(f: &fn(@Writer)) -> ~str { let mut v = with_bytes_writer(f); - // FIXME (#3758): This should not be needed. - unsafe { - // Make sure the vector has a trailing null and is proper utf8. - v.push(0); - } + // Make sure the vector has a trailing null and is proper utf8. + v.push(0); assert!(str::is_utf8(v)); unsafe { ::cast::transmute(v) } @@ -1285,16 +1637,14 @@ pub mod fsync { // outer res pub fn FILE_res_sync(file: &FILERes, opt_level: Option, blk: &fn(v: Res<*libc::FILE>)) { - unsafe { - blk(Res(Arg { - val: file.f, opt_level: opt_level, - fsync_fn: |file, l| { - unsafe { - os::fsync_fd(libc::fileno(file), l) as int - } + blk(Res(Arg { + val: file.f, opt_level: opt_level, + fsync_fn: |file, l| { + unsafe { + os::fsync_fd(libc::fileno(file), l) as int } - })); - } + } + })); } // fsync fd after executing blk diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 7ed4c3c36ea6d..a220cd520c32a 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -161,7 +161,7 @@ pub fn foldl>(self: &IA, b0: B, blk: &fn(&B, &A) -> B) #[inline(always)] pub fn to_vec>(self: &IA) -> ~[A] { - foldl::(self, ~[], |r, a| vec::append(copy (*r), ~[*a])) + map_to_vec(self, |&x| x) } #[inline(always)] @@ -344,3 +344,29 @@ pub fn copy_seq,BT:Buildable>(v: &IT) -> BT { for v.each |x| { push(*x); } } } + +/** + * Helper function to transform an internal iterator into an owned vector. + * + * # Example: + * + * ~~~ + * let v = ~[1, 2, 3]; + * let v2 = do iter_to_vec |f| { v.each(|e| f(*e)) }; + * if v != v2 { fail!() } + * ~~~ + */ +#[inline(always)] +pub fn iter_to_vec(pusher: &fn(it: &fn(T) -> bool)) -> ~[T] { + let mut v = ~[]; + let pushf = |e| {v.push(e); true}; + pusher(pushf); + v +} + +#[test] +fn test_iter_to_vec() { + let v = ~[1, 2, 3]; + let v2 = do iter_to_vec |f| { v.each(|e| f(*e)) }; + if v != v2 { fail!() } +} diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs new file mode 100644 index 0000000000000..fcb5102d4c07c --- /dev/null +++ b/src/libcore/iterator.rs @@ -0,0 +1,106 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Composable iterator objects + +use prelude::*; + +pub trait Iterator { + /// Advance the iterator and return the next value. Return `None` when the end is reached. + fn next(&mut self) -> Option; +} + +pub trait IteratorUtil { + fn zip>(self, other: U) -> ZipIterator; + // FIXME: #5898: should be called map + fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; + fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, Self>; + fn advance(&mut self, f: &fn(A) -> bool); +} + +impl> IteratorUtil for T { + #[inline(always)] + fn zip>(self, other: U) -> ZipIterator { + ZipIterator{a: self, b: other} + } + + // FIXME: #5898: should be called map + #[inline(always)] + fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, T> { + MapIterator{iter: self, f: f} + } + + #[inline(always)] + fn filter<'r>(self, predicate: &'r fn(&A) -> bool) -> FilterIterator<'r, A, T> { + FilterIterator{iter: self, predicate: predicate} + } + + /// A shim implementing the `for` loop iteration protocol for iterator objects + #[inline] + fn advance(&mut self, f: &fn(A) -> bool) { + loop { + match self.next() { + Some(x) => { + if !f(x) { return } + } + None => return + } + } + } +} + +pub struct ZipIterator { + priv a: T, + priv b: U +} + +impl, U: Iterator> Iterator<(A, B)> for ZipIterator { + #[inline] + fn next(&mut self) -> Option<(A, B)> { + match (self.a.next(), self.b.next()) { + (Some(x), Some(y)) => Some((x, y)), + _ => None + } + } +} + +pub struct FilterIterator<'self, A, T> { + priv iter: T, + priv predicate: &'self fn(&A) -> bool +} + +impl<'self, A, T: Iterator> Iterator for FilterIterator<'self, A, T> { + #[inline] + fn next(&mut self) -> Option { + for self.iter.advance |x| { + if (self.predicate)(&x) { + return Some(x); + } else { + loop + } + } + None + } +} + +pub struct MapIterator<'self, A, B, T> { + priv iter: T, + priv f: &'self fn(A) -> B +} + +impl<'self, A, B, T: Iterator> Iterator for MapIterator<'self, A, B, T> { + #[inline] + fn next(&mut self) -> Option { + match self.iter.next() { + Some(a) => Some((self.f)(a)), + _ => None + } + } +} diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index fdb82a7303bea..e5c5b2f9f2c26 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -863,8 +863,20 @@ pub mod consts { pub static F_TEST : int = 3; pub static F_TLOCK : int = 2; pub static F_ULOCK : int = 0; + pub static SIGHUP : int = 1; + pub static SIGINT : int = 2; + pub static SIGQUIT : int = 3; + pub static SIGILL : int = 4; + pub static SIGABRT : int = 6; + pub static SIGFPE : int = 8; + pub static SIGKILL : int = 9; + pub static SIGSEGV : int = 11; + pub static SIGPIPE : int = 13; + pub static SIGALRM : int = 14; + pub static SIGTERM : int = 15; } pub mod posix01 { + pub static SIGTRAP : int = 5; } pub mod posix08 { } @@ -930,8 +942,20 @@ pub mod consts { pub static F_TEST : int = 3; pub static F_TLOCK : int = 2; pub static F_ULOCK : int = 0; + pub static SIGHUP : int = 1; + pub static SIGINT : int = 2; + pub static SIGQUIT : int = 3; + pub static SIGILL : int = 4; + pub static SIGABRT : int = 6; + pub static SIGFPE : int = 8; + pub static SIGKILL : int = 9; + pub static SIGSEGV : int = 11; + pub static SIGPIPE : int = 13; + pub static SIGALRM : int = 14; + pub static SIGTERM : int = 15; } pub mod posix01 { + pub static SIGTRAP : int = 5; } pub mod posix08 { } @@ -998,8 +1022,20 @@ pub mod consts { pub static F_TEST : int = 3; pub static F_TLOCK : int = 2; pub static F_ULOCK : int = 0; + pub static SIGHUP : int = 1; + pub static SIGINT : int = 2; + pub static SIGQUIT : int = 3; + pub static SIGILL : int = 4; + pub static SIGABRT : int = 6; + pub static SIGFPE : int = 8; + pub static SIGKILL : int = 9; + pub static SIGSEGV : int = 11; + pub static SIGPIPE : int = 13; + pub static SIGALRM : int = 14; + pub static SIGTERM : int = 15; } pub mod posix01 { + pub static SIGTRAP : int = 5; } pub mod posix08 { } @@ -1394,7 +1430,7 @@ pub mod funcs { use libc::types::common::posix88::{DIR, dirent_t}; use libc::types::os::arch::c95::{c_char, c_int, c_long}; - // NOTE: On OS X opendir and readdir have two versions, + // NB: On OS X opendir and readdir have two versions, // one for 32-bit kernelspace and one for 64. // We should be linking to the 64-bit ones, called // opendir$INODE64, etc. but for some reason rustc @@ -1482,6 +1518,17 @@ pub mod funcs { -> ssize_t; } } + + #[nolink] + #[abi = "cdecl"] + pub mod signal { + use libc::types::os::arch::c95::{c_int}; + use libc::types::os::arch::posix88::{pid_t}; + + pub extern { + unsafe fn kill(pid: pid_t, sig: c_int) -> c_int; + } + } } #[cfg(target_os = "linux")] @@ -1623,6 +1670,7 @@ pub mod funcs { pub mod extra { pub mod kernel32 { + use libc::types::os::arch::c95::{c_uint}; use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE}; use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH}; use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES}; @@ -1663,6 +1711,7 @@ pub mod funcs { findFileData: HANDLE) -> BOOL; unsafe fn FindClose(findFile: HANDLE) -> BOOL; + unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL; } } diff --git a/src/libcore/managed.rs b/src/libcore/managed.rs index 234b710d238b0..2bd3959acf4de 100644 --- a/src/libcore/managed.rs +++ b/src/libcore/managed.rs @@ -38,13 +38,13 @@ pub mod raw { #[inline(always)] pub fn ptr_eq(a: @T, b: @T) -> bool { //! Determine if two shared boxes point to the same object - unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) } + ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) } #[inline(always)] pub fn mut_ptr_eq(a: @mut T, b: @mut T) -> bool { //! Determine if two mutable shared boxes point to the same object - unsafe { ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) } + ptr::addr_of(&(*a)) == ptr::addr_of(&(*b)) } #[cfg(notest)] diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 6361a6a5cb75e..5e672ea0dfa86 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -12,7 +12,6 @@ use cmath; use libc::{c_float, c_int}; -use num::NumCast; use num::strconv; use num; use option::Option; @@ -287,30 +286,6 @@ impl num::One for f32 { fn one() -> f32 { 1.0 } } -impl NumCast for f32 { - /** - * Cast `n` to an `f32` - */ - #[inline(always)] - fn from(n: N) -> f32 { n.to_f32() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - #[cfg(notest)] impl ops::Add for f32 { fn add(&self, other: &f32) -> f32 { *self + *other } @@ -507,7 +482,7 @@ impl num::ToStrRadix for f32 { #[inline(always)] pub fn from_str(num: &str) -> Option { strconv::from_str_common(num, 10u, true, true, true, - strconv::ExpDec, false) + strconv::ExpDec, false, false) } /** @@ -540,7 +515,7 @@ pub fn from_str(num: &str) -> Option { #[inline(always)] pub fn from_str_hex(num: &str) -> Option { strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false) + strconv::ExpBin, false, false) } /** @@ -565,7 +540,7 @@ pub fn from_str_hex(num: &str) -> Option { #[inline(always)] pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::from_str_common(num, rdx, true, true, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } impl from_str::FromStr for f32 { @@ -580,63 +555,6 @@ impl num::FromStrRadix for f32 { } } -#[test] -pub fn test_num() { - let ten: f32 = num::cast(10); - let two: f32 = num::cast(2); - - assert!((ten.add(&two) == num::cast(12))); - assert!((ten.sub(&two) == num::cast(8))); - assert!((ten.mul(&two) == num::cast(20))); - assert!((ten.div(&two) == num::cast(5))); - assert!((ten.modulo(&two) == num::cast(0))); -} - -#[test] -fn test_numcast() { - assert!((20u == 20f32.to_uint())); - assert!((20u8 == 20f32.to_u8())); - assert!((20u16 == 20f32.to_u16())); - assert!((20u32 == 20f32.to_u32())); - assert!((20u64 == 20f32.to_u64())); - assert!((20i == 20f32.to_int())); - assert!((20i8 == 20f32.to_i8())); - assert!((20i16 == 20f32.to_i16())); - assert!((20i32 == 20f32.to_i32())); - assert!((20i64 == 20f32.to_i64())); - assert!((20f == 20f32.to_float())); - assert!((20f32 == 20f32.to_f32())); - assert!((20f64 == 20f32.to_f64())); - - assert!((20f32 == NumCast::from(20u))); - assert!((20f32 == NumCast::from(20u8))); - assert!((20f32 == NumCast::from(20u16))); - assert!((20f32 == NumCast::from(20u32))); - assert!((20f32 == NumCast::from(20u64))); - assert!((20f32 == NumCast::from(20i))); - assert!((20f32 == NumCast::from(20i8))); - assert!((20f32 == NumCast::from(20i16))); - assert!((20f32 == NumCast::from(20i32))); - assert!((20f32 == NumCast::from(20i64))); - assert!((20f32 == NumCast::from(20f))); - assert!((20f32 == NumCast::from(20f32))); - assert!((20f32 == NumCast::from(20f64))); - - assert!((20f32 == num::cast(20u))); - assert!((20f32 == num::cast(20u8))); - assert!((20f32 == num::cast(20u16))); - assert!((20f32 == num::cast(20u32))); - assert!((20f32 == num::cast(20u64))); - assert!((20f32 == num::cast(20i))); - assert!((20f32 == num::cast(20i8))); - assert!((20f32 == num::cast(20i16))); - assert!((20f32 == num::cast(20i32))); - assert!((20f32 == num::cast(20i64))); - assert!((20f32 == num::cast(20f))); - assert!((20f32 == num::cast(20f32))); - assert!((20f32 == num::cast(20f64))); -} - // // Local Variables: // mode: rust diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 9e731e61ec49e..4c96da73d2130 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -12,7 +12,6 @@ use cmath; use libc::{c_double, c_int}; -use num::NumCast; use num::strconv; use num; use option::Option; @@ -299,30 +298,6 @@ impl cmp::Ord for f64 { fn gt(&self, other: &f64) -> bool { (*self) > (*other) } } -impl NumCast for f64 { - /** - * Cast `n` to an `f64` - */ - #[inline(always)] - fn from(n: N) -> f64 { n.to_f64() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - impl num::Zero for f64 { #[inline(always)] fn zero() -> f64 { 0.0 } @@ -529,7 +504,7 @@ impl num::ToStrRadix for f64 { #[inline(always)] pub fn from_str(num: &str) -> Option { strconv::from_str_common(num, 10u, true, true, true, - strconv::ExpDec, false) + strconv::ExpDec, false, false) } /** @@ -562,7 +537,7 @@ pub fn from_str(num: &str) -> Option { #[inline(always)] pub fn from_str_hex(num: &str) -> Option { strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false) + strconv::ExpBin, false, false) } /** @@ -587,7 +562,7 @@ pub fn from_str_hex(num: &str) -> Option { #[inline(always)] pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::from_str_common(num, rdx, true, true, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } impl from_str::FromStr for f64 { @@ -602,63 +577,6 @@ impl num::FromStrRadix for f64 { } } -#[test] -pub fn test_num() { - let ten: f64 = num::cast(10); - let two: f64 = num::cast(2); - - assert!((ten.add(&two) == num::cast(12))); - assert!((ten.sub(&two) == num::cast(8))); - assert!((ten.mul(&two) == num::cast(20))); - assert!((ten.div(&two) == num::cast(5))); - assert!((ten.modulo(&two) == num::cast(0))); -} - -#[test] -fn test_numcast() { - assert!((20u == 20f64.to_uint())); - assert!((20u8 == 20f64.to_u8())); - assert!((20u16 == 20f64.to_u16())); - assert!((20u32 == 20f64.to_u32())); - assert!((20u64 == 20f64.to_u64())); - assert!((20i == 20f64.to_int())); - assert!((20i8 == 20f64.to_i8())); - assert!((20i16 == 20f64.to_i16())); - assert!((20i32 == 20f64.to_i32())); - assert!((20i64 == 20f64.to_i64())); - assert!((20f == 20f64.to_float())); - assert!((20f32 == 20f64.to_f32())); - assert!((20f64 == 20f64.to_f64())); - - assert!((20f64 == NumCast::from(20u))); - assert!((20f64 == NumCast::from(20u8))); - assert!((20f64 == NumCast::from(20u16))); - assert!((20f64 == NumCast::from(20u32))); - assert!((20f64 == NumCast::from(20u64))); - assert!((20f64 == NumCast::from(20i))); - assert!((20f64 == NumCast::from(20i8))); - assert!((20f64 == NumCast::from(20i16))); - assert!((20f64 == NumCast::from(20i32))); - assert!((20f64 == NumCast::from(20i64))); - assert!((20f64 == NumCast::from(20f))); - assert!((20f64 == NumCast::from(20f32))); - assert!((20f64 == NumCast::from(20f64))); - - assert!((20f64 == num::cast(20u))); - assert!((20f64 == num::cast(20u8))); - assert!((20f64 == num::cast(20u16))); - assert!((20f64 == num::cast(20u32))); - assert!((20f64 == num::cast(20u64))); - assert!((20f64 == num::cast(20i))); - assert!((20f64 == num::cast(20i8))); - assert!((20f64 == num::cast(20i16))); - assert!((20f64 == num::cast(20i32))); - assert!((20f64 == num::cast(20i64))); - assert!((20f64 == num::cast(20f))); - assert!((20f64 == num::cast(20f32))); - assert!((20f64 == num::cast(20f64))); -} - // // Local Variables: // mode: rust diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index c80d52f496b49..488756787b5cd 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -21,7 +21,6 @@ // PORT this must match in width according to architecture use f64; -use num::NumCast; use num::strconv; use num; use option::Option; @@ -30,7 +29,6 @@ use from_str; #[cfg(notest)] use cmp::{Eq, Ord}; #[cfg(notest)] use ops; -#[cfg(test)] use option::{Some, None}; pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt}; pub use f64::logarithm; @@ -143,7 +141,7 @@ pub fn to_str_radix(num: float, radix: uint) -> ~str { let (r, special) = strconv::to_str_common( &num, radix, true, strconv::SignNeg, strconv::DigAll); if special { fail!(~"number has a special value, \ - try to_str_radix_special() if those are expected") } + try to_str_radix_special() if those are expected") } r } @@ -178,12 +176,6 @@ pub fn to_str_exact(num: float, digits: uint) -> ~str { r } -#[test] -pub fn test_to_str_exact_do_decimal() { - let s = to_str_exact(5.0, 4u); - assert!(s == ~"5.0000"); -} - /** * Converts a float to a string with a maximum number of * significant digits @@ -242,7 +234,7 @@ impl num::ToStrRadix for float { #[inline(always)] pub fn from_str(num: &str) -> Option { strconv::from_str_common(num, 10u, true, true, true, - strconv::ExpDec, false) + strconv::ExpDec, false, false) } /** @@ -275,7 +267,7 @@ pub fn from_str(num: &str) -> Option { #[inline(always)] pub fn from_str_hex(num: &str) -> Option { strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false) + strconv::ExpBin, false, false) } /** @@ -300,7 +292,7 @@ pub fn from_str_hex(num: &str) -> Option { #[inline(always)] pub fn from_str_radix(num: &str, radix: uint) -> Option { strconv::from_str_common(num, radix, true, true, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } impl from_str::FromStr for float { @@ -370,27 +362,27 @@ pub fn is_NaN(x: float) -> bool { f64::is_NaN(x as f64) } #[inline(always)] pub fn abs(x: float) -> float { - unsafe { f64::abs(x as f64) as float } + f64::abs(x as f64) as float } #[inline(always)] pub fn sqrt(x: float) -> float { - unsafe { f64::sqrt(x as f64) as float } + f64::sqrt(x as f64) as float } #[inline(always)] pub fn atan(x: float) -> float { - unsafe { f64::atan(x as f64) as float } + f64::atan(x as f64) as float } #[inline(always)] pub fn sin(x: float) -> float { - unsafe { f64::sin(x as f64) as float } + f64::sin(x as f64) as float } #[inline(always)] pub fn cos(x: float) -> float { - unsafe { f64::cos(x as f64) as float } + f64::cos(x as f64) as float } #[inline(always)] pub fn tan(x: float) -> float { - unsafe { f64::tan(x as f64) as float } + f64::tan(x as f64) as float } #[cfg(notest)] @@ -417,30 +409,6 @@ impl num::One for float { fn one() -> float { 1.0 } } -impl NumCast for float { - /** - * Cast `n` to a `float` - */ - #[inline(always)] - fn from(n: N) -> float { n.to_float() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self } -} - impl num::Round for float { #[inline(always)] fn round(&self, mode: num::RoundMode) -> float { @@ -499,252 +467,205 @@ impl ops::Neg for float { fn neg(&self) -> float { -*self } } -#[test] -pub fn test_from_str() { - assert!(from_str(~"3") == Some(3.)); - assert!(from_str(~"3.14") == Some(3.14)); - assert!(from_str(~"+3.14") == Some(3.14)); - assert!(from_str(~"-3.14") == Some(-3.14)); - assert!(from_str(~"2.5E10") == Some(25000000000.)); - assert!(from_str(~"2.5e10") == Some(25000000000.)); - assert!(from_str(~"25000000000.E-10") == Some(2.5)); - assert!(from_str(~".") == Some(0.)); - assert!(from_str(~".e1") == Some(0.)); - assert!(from_str(~".e-1") == Some(0.)); - assert!(from_str(~"5.") == Some(5.)); - assert!(from_str(~".5") == Some(0.5)); - assert!(from_str(~"0.5") == Some(0.5)); - assert!(from_str(~"-.5") == Some(-0.5)); - assert!(from_str(~"-5") == Some(-5.)); - assert!(from_str(~"inf") == Some(infinity)); - assert!(from_str(~"+inf") == Some(infinity)); - assert!(from_str(~"-inf") == Some(neg_infinity)); - // note: NaN != NaN, hence this slightly complex test - match from_str(~"NaN") { - Some(f) => assert!(is_NaN(f)), - None => fail!() - } - // note: -0 == 0, hence these slightly more complex tests - match from_str(~"-0") { - Some(v) if is_zero(v) => assert!(is_negative(v)), - _ => fail!() - } - match from_str(~"0") { - Some(v) if is_zero(v) => assert!(is_positive(v)), - _ => fail!() - } - - assert!(from_str(~"").is_none()); - assert!(from_str(~"x").is_none()); - assert!(from_str(~" ").is_none()); - assert!(from_str(~" ").is_none()); - assert!(from_str(~"e").is_none()); - assert!(from_str(~"E").is_none()); - assert!(from_str(~"E1").is_none()); - assert!(from_str(~"1e1e1").is_none()); - assert!(from_str(~"1e1.1").is_none()); - assert!(from_str(~"1e1-1").is_none()); -} - -#[test] -pub fn test_from_str_hex() { - assert!(from_str_hex(~"a4") == Some(164.)); - assert!(from_str_hex(~"a4.fe") == Some(164.9921875)); - assert!(from_str_hex(~"-a4.fe") == Some(-164.9921875)); - assert!(from_str_hex(~"+a4.fe") == Some(164.9921875)); - assert!(from_str_hex(~"ff0P4") == Some(0xff00 as float)); - assert!(from_str_hex(~"ff0p4") == Some(0xff00 as float)); - assert!(from_str_hex(~"ff0p-4") == Some(0xff as float)); - assert!(from_str_hex(~".") == Some(0.)); - assert!(from_str_hex(~".p1") == Some(0.)); - assert!(from_str_hex(~".p-1") == Some(0.)); - assert!(from_str_hex(~"f.") == Some(15.)); - assert!(from_str_hex(~".f") == Some(0.9375)); - assert!(from_str_hex(~"0.f") == Some(0.9375)); - assert!(from_str_hex(~"-.f") == Some(-0.9375)); - assert!(from_str_hex(~"-f") == Some(-15.)); - assert!(from_str_hex(~"inf") == Some(infinity)); - assert!(from_str_hex(~"+inf") == Some(infinity)); - assert!(from_str_hex(~"-inf") == Some(neg_infinity)); - // note: NaN != NaN, hence this slightly complex test - match from_str_hex(~"NaN") { - Some(f) => assert!(is_NaN(f)), - None => fail!() - } - // note: -0 == 0, hence these slightly more complex tests - match from_str_hex(~"-0") { - Some(v) if is_zero(v) => assert!(is_negative(v)), - _ => fail!() - } - match from_str_hex(~"0") { - Some(v) if is_zero(v) => assert!(is_positive(v)), - _ => fail!() - } - assert!(from_str_hex(~"e") == Some(14.)); - assert!(from_str_hex(~"E") == Some(14.)); - assert!(from_str_hex(~"E1") == Some(225.)); - assert!(from_str_hex(~"1e1e1") == Some(123361.)); - assert!(from_str_hex(~"1e1.1") == Some(481.0625)); - - assert!(from_str_hex(~"").is_none()); - assert!(from_str_hex(~"x").is_none()); - assert!(from_str_hex(~" ").is_none()); - assert!(from_str_hex(~" ").is_none()); - assert!(from_str_hex(~"p").is_none()); - assert!(from_str_hex(~"P").is_none()); - assert!(from_str_hex(~"P1").is_none()); - assert!(from_str_hex(~"1p1p1").is_none()); - assert!(from_str_hex(~"1p1.1").is_none()); - assert!(from_str_hex(~"1p1-1").is_none()); -} - -#[test] -pub fn test_to_str_hex() { - assert!(to_str_hex(164.) == ~"a4"); - assert!(to_str_hex(164.9921875) == ~"a4.fe"); - assert!(to_str_hex(-164.9921875) == ~"-a4.fe"); - assert!(to_str_hex(0xff00 as float) == ~"ff00"); - assert!(to_str_hex(-(0xff00 as float)) == ~"-ff00"); - assert!(to_str_hex(0.) == ~"0"); - assert!(to_str_hex(15.) == ~"f"); - assert!(to_str_hex(-15.) == ~"-f"); - assert!(to_str_hex(0.9375) == ~"0.f"); - assert!(to_str_hex(-0.9375) == ~"-0.f"); - assert!(to_str_hex(infinity) == ~"inf"); - assert!(to_str_hex(neg_infinity) == ~"-inf"); - assert!(to_str_hex(NaN) == ~"NaN"); - assert!(to_str_hex(0.) == ~"0"); - assert!(to_str_hex(-0.) == ~"-0"); -} - -#[test] -pub fn test_to_str_radix() { - assert!(to_str_radix(36., 36u) == ~"10"); - assert!(to_str_radix(8.125, 2u) == ~"1000.001"); -} - -#[test] -pub fn test_from_str_radix() { - assert!(from_str_radix(~"10", 36u) == Some(36.)); - assert!(from_str_radix(~"1000.001", 2u) == Some(8.125)); -} - -#[test] -pub fn test_positive() { - assert!((is_positive(infinity))); - assert!((is_positive(1.))); - assert!((is_positive(0.))); - assert!((!is_positive(-1.))); - assert!((!is_positive(neg_infinity))); - assert!((!is_positive(1./neg_infinity))); - assert!((!is_positive(NaN))); -} - -#[test] -pub fn test_negative() { - assert!((!is_negative(infinity))); - assert!((!is_negative(1.))); - assert!((!is_negative(0.))); - assert!((is_negative(-1.))); - assert!((is_negative(neg_infinity))); - assert!((is_negative(1./neg_infinity))); - assert!((!is_negative(NaN))); -} - -#[test] -pub fn test_nonpositive() { - assert!((!is_nonpositive(infinity))); - assert!((!is_nonpositive(1.))); - assert!((!is_nonpositive(0.))); - assert!((is_nonpositive(-1.))); - assert!((is_nonpositive(neg_infinity))); - assert!((is_nonpositive(1./neg_infinity))); - assert!((!is_nonpositive(NaN))); -} - -#[test] -pub fn test_nonnegative() { - assert!((is_nonnegative(infinity))); - assert!((is_nonnegative(1.))); - assert!((is_nonnegative(0.))); - assert!((!is_nonnegative(-1.))); - assert!((!is_nonnegative(neg_infinity))); - assert!((!is_nonnegative(1./neg_infinity))); - assert!((!is_nonnegative(NaN))); -} - -#[test] -pub fn test_to_str_inf() { - assert!(to_str_digits(infinity, 10u) == ~"inf"); - assert!(to_str_digits(-infinity, 10u) == ~"-inf"); -} - -#[test] -pub fn test_round() { - assert!(round(5.8) == 6.0); - assert!(round(5.2) == 5.0); - assert!(round(3.0) == 3.0); - assert!(round(2.5) == 3.0); - assert!(round(-3.5) == -4.0); -} - -#[test] -pub fn test_num() { - let ten: float = num::cast(10); - let two: float = num::cast(2); - - assert!((ten.add(&two) == num::cast(12))); - assert!((ten.sub(&two) == num::cast(8))); - assert!((ten.mul(&two) == num::cast(20))); - assert!((ten.div(&two) == num::cast(5))); - assert!((ten.modulo(&two) == num::cast(0))); -} - -#[test] -fn test_numcast() { - assert!((20u == 20f.to_uint())); - assert!((20u8 == 20f.to_u8())); - assert!((20u16 == 20f.to_u16())); - assert!((20u32 == 20f.to_u32())); - assert!((20u64 == 20f.to_u64())); - assert!((20i == 20f.to_int())); - assert!((20i8 == 20f.to_i8())); - assert!((20i16 == 20f.to_i16())); - assert!((20i32 == 20f.to_i32())); - assert!((20i64 == 20f.to_i64())); - assert!((20f == 20f.to_float())); - assert!((20f32 == 20f.to_f32())); - assert!((20f64 == 20f.to_f64())); - - assert!((20f == NumCast::from(20u))); - assert!((20f == NumCast::from(20u8))); - assert!((20f == NumCast::from(20u16))); - assert!((20f == NumCast::from(20u32))); - assert!((20f == NumCast::from(20u64))); - assert!((20f == NumCast::from(20i))); - assert!((20f == NumCast::from(20i8))); - assert!((20f == NumCast::from(20i16))); - assert!((20f == NumCast::from(20i32))); - assert!((20f == NumCast::from(20i64))); - assert!((20f == NumCast::from(20f))); - assert!((20f == NumCast::from(20f32))); - assert!((20f == NumCast::from(20f64))); - - assert!((20f == num::cast(20u))); - assert!((20f == num::cast(20u8))); - assert!((20f == num::cast(20u16))); - assert!((20f == num::cast(20u32))); - assert!((20f == num::cast(20u64))); - assert!((20f == num::cast(20i))); - assert!((20f == num::cast(20i8))); - assert!((20f == num::cast(20i16))); - assert!((20f == num::cast(20i32))); - assert!((20f == num::cast(20i64))); - assert!((20f == num::cast(20f))); - assert!((20f == num::cast(20f32))); - assert!((20f == num::cast(20f64))); -} +#[cfg(test)] +mod tests { + use super::*; + use prelude::*; + #[test] + pub fn test_to_str_exact_do_decimal() { + let s = to_str_exact(5.0, 4u); + assert!(s == ~"5.0000"); + } + #[test] + pub fn test_from_str() { + assert!(from_str(~"3") == Some(3.)); + assert!(from_str(~"3.14") == Some(3.14)); + assert!(from_str(~"+3.14") == Some(3.14)); + assert!(from_str(~"-3.14") == Some(-3.14)); + assert!(from_str(~"2.5E10") == Some(25000000000.)); + assert!(from_str(~"2.5e10") == Some(25000000000.)); + assert!(from_str(~"25000000000.E-10") == Some(2.5)); + assert!(from_str(~".") == Some(0.)); + assert!(from_str(~".e1") == Some(0.)); + assert!(from_str(~".e-1") == Some(0.)); + assert!(from_str(~"5.") == Some(5.)); + assert!(from_str(~".5") == Some(0.5)); + assert!(from_str(~"0.5") == Some(0.5)); + assert!(from_str(~"-.5") == Some(-0.5)); + assert!(from_str(~"-5") == Some(-5.)); + assert!(from_str(~"inf") == Some(infinity)); + assert!(from_str(~"+inf") == Some(infinity)); + assert!(from_str(~"-inf") == Some(neg_infinity)); + // note: NaN != NaN, hence this slightly complex test + match from_str(~"NaN") { + Some(f) => assert!(is_NaN(f)), + None => fail!() + } + // note: -0 == 0, hence these slightly more complex tests + match from_str(~"-0") { + Some(v) if is_zero(v) => assert!(is_negative(v)), + _ => fail!() + } + match from_str(~"0") { + Some(v) if is_zero(v) => assert!(is_positive(v)), + _ => fail!() + } + + assert!(from_str(~"").is_none()); + assert!(from_str(~"x").is_none()); + assert!(from_str(~" ").is_none()); + assert!(from_str(~" ").is_none()); + assert!(from_str(~"e").is_none()); + assert!(from_str(~"E").is_none()); + assert!(from_str(~"E1").is_none()); + assert!(from_str(~"1e1e1").is_none()); + assert!(from_str(~"1e1.1").is_none()); + assert!(from_str(~"1e1-1").is_none()); + } + + #[test] + pub fn test_from_str_hex() { + assert!(from_str_hex(~"a4") == Some(164.)); + assert!(from_str_hex(~"a4.fe") == Some(164.9921875)); + assert!(from_str_hex(~"-a4.fe") == Some(-164.9921875)); + assert!(from_str_hex(~"+a4.fe") == Some(164.9921875)); + assert!(from_str_hex(~"ff0P4") == Some(0xff00 as float)); + assert!(from_str_hex(~"ff0p4") == Some(0xff00 as float)); + assert!(from_str_hex(~"ff0p-4") == Some(0xff as float)); + assert!(from_str_hex(~".") == Some(0.)); + assert!(from_str_hex(~".p1") == Some(0.)); + assert!(from_str_hex(~".p-1") == Some(0.)); + assert!(from_str_hex(~"f.") == Some(15.)); + assert!(from_str_hex(~".f") == Some(0.9375)); + assert!(from_str_hex(~"0.f") == Some(0.9375)); + assert!(from_str_hex(~"-.f") == Some(-0.9375)); + assert!(from_str_hex(~"-f") == Some(-15.)); + assert!(from_str_hex(~"inf") == Some(infinity)); + assert!(from_str_hex(~"+inf") == Some(infinity)); + assert!(from_str_hex(~"-inf") == Some(neg_infinity)); + // note: NaN != NaN, hence this slightly complex test + match from_str_hex(~"NaN") { + Some(f) => assert!(is_NaN(f)), + None => fail!() + } + // note: -0 == 0, hence these slightly more complex tests + match from_str_hex(~"-0") { + Some(v) if is_zero(v) => assert!(is_negative(v)), + _ => fail!() + } + match from_str_hex(~"0") { + Some(v) if is_zero(v) => assert!(is_positive(v)), + _ => fail!() + } + assert!(from_str_hex(~"e") == Some(14.)); + assert!(from_str_hex(~"E") == Some(14.)); + assert!(from_str_hex(~"E1") == Some(225.)); + assert!(from_str_hex(~"1e1e1") == Some(123361.)); + assert!(from_str_hex(~"1e1.1") == Some(481.0625)); + + assert!(from_str_hex(~"").is_none()); + assert!(from_str_hex(~"x").is_none()); + assert!(from_str_hex(~" ").is_none()); + assert!(from_str_hex(~" ").is_none()); + assert!(from_str_hex(~"p").is_none()); + assert!(from_str_hex(~"P").is_none()); + assert!(from_str_hex(~"P1").is_none()); + assert!(from_str_hex(~"1p1p1").is_none()); + assert!(from_str_hex(~"1p1.1").is_none()); + assert!(from_str_hex(~"1p1-1").is_none()); + } + + #[test] + pub fn test_to_str_hex() { + assert!(to_str_hex(164.) == ~"a4"); + assert!(to_str_hex(164.9921875) == ~"a4.fe"); + assert!(to_str_hex(-164.9921875) == ~"-a4.fe"); + assert!(to_str_hex(0xff00 as float) == ~"ff00"); + assert!(to_str_hex(-(0xff00 as float)) == ~"-ff00"); + assert!(to_str_hex(0.) == ~"0"); + assert!(to_str_hex(15.) == ~"f"); + assert!(to_str_hex(-15.) == ~"-f"); + assert!(to_str_hex(0.9375) == ~"0.f"); + assert!(to_str_hex(-0.9375) == ~"-0.f"); + assert!(to_str_hex(infinity) == ~"inf"); + assert!(to_str_hex(neg_infinity) == ~"-inf"); + assert!(to_str_hex(NaN) == ~"NaN"); + assert!(to_str_hex(0.) == ~"0"); + assert!(to_str_hex(-0.) == ~"-0"); + } + + #[test] + pub fn test_to_str_radix() { + assert!(to_str_radix(36., 36u) == ~"10"); + assert!(to_str_radix(8.125, 2u) == ~"1000.001"); + } + + #[test] + pub fn test_from_str_radix() { + assert!(from_str_radix(~"10", 36u) == Some(36.)); + assert!(from_str_radix(~"1000.001", 2u) == Some(8.125)); + } + + #[test] + pub fn test_positive() { + assert!((is_positive(infinity))); + assert!((is_positive(1.))); + assert!((is_positive(0.))); + assert!((!is_positive(-1.))); + assert!((!is_positive(neg_infinity))); + assert!((!is_positive(1./neg_infinity))); + assert!((!is_positive(NaN))); + } + + #[test] + pub fn test_negative() { + assert!((!is_negative(infinity))); + assert!((!is_negative(1.))); + assert!((!is_negative(0.))); + assert!((is_negative(-1.))); + assert!((is_negative(neg_infinity))); + assert!((is_negative(1./neg_infinity))); + assert!((!is_negative(NaN))); + } + + #[test] + pub fn test_nonpositive() { + assert!((!is_nonpositive(infinity))); + assert!((!is_nonpositive(1.))); + assert!((!is_nonpositive(0.))); + assert!((is_nonpositive(-1.))); + assert!((is_nonpositive(neg_infinity))); + assert!((is_nonpositive(1./neg_infinity))); + assert!((!is_nonpositive(NaN))); + } + + #[test] + pub fn test_nonnegative() { + assert!((is_nonnegative(infinity))); + assert!((is_nonnegative(1.))); + assert!((is_nonnegative(0.))); + assert!((!is_nonnegative(-1.))); + assert!((!is_nonnegative(neg_infinity))); + assert!((!is_nonnegative(1./neg_infinity))); + assert!((!is_nonnegative(NaN))); + } + + #[test] + pub fn test_to_str_inf() { + assert!(to_str_digits(infinity, 10u) == ~"inf"); + assert!(to_str_digits(-infinity, 10u) == ~"-inf"); + } + + #[test] + pub fn test_round() { + assert!(round(5.8) == 6.0); + assert!(round(5.2) == 5.0); + assert!(round(3.0) == 3.0); + assert!(round(2.5) == 3.0); + assert!(round(-3.5) == -4.0); + } +} // // Local Variables: diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index a3cbd9fe7e3a4..b495f9e7088fe 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -107,11 +107,15 @@ pub fn range_step(start: T, stop: T, step: T, it: &fn(T) -> bool) { } else if step > 0 { // ascending while i < stop { if !it(i) { break } + // avoiding overflow. break if i + step > max_value + if i > max_value - step { break; } i += step; } } else { // descending while i > stop { if !it(i) { break } + // avoiding underflow. break if i + step < min_value + if i < min_value - step { break; } i += step; } } @@ -202,21 +206,21 @@ impl ops::Neg for T { #[inline(always)] pub fn from_str(s: &str) -> Option { strconv::from_str_common(s, 10u, true, false, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } /// Parse a string as a number in the given base. #[inline(always)] pub fn from_str_radix(s: &str, radix: uint) -> Option { strconv::from_str_common(s, radix, true, false, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } /// Parse a byte slice as a number in the given base. #[inline(always)] pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { strconv::from_str_bytes_common(buf, radix, true, false, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } impl FromStr for T { @@ -273,177 +277,188 @@ impl ToStrRadix for T { } } -#[test] -fn test_from_str() { - assert!(from_str(~"0") == Some(0 as T)); - assert!(from_str(~"3") == Some(3 as T)); - assert!(from_str(~"10") == Some(10 as T)); - assert!(i32::from_str(~"123456789") == Some(123456789 as i32)); - assert!(from_str(~"00100") == Some(100 as T)); - - assert!(from_str(~"-1") == Some(-1 as T)); - assert!(from_str(~"-3") == Some(-3 as T)); - assert!(from_str(~"-10") == Some(-10 as T)); - assert!(i32::from_str(~"-123456789") == Some(-123456789 as i32)); - assert!(from_str(~"-00100") == Some(-100 as T)); - - assert!(from_str(~" ").is_none()); - assert!(from_str(~"x").is_none()); -} - -#[test] -fn test_parse_bytes() { - use str::to_bytes; - assert!(parse_bytes(to_bytes(~"123"), 10u) == Some(123 as T)); - assert!(parse_bytes(to_bytes(~"1001"), 2u) == Some(9 as T)); - assert!(parse_bytes(to_bytes(~"123"), 8u) == Some(83 as T)); - assert!(i32::parse_bytes(to_bytes(~"123"), 16u) == Some(291 as i32)); - assert!(i32::parse_bytes(to_bytes(~"ffff"), 16u) == - Some(65535 as i32)); - assert!(i32::parse_bytes(to_bytes(~"FFFF"), 16u) == - Some(65535 as i32)); - assert!(parse_bytes(to_bytes(~"z"), 36u) == Some(35 as T)); - assert!(parse_bytes(to_bytes(~"Z"), 36u) == Some(35 as T)); - - assert!(parse_bytes(to_bytes(~"-123"), 10u) == Some(-123 as T)); - assert!(parse_bytes(to_bytes(~"-1001"), 2u) == Some(-9 as T)); - assert!(parse_bytes(to_bytes(~"-123"), 8u) == Some(-83 as T)); - assert!(i32::parse_bytes(to_bytes(~"-123"), 16u) == - Some(-291 as i32)); - assert!(i32::parse_bytes(to_bytes(~"-ffff"), 16u) == - Some(-65535 as i32)); - assert!(i32::parse_bytes(to_bytes(~"-FFFF"), 16u) == - Some(-65535 as i32)); - assert!(parse_bytes(to_bytes(~"-z"), 36u) == Some(-35 as T)); - assert!(parse_bytes(to_bytes(~"-Z"), 36u) == Some(-35 as T)); - - assert!(parse_bytes(to_bytes(~"Z"), 35u).is_none()); - assert!(parse_bytes(to_bytes(~"-9"), 2u).is_none()); -} - -#[test] -fn test_to_str() { - assert!((to_str_radix(0 as T, 10u) == ~"0")); - assert!((to_str_radix(1 as T, 10u) == ~"1")); - assert!((to_str_radix(-1 as T, 10u) == ~"-1")); - assert!((to_str_radix(127 as T, 16u) == ~"7f")); - assert!((to_str_radix(100 as T, 10u) == ~"100")); +#[cfg(test)] +mod tests { + use super::*; + use super::inst::T; + use prelude::*; + + #[test] + fn test_from_str() { + assert!(from_str(~"0") == Some(0 as T)); + assert!(from_str(~"3") == Some(3 as T)); + assert!(from_str(~"10") == Some(10 as T)); + assert!(i32::from_str(~"123456789") == Some(123456789 as i32)); + assert!(from_str(~"00100") == Some(100 as T)); + + assert!(from_str(~"-1") == Some(-1 as T)); + assert!(from_str(~"-3") == Some(-3 as T)); + assert!(from_str(~"-10") == Some(-10 as T)); + assert!(i32::from_str(~"-123456789") == Some(-123456789 as i32)); + assert!(from_str(~"-00100") == Some(-100 as T)); + + assert!(from_str(~" ").is_none()); + assert!(from_str(~"x").is_none()); + } -} + #[test] + fn test_parse_bytes() { + use str::to_bytes; + assert!(parse_bytes(to_bytes(~"123"), 10u) == Some(123 as T)); + assert!(parse_bytes(to_bytes(~"1001"), 2u) == Some(9 as T)); + assert!(parse_bytes(to_bytes(~"123"), 8u) == Some(83 as T)); + assert!(i32::parse_bytes(to_bytes(~"123"), 16u) == Some(291 as i32)); + assert!(i32::parse_bytes(to_bytes(~"ffff"), 16u) == + Some(65535 as i32)); + assert!(i32::parse_bytes(to_bytes(~"FFFF"), 16u) == + Some(65535 as i32)); + assert!(parse_bytes(to_bytes(~"z"), 36u) == Some(35 as T)); + assert!(parse_bytes(to_bytes(~"Z"), 36u) == Some(35 as T)); + + assert!(parse_bytes(to_bytes(~"-123"), 10u) == Some(-123 as T)); + assert!(parse_bytes(to_bytes(~"-1001"), 2u) == Some(-9 as T)); + assert!(parse_bytes(to_bytes(~"-123"), 8u) == Some(-83 as T)); + assert!(i32::parse_bytes(to_bytes(~"-123"), 16u) == + Some(-291 as i32)); + assert!(i32::parse_bytes(to_bytes(~"-ffff"), 16u) == + Some(-65535 as i32)); + assert!(i32::parse_bytes(to_bytes(~"-FFFF"), 16u) == + Some(-65535 as i32)); + assert!(parse_bytes(to_bytes(~"-z"), 36u) == Some(-35 as T)); + assert!(parse_bytes(to_bytes(~"-Z"), 36u) == Some(-35 as T)); + + assert!(parse_bytes(to_bytes(~"Z"), 35u).is_none()); + assert!(parse_bytes(to_bytes(~"-9"), 2u).is_none()); + } -#[test] -fn test_int_to_str_overflow() { - let mut i8_val: i8 = 127_i8; - assert!((i8::to_str(i8_val) == ~"127")); + #[test] + fn test_to_str() { + assert!((to_str_radix(0 as T, 10u) == ~"0")); + assert!((to_str_radix(1 as T, 10u) == ~"1")); + assert!((to_str_radix(-1 as T, 10u) == ~"-1")); + assert!((to_str_radix(127 as T, 16u) == ~"7f")); + assert!((to_str_radix(100 as T, 10u) == ~"100")); - i8_val += 1 as i8; - assert!((i8::to_str(i8_val) == ~"-128")); + } - let mut i16_val: i16 = 32_767_i16; - assert!((i16::to_str(i16_val) == ~"32767")); + #[test] + fn test_int_to_str_overflow() { + let mut i8_val: i8 = 127_i8; + assert!((i8::to_str(i8_val) == ~"127")); - i16_val += 1 as i16; - assert!((i16::to_str(i16_val) == ~"-32768")); + i8_val += 1 as i8; + assert!((i8::to_str(i8_val) == ~"-128")); - let mut i32_val: i32 = 2_147_483_647_i32; - assert!((i32::to_str(i32_val) == ~"2147483647")); + let mut i16_val: i16 = 32_767_i16; + assert!((i16::to_str(i16_val) == ~"32767")); - i32_val += 1 as i32; - assert!((i32::to_str(i32_val) == ~"-2147483648")); + i16_val += 1 as i16; + assert!((i16::to_str(i16_val) == ~"-32768")); - let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert!((i64::to_str(i64_val) == ~"9223372036854775807")); + let mut i32_val: i32 = 2_147_483_647_i32; + assert!((i32::to_str(i32_val) == ~"2147483647")); - i64_val += 1 as i64; - assert!((i64::to_str(i64_val) == ~"-9223372036854775808")); -} + i32_val += 1 as i32; + assert!((i32::to_str(i32_val) == ~"-2147483648")); -#[test] -fn test_int_from_str_overflow() { - let mut i8_val: i8 = 127_i8; - assert!((i8::from_str(~"127") == Some(i8_val))); - assert!((i8::from_str(~"128").is_none())); + let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; + assert!((i64::to_str(i64_val) == ~"9223372036854775807")); - i8_val += 1 as i8; - assert!((i8::from_str(~"-128") == Some(i8_val))); - assert!((i8::from_str(~"-129").is_none())); + i64_val += 1 as i64; + assert!((i64::to_str(i64_val) == ~"-9223372036854775808")); + } - let mut i16_val: i16 = 32_767_i16; - assert!((i16::from_str(~"32767") == Some(i16_val))); - assert!((i16::from_str(~"32768").is_none())); + #[test] + fn test_int_from_str_overflow() { + let mut i8_val: i8 = 127_i8; + assert!((i8::from_str(~"127") == Some(i8_val))); + assert!((i8::from_str(~"128").is_none())); - i16_val += 1 as i16; - assert!((i16::from_str(~"-32768") == Some(i16_val))); - assert!((i16::from_str(~"-32769").is_none())); + i8_val += 1 as i8; + assert!((i8::from_str(~"-128") == Some(i8_val))); + assert!((i8::from_str(~"-129").is_none())); - let mut i32_val: i32 = 2_147_483_647_i32; - assert!((i32::from_str(~"2147483647") == Some(i32_val))); - assert!((i32::from_str(~"2147483648").is_none())); + let mut i16_val: i16 = 32_767_i16; + assert!((i16::from_str(~"32767") == Some(i16_val))); + assert!((i16::from_str(~"32768").is_none())); - i32_val += 1 as i32; - assert!((i32::from_str(~"-2147483648") == Some(i32_val))); - assert!((i32::from_str(~"-2147483649").is_none())); + i16_val += 1 as i16; + assert!((i16::from_str(~"-32768") == Some(i16_val))); + assert!((i16::from_str(~"-32769").is_none())); - let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; - assert!((i64::from_str(~"9223372036854775807") == Some(i64_val))); - assert!((i64::from_str(~"9223372036854775808").is_none())); + let mut i32_val: i32 = 2_147_483_647_i32; + assert!((i32::from_str(~"2147483647") == Some(i32_val))); + assert!((i32::from_str(~"2147483648").is_none())); - i64_val += 1 as i64; - assert!((i64::from_str(~"-9223372036854775808") == Some(i64_val))); - assert!((i64::from_str(~"-9223372036854775809").is_none())); -} + i32_val += 1 as i32; + assert!((i32::from_str(~"-2147483648") == Some(i32_val))); + assert!((i32::from_str(~"-2147483649").is_none())); -#[test] -pub fn test_num() { - let ten: T = num::cast(10); - let two: T = num::cast(2); + let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; + assert!((i64::from_str(~"9223372036854775807") == Some(i64_val))); + assert!((i64::from_str(~"9223372036854775808").is_none())); - assert!((ten.add(&two) == num::cast(12))); - assert!((ten.sub(&two) == num::cast(8))); - assert!((ten.mul(&two) == num::cast(20))); - assert!((ten.div(&two) == num::cast(5))); - assert!((ten.modulo(&two) == num::cast(0))); -} + i64_val += 1 as i64; + assert!((i64::from_str(~"-9223372036854775808") == Some(i64_val))); + assert!((i64::from_str(~"-9223372036854775809").is_none())); + } -#[test] -pub fn test_ranges() { - let mut l = ~[]; + #[test] + fn test_ranges() { + let mut l = ~[]; - for range(0,3) |i| { - l.push(i); - } - for range_rev(13,10) |i| { - l.push(i); - } - for range_step(20,26,2) |i| { - l.push(i); - } - for range_step(36,30,-2) |i| { - l.push(i); - } - assert!(l == ~[0,1,2, + for range(0,3) |i| { + l.push(i); + } + for range_rev(13,10) |i| { + l.push(i); + } + for range_step(20,26,2) |i| { + l.push(i); + } + for range_step(36,30,-2) |i| { + l.push(i); + } + for range_step(max_value - 2, max_value, 2) |i| { + l.push(i); + } + for range_step(max_value - 3, max_value, 2) |i| { + l.push(i); + } + for range_step(min_value + 2, min_value, -2) |i| { + l.push(i); + } + for range_step(min_value + 3, min_value, -2) |i| { + l.push(i); + } + assert_eq!(l, ~[0,1,2, 13,12,11, 20,22,24, - 36,34,32]); - - // None of the `fail`s should execute. - for range(10,0) |_i| { - fail!(~"unreachable"); - } - for range_rev(0,10) |_i| { - fail!(~"unreachable"); - } - for range_step(10,0,1) |_i| { - fail!(~"unreachable"); - } - for range_step(0,10,-1) |_i| { - fail!(~"unreachable"); + 36,34,32, + max_value-2, + max_value-3,max_value-1, + min_value+2, + min_value+3,min_value+1]); + + // None of the `fail`s should execute. + for range(10,0) |_i| { + fail!(~"unreachable"); + } + for range_rev(0,10) |_i| { + fail!(~"unreachable"); + } + for range_step(10,0,1) |_i| { + fail!(~"unreachable"); + } + for range_step(0,10,-1) |_i| { + fail!(~"unreachable"); + } } -} -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_range_step_zero_step() { - for range_step(0,10,0) |_i| {} -} + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_range_step_zero_step() { + for range_step(0,10,0) |_i| {} + } +} \ No newline at end of file diff --git a/src/libcore/num/int-template/i16.rs b/src/libcore/num/int-template/i16.rs index 76be224af15b9..34dcd50839785 100644 --- a/src/libcore/num/int-template/i16.rs +++ b/src/libcore/num/int-template/i16.rs @@ -10,78 +10,7 @@ //! Operations and constants for `i16` -use num::NumCast; - mod inst { pub type T = i16; pub static bits: uint = ::u16::bits; } - -impl NumCast for i16 { - /** - * Cast `n` to a `i16` - */ - #[inline(always)] - fn from(n: N) -> i16 { n.to_i16() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20i16.to_uint())); - assert!((20u8 == 20i16.to_u8())); - assert!((20u16 == 20i16.to_u16())); - assert!((20u32 == 20i16.to_u32())); - assert!((20u64 == 20i16.to_u64())); - assert!((20i == 20i16.to_int())); - assert!((20i8 == 20i16.to_i8())); - assert!((20i16 == 20i16.to_i16())); - assert!((20i32 == 20i16.to_i32())); - assert!((20i64 == 20i16.to_i64())); - assert!((20f == 20i16.to_float())); - assert!((20f32 == 20i16.to_f32())); - assert!((20f64 == 20i16.to_f64())); - - assert!((20i16 == NumCast::from(20u))); - assert!((20i16 == NumCast::from(20u8))); - assert!((20i16 == NumCast::from(20u16))); - assert!((20i16 == NumCast::from(20u32))); - assert!((20i16 == NumCast::from(20u64))); - assert!((20i16 == NumCast::from(20i))); - assert!((20i16 == NumCast::from(20i8))); - assert!((20i16 == NumCast::from(20i16))); - assert!((20i16 == NumCast::from(20i32))); - assert!((20i16 == NumCast::from(20i64))); - assert!((20i16 == NumCast::from(20f))); - assert!((20i16 == NumCast::from(20f32))); - assert!((20i16 == NumCast::from(20f64))); - - assert!((20i16 == num::cast(20u))); - assert!((20i16 == num::cast(20u8))); - assert!((20i16 == num::cast(20u16))); - assert!((20i16 == num::cast(20u32))); - assert!((20i16 == num::cast(20u64))); - assert!((20i16 == num::cast(20i))); - assert!((20i16 == num::cast(20i8))); - assert!((20i16 == num::cast(20i16))); - assert!((20i16 == num::cast(20i32))); - assert!((20i16 == num::cast(20i64))); - assert!((20i16 == num::cast(20f))); - assert!((20i16 == num::cast(20f32))); - assert!((20i16 == num::cast(20f64))); -} diff --git a/src/libcore/num/int-template/i32.rs b/src/libcore/num/int-template/i32.rs index 596d29aa2910a..91eea0e8d4709 100644 --- a/src/libcore/num/int-template/i32.rs +++ b/src/libcore/num/int-template/i32.rs @@ -10,78 +10,7 @@ //! Operations and constants for `i32` -use num::NumCast; - mod inst { pub type T = i32; pub static bits: uint = ::u32::bits; } - -impl NumCast for i32 { - /** - * Cast `n` to a `i32` - */ - #[inline(always)] - fn from(n: N) -> i32 { n.to_i32() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20i32.to_uint())); - assert!((20u8 == 20i32.to_u8())); - assert!((20u16 == 20i32.to_u16())); - assert!((20u32 == 20i32.to_u32())); - assert!((20u64 == 20i32.to_u64())); - assert!((20i == 20i32.to_int())); - assert!((20i8 == 20i32.to_i8())); - assert!((20i16 == 20i32.to_i16())); - assert!((20i32 == 20i32.to_i32())); - assert!((20i64 == 20i32.to_i64())); - assert!((20f == 20i32.to_float())); - assert!((20f32 == 20i32.to_f32())); - assert!((20f64 == 20i32.to_f64())); - - assert!((20i32 == NumCast::from(20u))); - assert!((20i32 == NumCast::from(20u8))); - assert!((20i32 == NumCast::from(20u16))); - assert!((20i32 == NumCast::from(20u32))); - assert!((20i32 == NumCast::from(20u64))); - assert!((20i32 == NumCast::from(20i))); - assert!((20i32 == NumCast::from(20i8))); - assert!((20i32 == NumCast::from(20i16))); - assert!((20i32 == NumCast::from(20i32))); - assert!((20i32 == NumCast::from(20i64))); - assert!((20i32 == NumCast::from(20f))); - assert!((20i32 == NumCast::from(20f32))); - assert!((20i32 == NumCast::from(20f64))); - - assert!((20i32 == num::cast(20u))); - assert!((20i32 == num::cast(20u8))); - assert!((20i32 == num::cast(20u16))); - assert!((20i32 == num::cast(20u32))); - assert!((20i32 == num::cast(20u64))); - assert!((20i32 == num::cast(20i))); - assert!((20i32 == num::cast(20i8))); - assert!((20i32 == num::cast(20i16))); - assert!((20i32 == num::cast(20i32))); - assert!((20i32 == num::cast(20i64))); - assert!((20i32 == num::cast(20f))); - assert!((20i32 == num::cast(20f32))); - assert!((20i32 == num::cast(20f64))); -} diff --git a/src/libcore/num/int-template/i64.rs b/src/libcore/num/int-template/i64.rs index d02c46d939310..3834a1e2a0387 100644 --- a/src/libcore/num/int-template/i64.rs +++ b/src/libcore/num/int-template/i64.rs @@ -10,78 +10,7 @@ //! Operations and constants for `i64` -use num::NumCast; - mod inst { pub type T = i64; pub static bits: uint = ::u64::bits; } - -impl NumCast for i64 { - /** - * Cast `n` to a `i64` - */ - #[inline(always)] - fn from(n: N) -> i64 { n.to_i64() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20i64.to_uint())); - assert!((20u8 == 20i64.to_u8())); - assert!((20u16 == 20i64.to_u16())); - assert!((20u32 == 20i64.to_u32())); - assert!((20u64 == 20i64.to_u64())); - assert!((20i == 20i64.to_int())); - assert!((20i8 == 20i64.to_i8())); - assert!((20i16 == 20i64.to_i16())); - assert!((20i32 == 20i64.to_i32())); - assert!((20i64 == 20i64.to_i64())); - assert!((20f == 20i64.to_float())); - assert!((20f32 == 20i64.to_f32())); - assert!((20f64 == 20i64.to_f64())); - - assert!((20i64 == NumCast::from(20u))); - assert!((20i64 == NumCast::from(20u8))); - assert!((20i64 == NumCast::from(20u16))); - assert!((20i64 == NumCast::from(20u32))); - assert!((20i64 == NumCast::from(20u64))); - assert!((20i64 == NumCast::from(20i))); - assert!((20i64 == NumCast::from(20i8))); - assert!((20i64 == NumCast::from(20i16))); - assert!((20i64 == NumCast::from(20i32))); - assert!((20i64 == NumCast::from(20i64))); - assert!((20i64 == NumCast::from(20f))); - assert!((20i64 == NumCast::from(20f32))); - assert!((20i64 == NumCast::from(20f64))); - - assert!((20i64 == num::cast(20u))); - assert!((20i64 == num::cast(20u8))); - assert!((20i64 == num::cast(20u16))); - assert!((20i64 == num::cast(20u32))); - assert!((20i64 == num::cast(20u64))); - assert!((20i64 == num::cast(20i))); - assert!((20i64 == num::cast(20i8))); - assert!((20i64 == num::cast(20i16))); - assert!((20i64 == num::cast(20i32))); - assert!((20i64 == num::cast(20i64))); - assert!((20i64 == num::cast(20f))); - assert!((20i64 == num::cast(20f32))); - assert!((20i64 == num::cast(20f64))); -} diff --git a/src/libcore/num/int-template/i8.rs b/src/libcore/num/int-template/i8.rs index c0dd6e01d4b7f..9486ed748d7d0 100644 --- a/src/libcore/num/int-template/i8.rs +++ b/src/libcore/num/int-template/i8.rs @@ -10,78 +10,7 @@ //! Operations and constants for `i8` -use num::NumCast; - mod inst { pub type T = i8; pub static bits: uint = ::u8::bits; } - -impl NumCast for i8 { - /** - * Cast `n` to a `i8` - */ - #[inline(always)] - fn from(n: N) -> i8 { n.to_i8() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20i8.to_uint())); - assert!((20u8 == 20i8.to_u8())); - assert!((20u16 == 20i8.to_u16())); - assert!((20u32 == 20i8.to_u32())); - assert!((20u64 == 20i8.to_u64())); - assert!((20i == 20i8.to_int())); - assert!((20i8 == 20i8.to_i8())); - assert!((20i16 == 20i8.to_i16())); - assert!((20i32 == 20i8.to_i32())); - assert!((20i64 == 20i8.to_i64())); - assert!((20f == 20i8.to_float())); - assert!((20f32 == 20i8.to_f32())); - assert!((20f64 == 20i8.to_f64())); - - assert!((20i8 == NumCast::from(20u))); - assert!((20i8 == NumCast::from(20u8))); - assert!((20i8 == NumCast::from(20u16))); - assert!((20i8 == NumCast::from(20u32))); - assert!((20i8 == NumCast::from(20u64))); - assert!((20i8 == NumCast::from(20i))); - assert!((20i8 == NumCast::from(20i8))); - assert!((20i8 == NumCast::from(20i16))); - assert!((20i8 == NumCast::from(20i32))); - assert!((20i8 == NumCast::from(20i64))); - assert!((20i8 == NumCast::from(20f))); - assert!((20i8 == NumCast::from(20f32))); - assert!((20i8 == NumCast::from(20f64))); - - assert!((20i8 == num::cast(20u))); - assert!((20i8 == num::cast(20u8))); - assert!((20i8 == num::cast(20u16))); - assert!((20i8 == num::cast(20u32))); - assert!((20i8 == num::cast(20u64))); - assert!((20i8 == num::cast(20i))); - assert!((20i8 == num::cast(20i8))); - assert!((20i8 == num::cast(20i16))); - assert!((20i8 == num::cast(20i32))); - assert!((20i8 == num::cast(20i64))); - assert!((20i8 == num::cast(20f))); - assert!((20i8 == num::cast(20f32))); - assert!((20i8 == num::cast(20f64))); -} diff --git a/src/libcore/num/int-template/int.rs b/src/libcore/num/int-template/int.rs index ea8aec1222438..6649b364015d3 100644 --- a/src/libcore/num/int-template/int.rs +++ b/src/libcore/num/int-template/int.rs @@ -10,8 +10,6 @@ //! Operations and constants for `int` -use num::NumCast; - pub use self::inst::pow; mod inst { @@ -57,72 +55,3 @@ mod inst { assert!((::int::min_value + ::int::max_value + 1 == 0)); } } - -impl NumCast for int { - /** - * Cast `n` to a `int` - */ - #[inline(always)] - fn from(n: N) -> int { n.to_int() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20i.to_uint())); - assert!((20u8 == 20i.to_u8())); - assert!((20u16 == 20i.to_u16())); - assert!((20u32 == 20i.to_u32())); - assert!((20u64 == 20i.to_u64())); - assert!((20i == 20i.to_int())); - assert!((20i8 == 20i.to_i8())); - assert!((20i16 == 20i.to_i16())); - assert!((20i32 == 20i.to_i32())); - assert!((20i64 == 20i.to_i64())); - assert!((20f == 20i.to_float())); - assert!((20f32 == 20i.to_f32())); - assert!((20f64 == 20i.to_f64())); - - assert!((20i == NumCast::from(20u))); - assert!((20i == NumCast::from(20u8))); - assert!((20i == NumCast::from(20u16))); - assert!((20i == NumCast::from(20u32))); - assert!((20i == NumCast::from(20u64))); - assert!((20i == NumCast::from(20i))); - assert!((20i == NumCast::from(20i8))); - assert!((20i == NumCast::from(20i16))); - assert!((20i == NumCast::from(20i32))); - assert!((20i == NumCast::from(20i64))); - assert!((20i == NumCast::from(20f))); - assert!((20i == NumCast::from(20f32))); - assert!((20i == NumCast::from(20f64))); - - assert!((20i == num::cast(20u))); - assert!((20i == num::cast(20u8))); - assert!((20i == num::cast(20u16))); - assert!((20i == num::cast(20u32))); - assert!((20i == num::cast(20u64))); - assert!((20i == num::cast(20i))); - assert!((20i == num::cast(20i8))); - assert!((20i == num::cast(20i16))); - assert!((20i == num::cast(20i32))); - assert!((20i == num::cast(20i64))); - assert!((20i == num::cast(20f))); - assert!((20i == num::cast(20f32))); - assert!((20i == num::cast(20f64))); -} diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index daa36f9dc32f5..19a1e276d3754 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -9,13 +9,35 @@ // except according to those terms. //! An interface for numeric types -use cmp::Ord; -use ops::{Div, Mul, Neg}; +use cmp::{Eq, Ord}; +use ops::{Neg, Add, Sub, Mul, Div, Modulo}; use option::Option; use kinds::Copy; pub mod strconv; +pub trait Num: Eq + Zero + One + + Neg + + Add + + Sub + + Mul + + Div + + Modulo {} + +impl Num for u8 {} +impl Num for u16 {} +impl Num for u32 {} +impl Num for u64 {} +impl Num for uint {} +impl Num for i8 {} +impl Num for i16 {} +impl Num for i32 {} +impl Num for i64 {} +impl Num for int {} +impl Num for f32 {} +impl Num for f64 {} +impl Num for float {} + pub trait IntConvertible { fn to_int(&self) -> int; fn from_int(n: int) -> Self; @@ -49,7 +71,7 @@ pub enum RoundMode { } /** - * Cast a number the the enclosing type + * Cast from one machine scalar to another * * # Example * @@ -64,7 +86,7 @@ pub fn cast(n: T) -> U { } /** - * An interface for generic numeric type casts + * An interface for casting between machine scalars */ pub trait NumCast { fn from(n: T) -> Self; @@ -86,6 +108,49 @@ pub trait NumCast { fn to_float(&self) -> float; } +macro_rules! impl_num_cast( + ($T:ty, $conv:ident) => ( + impl NumCast for $T { + #[inline(always)] + fn from(n: N) -> $T { + // `$conv` could be generated using `concat_idents!`, but that + // macro seems to be broken at the moment + n.$conv() + } + + #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } + #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } + #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } + #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } + #[inline(always)] fn to_uint(&self) -> uint { *self as uint } + + #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } + #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } + #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } + #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } + #[inline(always)] fn to_int(&self) -> int { *self as int } + + #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } + #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } + #[inline(always)] fn to_float(&self) -> float { *self as float } + } + ) +) + +impl_num_cast!(u8, to_u8) +impl_num_cast!(u16, to_u16) +impl_num_cast!(u32, to_u32) +impl_num_cast!(u64, to_u64) +impl_num_cast!(uint, to_uint) +impl_num_cast!(i8, to_i8) +impl_num_cast!(i16, to_i16) +impl_num_cast!(i32, to_i32) +impl_num_cast!(i64, to_i64) +impl_num_cast!(int, to_int) +impl_num_cast!(f32, to_f32) +impl_num_cast!(f64, to_f64) +impl_num_cast!(float, to_float) + pub trait ToStrRadix { pub fn to_str_radix(&self, radix: uint) -> ~str; } @@ -129,3 +194,93 @@ pub fn pow_with_uint+Mul>( total } +#[cfg(test)] +fn test_num(ten: T, two: T) { + assert!(ten.add(&two) == cast(12)); + assert!(ten.sub(&two) == cast(8)); + assert!(ten.mul(&two) == cast(20)); + assert!(ten.div(&two) == cast(5)); + assert!(ten.modulo(&two) == cast(0)); + + assert!(ten.add(&two) == ten + two); + assert!(ten.sub(&two) == ten - two); + assert!(ten.mul(&two) == ten * two); + assert!(ten.div(&two) == ten / two); + assert!(ten.modulo(&two) == ten % two); +} + +#[test] fn test_u8_num() { test_num(10u8, 2u8) } +#[test] fn test_u16_num() { test_num(10u16, 2u16) } +#[test] fn test_u32_num() { test_num(10u32, 2u32) } +#[test] fn test_u64_num() { test_num(10u64, 2u64) } +#[test] fn test_uint_num() { test_num(10u, 2u) } +#[test] fn test_i8_num() { test_num(10i8, 2i8) } +#[test] fn test_i16_num() { test_num(10i16, 2i16) } +#[test] fn test_i32_num() { test_num(10i32, 2i32) } +#[test] fn test_i64_num() { test_num(10i64, 2i64) } +#[test] fn test_int_num() { test_num(10i, 2i) } +#[test] fn test_f32_num() { test_num(10f32, 2f32) } +#[test] fn test_f64_num() { test_num(10f64, 2f64) } +#[test] fn test_float_num() { test_num(10f, 2f) } + +macro_rules! test_cast_20( + ($_20:expr) => ({ + let _20 = $_20; + + assert!(20u == _20.to_uint()); + assert!(20u8 == _20.to_u8()); + assert!(20u16 == _20.to_u16()); + assert!(20u32 == _20.to_u32()); + assert!(20u64 == _20.to_u64()); + assert!(20i == _20.to_int()); + assert!(20i8 == _20.to_i8()); + assert!(20i16 == _20.to_i16()); + assert!(20i32 == _20.to_i32()); + assert!(20i64 == _20.to_i64()); + assert!(20f == _20.to_float()); + assert!(20f32 == _20.to_f32()); + assert!(20f64 == _20.to_f64()); + + assert!(_20 == NumCast::from(20u)); + assert!(_20 == NumCast::from(20u8)); + assert!(_20 == NumCast::from(20u16)); + assert!(_20 == NumCast::from(20u32)); + assert!(_20 == NumCast::from(20u64)); + assert!(_20 == NumCast::from(20i)); + assert!(_20 == NumCast::from(20i8)); + assert!(_20 == NumCast::from(20i16)); + assert!(_20 == NumCast::from(20i32)); + assert!(_20 == NumCast::from(20i64)); + assert!(_20 == NumCast::from(20f)); + assert!(_20 == NumCast::from(20f32)); + assert!(_20 == NumCast::from(20f64)); + + assert!(_20 == cast(20u)); + assert!(_20 == cast(20u8)); + assert!(_20 == cast(20u16)); + assert!(_20 == cast(20u32)); + assert!(_20 == cast(20u64)); + assert!(_20 == cast(20i)); + assert!(_20 == cast(20i8)); + assert!(_20 == cast(20i16)); + assert!(_20 == cast(20i32)); + assert!(_20 == cast(20i64)); + assert!(_20 == cast(20f)); + assert!(_20 == cast(20f32)); + assert!(_20 == cast(20f64)); + }) +) + +#[test] fn test_u8_cast() { test_cast_20!(20u8) } +#[test] fn test_u16_cast() { test_cast_20!(20u16) } +#[test] fn test_u32_cast() { test_cast_20!(20u32) } +#[test] fn test_u64_cast() { test_cast_20!(20u64) } +#[test] fn test_uint_cast() { test_cast_20!(20u) } +#[test] fn test_i8_cast() { test_cast_20!(20i8) } +#[test] fn test_i16_cast() { test_cast_20!(20i16) } +#[test] fn test_i32_cast() { test_cast_20!(20i32) } +#[test] fn test_i64_cast() { test_cast_20!(20i64) } +#[test] fn test_int_cast() { test_cast_20!(20i) } +#[test] fn test_f32_cast() { test_cast_20!(20f32) } +#[test] fn test_f64_cast() { test_cast_20!(20f64) } +#[test] fn test_float_cast() { test_cast_20!(20f) } diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs index 5299203eb4273..de699a3756b6e 100644 --- a/src/libcore/num/strconv.rs +++ b/src/libcore/num/strconv.rs @@ -228,10 +228,8 @@ pub fn to_str_bytes_common break if deccum == _0 { break; } @@ -247,21 +245,15 @@ pub fn to_str_bytes_common { - unsafe { // FIXME: Pureness workaround (#4568) - buf.push('-' as u8); - } + buf.push('-' as u8); } SignAll => { - unsafe { // FIXME: Pureness workaround (#4568) - buf.push('+' as u8); - } + buf.push('+' as u8); } _ => () } - unsafe { // FIXME: Pureness workaround (#4568) - vec::reverse(buf); - } + vec::reverse(buf); // Remember start of the fractional digits. // Points one beyond end of buf if none get generated, @@ -271,9 +263,7 @@ pub fn to_str_bytes_common 0) { - unsafe { // FIXME: Pureness workaround (#4568) - buf.push('.' as u8); - } + buf.push('.' as u8); let mut dig = 0u; // calculate new digits while @@ -299,10 +289,8 @@ pub fn to_str_bytes_common= radix / 2 { // -> need to round - let mut i: int = buf.len() as int - 1; - loop { - // If reached left end of number, have to - // insert additional digit: - if i < 0 - || buf[i] == '-' as u8 - || buf[i] == '+' as u8 { - buf.insert((i + 1) as uint, value2ascii(1)); - break; - } - - // Skip the '.' - if buf[i] == '.' as u8 { i -= 1; loop; } - - // Either increment the digit, - // or set to 0 if max and carry the 1. - let current_digit = ascii2value(buf[i]); - if current_digit < (radix - 1) { - buf[i] = value2ascii(current_digit+1); - break; - } else { - buf[i] = value2ascii(0); - i -= 1; - } + let extra_digit = ascii2value(buf.pop()); + if extra_digit >= radix / 2 { // -> need to round + let mut i: int = buf.len() as int - 1; + loop { + // If reached left end of number, have to + // insert additional digit: + if i < 0 + || buf[i] == '-' as u8 + || buf[i] == '+' as u8 { + buf.insert((i + 1) as uint, value2ascii(1)); + break; + } + + // Skip the '.' + if buf[i] == '.' as u8 { i -= 1; loop; } + + // Either increment the digit, + // or set to 0 if max and carry the 1. + let current_digit = ascii2value(buf[i]); + if current_digit < (radix - 1) { + buf[i] = value2ascii(current_digit+1); + break; + } else { + buf[i] = value2ascii(0); + i -= 1; } } } @@ -429,6 +415,8 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; * `FFp128`. The exponent string itself is always base 10. * Can conflict with `radix`, see Failure. * - `empty_zero` - Whether to accept a empty `buf` as a 0 or not. + * - `ignore_underscores` - Whether all underscores within the string should + * be ignored. * * # Return value * Returns `Some(n)` if `buf` parses to a number n without overflowing, and @@ -443,16 +431,13 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; * between digit and exponent sign `'p'`. * - Fails if `radix` > 18 and `special == true` due to conflict * between digit and lowest first character in `inf` and `NaN`, the `'i'`. - * - * # Possible improvements - * - Could accept option to allow ignoring underscores, allowing for numbers - * formated like `FF_AE_FF_FF`. */ -pub fn from_str_bytes_common+ +pub fn from_str_bytes_common+ Mul+Sub+Neg+Add+ NumStrConv>( buf: &[u8], radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool + special: bool, exponent: ExponentFormat, empty_zero: bool, + ignore_underscores: bool ) -> Option { match exponent { ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' @@ -531,12 +516,16 @@ pub fn from_str_bytes_common+ accum -= cast(digit as int); } - // Detect overflow by comparing to last value - if accum_positive && accum < last_accum { return None; } - if !accum_positive && accum > last_accum { return None; } + // Detect overflow by comparing to last value, except + // if we've not seen any non-zero digits. + if last_accum != _0 { + if accum_positive && accum <= last_accum { return None; } + if !accum_positive && accum >= last_accum { return None; } + } last_accum = accum; } None => match c { + '_' if ignore_underscores => {} 'e' | 'E' | 'p' | 'P' => { exp_found = true; break; // start of exponent @@ -580,6 +569,7 @@ pub fn from_str_bytes_common+ last_accum = accum; } None => match c { + '_' if ignore_underscores => {} 'e' | 'E' | 'p' | 'P' => { exp_found = true; break; // start of exponent @@ -607,6 +597,7 @@ pub fn from_str_bytes_common+ if exp_found { let c = buf[i] as char; let base = match (c, exponent) { + // c is never _ so don't need to handle specially ('e', ExpDec) | ('E', ExpDec) => 10u, ('p', ExpBin) | ('P', ExpBin) => 2u, _ => return None // char doesn't fit given exponent format @@ -615,7 +606,8 @@ pub fn from_str_bytes_common+ // parse remaining bytes as decimal integer, // skipping the exponent char let exp: Option = from_str_bytes_common( - buf.slice(i+1, len), 10, true, false, false, ExpNone, false); + buf.slice(i+1, len), 10, true, false, false, ExpNone, false, + ignore_underscores); match exp { Some(exp_pow) => { @@ -637,11 +629,44 @@ pub fn from_str_bytes_common+ * `from_str_bytes_common()`, for details see there. */ #[inline(always)] -pub fn from_str_common+Mul+ +pub fn from_str_common+Mul+ Sub+Neg+Add+NumStrConv>( buf: &str, radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool + special: bool, exponent: ExponentFormat, empty_zero: bool, + ignore_underscores: bool ) -> Option { from_str_bytes_common(str::to_bytes(buf), radix, negative, - fractional, special, exponent, empty_zero) + fractional, special, exponent, empty_zero, + ignore_underscores) +} + +#[cfg(test)] +mod test { + use super::*; + use option::*; + + #[test] + fn from_str_ignore_underscores() { + let s : Option = from_str_common("__1__", 2, false, false, false, + ExpNone, false, true); + assert_eq!(s, Some(1u8)); + + let n : Option = from_str_common("__1__", 2, false, false, false, + ExpNone, false, false); + assert_eq!(n, None); + + let f : Option = from_str_common("_1_._1_e_1_", 10, false, true, false, + ExpDec, false, true); + assert_eq!(f, Some(1.1e1f32)); + } + + #[test] + fn from_str_issue5770() { + // try to parse 0b1_1111_1111 = 511 as a u8. Caused problems + // since 255*2+1 == 255 (mod 256) so the overflow wasn't + // detected. + let n : Option = from_str_common("111111111", 2, false, false, false, + ExpNone, false, false); + assert_eq!(n, None); + } } diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 400417284a279..af6557e9881f2 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -78,12 +78,15 @@ pub fn range_step(start: T, if step >= 0 { while i < stop { if !it(i) { break } + // avoiding overflow. break if i + step > max_value + if i > max_value - (step as T) { break; } i += step as T; } - } - else { + } else { while i > stop { if !it(i) { break } + // avoiding underflow. break if i + step < min_value + if i < min_value + ((-step) as T) { break; } i -= -step as T; } } @@ -168,21 +171,21 @@ impl ops::Neg for T { #[inline(always)] pub fn from_str(s: &str) -> Option { strconv::from_str_common(s, 10u, false, false, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } /// Parse a string as a number in the given base. #[inline(always)] pub fn from_str_radix(s: &str, radix: uint) -> Option { strconv::from_str_common(s, radix, false, false, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } /// Parse a byte slice as a number in the given base. #[inline(always)] pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { strconv::from_str_bytes_common(buf, radix, false, false, false, - strconv::ExpNone, false) + strconv::ExpNone, false, false) } impl FromStr for T { @@ -239,180 +242,190 @@ impl ToStrRadix for T { } } -#[test] -pub fn test_to_str() { - assert!(to_str_radix(0 as T, 10u) == ~"0"); - assert!(to_str_radix(1 as T, 10u) == ~"1"); - assert!(to_str_radix(2 as T, 10u) == ~"2"); - assert!(to_str_radix(11 as T, 10u) == ~"11"); - assert!(to_str_radix(11 as T, 16u) == ~"b"); - assert!(to_str_radix(255 as T, 16u) == ~"ff"); - assert!(to_str_radix(0xff as T, 10u) == ~"255"); -} +#[cfg(test)] +mod tests { + use super::*; + use super::inst::T; + use prelude::*; + #[test] + pub fn test_to_str() { + assert!(to_str_radix(0 as T, 10u) == ~"0"); + assert!(to_str_radix(1 as T, 10u) == ~"1"); + assert!(to_str_radix(2 as T, 10u) == ~"2"); + assert!(to_str_radix(11 as T, 10u) == ~"11"); + assert!(to_str_radix(11 as T, 16u) == ~"b"); + assert!(to_str_radix(255 as T, 16u) == ~"ff"); + assert!(to_str_radix(0xff as T, 10u) == ~"255"); + } -#[test] -pub fn test_from_str() { - assert!(from_str(~"0") == Some(0u as T)); - assert!(from_str(~"3") == Some(3u as T)); - assert!(from_str(~"10") == Some(10u as T)); - assert!(u32::from_str(~"123456789") == Some(123456789 as u32)); - assert!(from_str(~"00100") == Some(100u as T)); - - assert!(from_str(~"").is_none()); - assert!(from_str(~" ").is_none()); - assert!(from_str(~"x").is_none()); -} + #[test] + pub fn test_from_str() { + assert!(from_str(~"0") == Some(0u as T)); + assert!(from_str(~"3") == Some(3u as T)); + assert!(from_str(~"10") == Some(10u as T)); + assert!(u32::from_str(~"123456789") == Some(123456789 as u32)); + assert!(from_str(~"00100") == Some(100u as T)); + + assert!(from_str(~"").is_none()); + assert!(from_str(~" ").is_none()); + assert!(from_str(~"x").is_none()); + } -#[test] -pub fn test_parse_bytes() { - use str::to_bytes; - assert!(parse_bytes(to_bytes(~"123"), 10u) == Some(123u as T)); - assert!(parse_bytes(to_bytes(~"1001"), 2u) == Some(9u as T)); - assert!(parse_bytes(to_bytes(~"123"), 8u) == Some(83u as T)); - assert!(u16::parse_bytes(to_bytes(~"123"), 16u) == - Some(291u as u16)); - assert!(u16::parse_bytes(to_bytes(~"ffff"), 16u) == - Some(65535u as u16)); - assert!(parse_bytes(to_bytes(~"z"), 36u) == Some(35u as T)); - - assert!(parse_bytes(to_bytes(~"Z"), 10u).is_none()); - assert!(parse_bytes(to_bytes(~"_"), 2u).is_none()); -} + #[test] + pub fn test_parse_bytes() { + use str::to_bytes; + assert!(parse_bytes(to_bytes(~"123"), 10u) == Some(123u as T)); + assert!(parse_bytes(to_bytes(~"1001"), 2u) == Some(9u as T)); + assert!(parse_bytes(to_bytes(~"123"), 8u) == Some(83u as T)); + assert!(u16::parse_bytes(to_bytes(~"123"), 16u) == + Some(291u as u16)); + assert!(u16::parse_bytes(to_bytes(~"ffff"), 16u) == + Some(65535u as u16)); + assert!(parse_bytes(to_bytes(~"z"), 36u) == Some(35u as T)); + + assert!(parse_bytes(to_bytes(~"Z"), 10u).is_none()); + assert!(parse_bytes(to_bytes(~"_"), 2u).is_none()); + } -#[test] -fn test_uint_to_str_overflow() { - let mut u8_val: u8 = 255_u8; - assert!((u8::to_str(u8_val) == ~"255")); + #[test] + fn test_uint_to_str_overflow() { + let mut u8_val: u8 = 255_u8; + assert!((u8::to_str(u8_val) == ~"255")); - u8_val += 1 as u8; - assert!((u8::to_str(u8_val) == ~"0")); + u8_val += 1 as u8; + assert!((u8::to_str(u8_val) == ~"0")); - let mut u16_val: u16 = 65_535_u16; - assert!((u16::to_str(u16_val) == ~"65535")); + let mut u16_val: u16 = 65_535_u16; + assert!((u16::to_str(u16_val) == ~"65535")); - u16_val += 1 as u16; - assert!((u16::to_str(u16_val) == ~"0")); + u16_val += 1 as u16; + assert!((u16::to_str(u16_val) == ~"0")); - let mut u32_val: u32 = 4_294_967_295_u32; - assert!((u32::to_str(u32_val) == ~"4294967295")); + let mut u32_val: u32 = 4_294_967_295_u32; + assert!((u32::to_str(u32_val) == ~"4294967295")); - u32_val += 1 as u32; - assert!((u32::to_str(u32_val) == ~"0")); + u32_val += 1 as u32; + assert!((u32::to_str(u32_val) == ~"0")); - let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; - assert!((u64::to_str(u64_val) == ~"18446744073709551615")); + let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; + assert!((u64::to_str(u64_val) == ~"18446744073709551615")); - u64_val += 1 as u64; - assert!((u64::to_str(u64_val) == ~"0")); -} + u64_val += 1 as u64; + assert!((u64::to_str(u64_val) == ~"0")); + } -#[test] -fn test_uint_from_str_overflow() { - let mut u8_val: u8 = 255_u8; - assert!((u8::from_str(~"255") == Some(u8_val))); - assert!((u8::from_str(~"256").is_none())); + #[test] + fn test_uint_from_str_overflow() { + let mut u8_val: u8 = 255_u8; + assert!((u8::from_str(~"255") == Some(u8_val))); + assert!((u8::from_str(~"256").is_none())); - u8_val += 1 as u8; - assert!((u8::from_str(~"0") == Some(u8_val))); - assert!((u8::from_str(~"-1").is_none())); + u8_val += 1 as u8; + assert!((u8::from_str(~"0") == Some(u8_val))); + assert!((u8::from_str(~"-1").is_none())); - let mut u16_val: u16 = 65_535_u16; - assert!((u16::from_str(~"65535") == Some(u16_val))); - assert!((u16::from_str(~"65536").is_none())); + let mut u16_val: u16 = 65_535_u16; + assert!((u16::from_str(~"65535") == Some(u16_val))); + assert!((u16::from_str(~"65536").is_none())); - u16_val += 1 as u16; - assert!((u16::from_str(~"0") == Some(u16_val))); - assert!((u16::from_str(~"-1").is_none())); + u16_val += 1 as u16; + assert!((u16::from_str(~"0") == Some(u16_val))); + assert!((u16::from_str(~"-1").is_none())); - let mut u32_val: u32 = 4_294_967_295_u32; - assert!((u32::from_str(~"4294967295") == Some(u32_val))); - assert!((u32::from_str(~"4294967296").is_none())); + let mut u32_val: u32 = 4_294_967_295_u32; + assert!((u32::from_str(~"4294967295") == Some(u32_val))); + assert!((u32::from_str(~"4294967296").is_none())); - u32_val += 1 as u32; - assert!((u32::from_str(~"0") == Some(u32_val))); - assert!((u32::from_str(~"-1").is_none())); + u32_val += 1 as u32; + assert!((u32::from_str(~"0") == Some(u32_val))); + assert!((u32::from_str(~"-1").is_none())); - let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; - assert!((u64::from_str(~"18446744073709551615") == Some(u64_val))); - assert!((u64::from_str(~"18446744073709551616").is_none())); + let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; + assert!((u64::from_str(~"18446744073709551615") == Some(u64_val))); + assert!((u64::from_str(~"18446744073709551616").is_none())); - u64_val += 1 as u64; - assert!((u64::from_str(~"0") == Some(u64_val))); - assert!((u64::from_str(~"-1").is_none())); -} + u64_val += 1 as u64; + assert!((u64::from_str(~"0") == Some(u64_val))); + assert!((u64::from_str(~"-1").is_none())); + } -#[test] -#[should_fail] -#[ignore(cfg(windows))] -pub fn to_str_radix1() { - uint::to_str_radix(100u, 1u); -} + #[test] + #[should_fail] + #[ignore(cfg(windows))] + pub fn to_str_radix1() { + uint::to_str_radix(100u, 1u); + } -#[test] -#[should_fail] -#[ignore(cfg(windows))] -pub fn to_str_radix37() { - uint::to_str_radix(100u, 37u); -} + #[test] + #[should_fail] + #[ignore(cfg(windows))] + pub fn to_str_radix37() { + uint::to_str_radix(100u, 37u); + } -#[test] -pub fn test_ranges() { - let mut l = ~[]; + #[test] + pub fn test_ranges() { + let mut l = ~[]; - for range(0,3) |i| { - l.push(i); - } - for range_rev(13,10) |i| { - l.push(i); - } - for range_step(20,26,2) |i| { - l.push(i); - } - for range_step(36,30,-2) |i| { - l.push(i); - } + for range(0,3) |i| { + l.push(i); + } + for range_rev(13,10) |i| { + l.push(i); + } + for range_step(20,26,2) |i| { + l.push(i); + } + for range_step(36,30,-2) |i| { + l.push(i); + } + for range_step(max_value - 2, max_value, 2) |i| { + l.push(i); + } + for range_step(max_value - 3, max_value, 2) |i| { + l.push(i); + } + for range_step(min_value + 2, min_value, -2) |i| { + l.push(i); + } + for range_step(min_value + 3, min_value, -2) |i| { + l.push(i); + } - assert!(l == ~[0,1,2, + assert_eq!(l, ~[0,1,2, 13,12,11, 20,22,24, - 36,34,32]); - - // None of the `fail`s should execute. - for range(0,0) |_i| { - fail!(~"unreachable"); - } - for range_rev(0,0) |_i| { - fail!(~"unreachable"); + 36,34,32, + max_value-2, + max_value-3,max_value-1, + min_value+2, + min_value+3,min_value+1]); + + // None of the `fail`s should execute. + for range(0,0) |_i| { + fail!(~"unreachable"); + } + for range_rev(0,0) |_i| { + fail!(~"unreachable"); + } + for range_step(10,0,1) |_i| { + fail!(~"unreachable"); + } + for range_step(0,1,-10) |_i| { + fail!(~"unreachable"); + } } - for range_step(10,0,1) |_i| { - fail!(~"unreachable"); + + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_range_step_zero_step_up() { + for range_step(0,10,0) |_i| {} } - for range_step(0,1,-10) |_i| { - fail!(~"unreachable"); + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_range_step_zero_step_down() { + for range_step(0,-10,0) |_i| {} } -} - -#[test] -pub fn test_num() { - let ten: T = num::cast(10); - let two: T = num::cast(2); - - assert!((ten.add(&two) == num::cast(12))); - assert!((ten.sub(&two) == num::cast(8))); - assert!((ten.mul(&two) == num::cast(20))); - assert!((ten.div(&two) == num::cast(5))); - assert!((ten.modulo(&two) == num::cast(0))); -} - -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_range_step_zero_step_up() { - for range_step(0,10,0) |_i| {} -} -#[test] -#[should_fail] -#[ignore(cfg(windows))] -fn test_range_step_zero_step_down() { - for range_step(0,-10,0) |_i| {} -} +} \ No newline at end of file diff --git a/src/libcore/num/uint-template/u16.rs b/src/libcore/num/uint-template/u16.rs index 7445a43e48645..63144162fc50a 100644 --- a/src/libcore/num/uint-template/u16.rs +++ b/src/libcore/num/uint-template/u16.rs @@ -10,80 +10,9 @@ //! Operations and constants for `u16` -use num::NumCast; - mod inst { pub type T = u16; #[allow(non_camel_case_types)] pub type T_SIGNED = i16; pub static bits: uint = 16; } - -impl NumCast for u16 { - /** - * Cast `n` to a `u16` - */ - #[inline(always)] - fn from(n: N) -> u16 { n.to_u16() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20u16.to_uint())); - assert!((20u8 == 20u16.to_u8())); - assert!((20u16 == 20u16.to_u16())); - assert!((20u32 == 20u16.to_u32())); - assert!((20u64 == 20u16.to_u64())); - assert!((20i == 20u16.to_int())); - assert!((20i8 == 20u16.to_i8())); - assert!((20i16 == 20u16.to_i16())); - assert!((20i32 == 20u16.to_i32())); - assert!((20i64 == 20u16.to_i64())); - assert!((20f == 20u16.to_float())); - assert!((20f32 == 20u16.to_f32())); - assert!((20f64 == 20u16.to_f64())); - - assert!((20u16 == NumCast::from(20u))); - assert!((20u16 == NumCast::from(20u8))); - assert!((20u16 == NumCast::from(20u16))); - assert!((20u16 == NumCast::from(20u32))); - assert!((20u16 == NumCast::from(20u64))); - assert!((20u16 == NumCast::from(20i))); - assert!((20u16 == NumCast::from(20i8))); - assert!((20u16 == NumCast::from(20i16))); - assert!((20u16 == NumCast::from(20i32))); - assert!((20u16 == NumCast::from(20i64))); - assert!((20u16 == NumCast::from(20f))); - assert!((20u16 == NumCast::from(20f32))); - assert!((20u16 == NumCast::from(20f64))); - - assert!((20u16 == num::cast(20u))); - assert!((20u16 == num::cast(20u8))); - assert!((20u16 == num::cast(20u16))); - assert!((20u16 == num::cast(20u32))); - assert!((20u16 == num::cast(20u64))); - assert!((20u16 == num::cast(20i))); - assert!((20u16 == num::cast(20i8))); - assert!((20u16 == num::cast(20i16))); - assert!((20u16 == num::cast(20i32))); - assert!((20u16 == num::cast(20i64))); - assert!((20u16 == num::cast(20f))); - assert!((20u16 == num::cast(20f32))); - assert!((20u16 == num::cast(20f64))); -} diff --git a/src/libcore/num/uint-template/u32.rs b/src/libcore/num/uint-template/u32.rs index cfc112be8a6d1..4d9958fe38aaf 100644 --- a/src/libcore/num/uint-template/u32.rs +++ b/src/libcore/num/uint-template/u32.rs @@ -10,80 +10,9 @@ //! Operations and constants for `u32` -use num::NumCast; - mod inst { pub type T = u32; #[allow(non_camel_case_types)] pub type T_SIGNED = i32; pub static bits: uint = 32; } - -impl NumCast for u32 { - /** - * Cast `n` to a `u32` - */ - #[inline(always)] - fn from(n: N) -> u32 { n.to_u32() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20u64.to_uint())); - assert!((20u8 == 20u64.to_u8())); - assert!((20u16 == 20u64.to_u16())); - assert!((20u32 == 20u64.to_u32())); - assert!((20u64 == 20u64.to_u64())); - assert!((20i == 20u64.to_int())); - assert!((20i8 == 20u64.to_i8())); - assert!((20i16 == 20u64.to_i16())); - assert!((20i32 == 20u64.to_i32())); - assert!((20i64 == 20u64.to_i64())); - assert!((20f == 20u64.to_float())); - assert!((20f32 == 20u64.to_f32())); - assert!((20f64 == 20u64.to_f64())); - - assert!((20u64 == NumCast::from(20u))); - assert!((20u64 == NumCast::from(20u8))); - assert!((20u64 == NumCast::from(20u16))); - assert!((20u64 == NumCast::from(20u32))); - assert!((20u64 == NumCast::from(20u64))); - assert!((20u64 == NumCast::from(20i))); - assert!((20u64 == NumCast::from(20i8))); - assert!((20u64 == NumCast::from(20i16))); - assert!((20u64 == NumCast::from(20i32))); - assert!((20u64 == NumCast::from(20i64))); - assert!((20u64 == NumCast::from(20f))); - assert!((20u64 == NumCast::from(20f32))); - assert!((20u64 == NumCast::from(20f64))); - - assert!((20u64 == num::cast(20u))); - assert!((20u64 == num::cast(20u8))); - assert!((20u64 == num::cast(20u16))); - assert!((20u64 == num::cast(20u32))); - assert!((20u64 == num::cast(20u64))); - assert!((20u64 == num::cast(20i))); - assert!((20u64 == num::cast(20i8))); - assert!((20u64 == num::cast(20i16))); - assert!((20u64 == num::cast(20i32))); - assert!((20u64 == num::cast(20i64))); - assert!((20u64 == num::cast(20f))); - assert!((20u64 == num::cast(20f32))); - assert!((20u64 == num::cast(20f64))); -} diff --git a/src/libcore/num/uint-template/u64.rs b/src/libcore/num/uint-template/u64.rs index 4e2f6640d6974..af198dd69424b 100644 --- a/src/libcore/num/uint-template/u64.rs +++ b/src/libcore/num/uint-template/u64.rs @@ -10,80 +10,9 @@ //! Operations and constants for `u64` -use num::NumCast; - mod inst { pub type T = u64; #[allow(non_camel_case_types)] pub type T_SIGNED = i64; pub static bits: uint = 64; } - -impl NumCast for u64 { - /** - * Cast `n` to a `u64` - */ - #[inline(always)] - fn from(n: N) -> u64 { n.to_u64() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20u64.to_uint())); - assert!((20u8 == 20u64.to_u8())); - assert!((20u16 == 20u64.to_u16())); - assert!((20u32 == 20u64.to_u32())); - assert!((20u64 == 20u64.to_u64())); - assert!((20i == 20u64.to_int())); - assert!((20i8 == 20u64.to_i8())); - assert!((20i16 == 20u64.to_i16())); - assert!((20i32 == 20u64.to_i32())); - assert!((20i64 == 20u64.to_i64())); - assert!((20f == 20u64.to_float())); - assert!((20f32 == 20u64.to_f32())); - assert!((20f64 == 20u64.to_f64())); - - assert!((20u64 == NumCast::from(20u))); - assert!((20u64 == NumCast::from(20u8))); - assert!((20u64 == NumCast::from(20u16))); - assert!((20u64 == NumCast::from(20u32))); - assert!((20u64 == NumCast::from(20u64))); - assert!((20u64 == NumCast::from(20i))); - assert!((20u64 == NumCast::from(20i8))); - assert!((20u64 == NumCast::from(20i16))); - assert!((20u64 == NumCast::from(20i32))); - assert!((20u64 == NumCast::from(20i64))); - assert!((20u64 == NumCast::from(20f))); - assert!((20u64 == NumCast::from(20f32))); - assert!((20u64 == NumCast::from(20f64))); - - assert!((20u64 == num::cast(20u))); - assert!((20u64 == num::cast(20u8))); - assert!((20u64 == num::cast(20u16))); - assert!((20u64 == num::cast(20u32))); - assert!((20u64 == num::cast(20u64))); - assert!((20u64 == num::cast(20i))); - assert!((20u64 == num::cast(20i8))); - assert!((20u64 == num::cast(20i16))); - assert!((20u64 == num::cast(20i32))); - assert!((20u64 == num::cast(20i64))); - assert!((20u64 == num::cast(20f))); - assert!((20u64 == num::cast(20f32))); - assert!((20u64 == num::cast(20f64))); -} diff --git a/src/libcore/num/uint-template/u8.rs b/src/libcore/num/uint-template/u8.rs index 52bc56b955cc1..ce23bebacdad1 100644 --- a/src/libcore/num/uint-template/u8.rs +++ b/src/libcore/num/uint-template/u8.rs @@ -12,8 +12,6 @@ pub use self::inst::is_ascii; -use num::NumCast; - mod inst { pub type T = u8; #[allow(non_camel_case_types)] @@ -25,72 +23,3 @@ mod inst { pub fn is_ascii(x: T) -> bool { return 0 as T == x & 128 as T; } } - -impl NumCast for u8 { - /** - * Cast `n` to a `u8` - */ - #[inline(always)] - fn from(n: N) -> u8 { n.to_u8() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self as uint } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20u8.to_uint())); - assert!((20u8 == 20u8.to_u8())); - assert!((20u16 == 20u8.to_u16())); - assert!((20u32 == 20u8.to_u32())); - assert!((20u64 == 20u8.to_u64())); - assert!((20i == 20u8.to_int())); - assert!((20i8 == 20u8.to_i8())); - assert!((20i16 == 20u8.to_i16())); - assert!((20i32 == 20u8.to_i32())); - assert!((20i64 == 20u8.to_i64())); - assert!((20f == 20u8.to_float())); - assert!((20f32 == 20u8.to_f32())); - assert!((20f64 == 20u8.to_f64())); - - assert!((20u8 == NumCast::from(20u))); - assert!((20u8 == NumCast::from(20u8))); - assert!((20u8 == NumCast::from(20u16))); - assert!((20u8 == NumCast::from(20u32))); - assert!((20u8 == NumCast::from(20u64))); - assert!((20u8 == NumCast::from(20i))); - assert!((20u8 == NumCast::from(20i8))); - assert!((20u8 == NumCast::from(20i16))); - assert!((20u8 == NumCast::from(20i32))); - assert!((20u8 == NumCast::from(20i64))); - assert!((20u8 == NumCast::from(20f))); - assert!((20u8 == NumCast::from(20f32))); - assert!((20u8 == NumCast::from(20f64))); - - assert!((20u8 == num::cast(20u))); - assert!((20u8 == num::cast(20u8))); - assert!((20u8 == num::cast(20u16))); - assert!((20u8 == num::cast(20u32))); - assert!((20u8 == num::cast(20u64))); - assert!((20u8 == num::cast(20i))); - assert!((20u8 == num::cast(20i8))); - assert!((20u8 == num::cast(20i16))); - assert!((20u8 == num::cast(20i32))); - assert!((20u8 == num::cast(20i64))); - assert!((20u8 == num::cast(20f))); - assert!((20u8 == num::cast(20f32))); - assert!((20u8 == num::cast(20f64))); -} diff --git a/src/libcore/num/uint-template/uint.rs b/src/libcore/num/uint-template/uint.rs index 16e53eb4b6c97..efcf68aba3160 100644 --- a/src/libcore/num/uint-template/uint.rs +++ b/src/libcore/num/uint-template/uint.rs @@ -10,8 +10,6 @@ //! Operations and constants for `uint` -use num::NumCast; - pub use self::inst::{ div_ceil, div_round, div_floor, iterate, next_power_of_two @@ -209,72 +207,3 @@ pub mod inst { assert!((accum == 10)); } } - -impl NumCast for uint { - /** - * Cast `n` to a `uint` - */ - #[inline(always)] - fn from(n: N) -> uint { n.to_uint() } - - #[inline(always)] fn to_u8(&self) -> u8 { *self as u8 } - #[inline(always)] fn to_u16(&self) -> u16 { *self as u16 } - #[inline(always)] fn to_u32(&self) -> u32 { *self as u32 } - #[inline(always)] fn to_u64(&self) -> u64 { *self as u64 } - #[inline(always)] fn to_uint(&self) -> uint { *self } - - #[inline(always)] fn to_i8(&self) -> i8 { *self as i8 } - #[inline(always)] fn to_i16(&self) -> i16 { *self as i16 } - #[inline(always)] fn to_i32(&self) -> i32 { *self as i32 } - #[inline(always)] fn to_i64(&self) -> i64 { *self as i64 } - #[inline(always)] fn to_int(&self) -> int { *self as int } - - #[inline(always)] fn to_f32(&self) -> f32 { *self as f32 } - #[inline(always)] fn to_f64(&self) -> f64 { *self as f64 } - #[inline(always)] fn to_float(&self) -> float { *self as float } -} - -#[test] -fn test_numcast() { - assert!((20u == 20u.to_uint())); - assert!((20u8 == 20u.to_u8())); - assert!((20u16 == 20u.to_u16())); - assert!((20u32 == 20u.to_u32())); - assert!((20u64 == 20u.to_u64())); - assert!((20i == 20u.to_int())); - assert!((20i8 == 20u.to_i8())); - assert!((20i16 == 20u.to_i16())); - assert!((20i32 == 20u.to_i32())); - assert!((20i64 == 20u.to_i64())); - assert!((20f == 20u.to_float())); - assert!((20f32 == 20u.to_f32())); - assert!((20f64 == 20u.to_f64())); - - assert!((20u == NumCast::from(20u))); - assert!((20u == NumCast::from(20u8))); - assert!((20u == NumCast::from(20u16))); - assert!((20u == NumCast::from(20u32))); - assert!((20u == NumCast::from(20u64))); - assert!((20u == NumCast::from(20i))); - assert!((20u == NumCast::from(20i8))); - assert!((20u == NumCast::from(20i16))); - assert!((20u == NumCast::from(20i32))); - assert!((20u == NumCast::from(20i64))); - assert!((20u == NumCast::from(20f))); - assert!((20u == NumCast::from(20f32))); - assert!((20u == NumCast::from(20f64))); - - assert!((20u == num::cast(20u))); - assert!((20u == num::cast(20u8))); - assert!((20u == num::cast(20u16))); - assert!((20u == num::cast(20u32))); - assert!((20u == num::cast(20u64))); - assert!((20u == num::cast(20i))); - assert!((20u == num::cast(20i8))); - assert!((20u == num::cast(20i16))); - assert!((20u == num::cast(20i32))); - assert!((20u == num::cast(20i64))); - assert!((20u == num::cast(20f))); - assert!((20u == num::cast(20f32))); - assert!((20u == num::cast(20f64))); -} diff --git a/src/libcore/option.rs b/src/libcore/option.rs index cd34d7ab0c0bb..9b7276879c123 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -46,7 +46,8 @@ use ops::Add; use kinds::Copy; use util; use num::Zero; -use iter::{BaseIter, MutableIter}; +use iter::{BaseIter, MutableIter, ExtendedIter}; +use iter; #[cfg(test)] use ptr; #[cfg(test)] use str; @@ -100,11 +101,21 @@ impl> Add, Option> for Option { impl BaseIter for Option { /// Performs an operation on the contained value by reference + #[cfg(stage0)] #[inline(always)] fn each(&self, f: &fn(x: &'self T) -> bool) { match *self { None => (), Some(ref t) => { f(t); } } } + /// Performs an operation on the contained value by reference + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn each<'a>(&'a self, f: &fn(x: &'a T) -> bool) { + match *self { None => (), Some(ref t) => { f(t); } } + } + #[inline(always)] fn size_hint(&self) -> Option { if self.is_some() { Some(1) } else { Some(0) } @@ -112,10 +123,44 @@ impl BaseIter for Option { } impl MutableIter for Option { + #[cfg(stage0)] #[inline(always)] fn each_mut(&mut self, f: &fn(&'self mut T) -> bool) { match *self { None => (), Some(ref mut t) => { f(t); } } } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn each_mut<'a>(&'a mut self, f: &fn(&'a mut T) -> bool) { + match *self { None => (), Some(ref mut t) => { f(t); } } + } +} + +impl ExtendedIter for Option { + pub fn eachi(&self, blk: &fn(uint, v: &A) -> bool) { + iter::eachi(self, blk) + } + pub fn all(&self, blk: &fn(&A) -> bool) -> bool { + iter::all(self, blk) + } + pub fn any(&self, blk: &fn(&A) -> bool) -> bool { + iter::any(self, blk) + } + pub fn foldl(&self, b0: B, blk: &fn(&B, &A) -> B) -> B { + iter::foldl(self, b0, blk) + } + pub fn position(&self, f: &fn(&A) -> bool) -> Option { + iter::position(self, f) + } + fn map_to_vec(&self, op: &fn(&A) -> B) -> ~[B] { + iter::map_to_vec(self, op) + } + fn flat_map_to_vec>(&self, op: &fn(&A) -> IB) + -> ~[B] { + iter::flat_map_to_vec(self, op) + } } pub impl Option { @@ -156,17 +201,40 @@ pub impl Option { * Update an optional value by optionally running its content by reference * through a function that returns an option. */ + #[cfg(stage0)] #[inline(always)] fn chain_ref(&self, f: &fn(x: &'self T) -> Option) -> Option { match *self { Some(ref x) => f(x), None => None } } + /** + * Update an optional value by optionally running its content by reference + * through a function that returns an option. + */ + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option) -> Option { + match *self { Some(ref x) => f(x), None => None } + } + /// Maps a `some` value from one type to another by reference + #[cfg(stage0)] #[inline(always)] fn map(&self, f: &fn(&'self T) -> U) -> Option { match *self { Some(ref x) => Some(f(x)), None => None } } + /// Maps a `some` value from one type to another by reference + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn map<'a, U>(&self, f: &fn(&'a T) -> U) -> Option { + match *self { Some(ref x) => Some(f(x)), None => None } + } + /// As `map`, but consumes the option and gives `f` ownership to avoid /// copying. #[inline(always)] @@ -175,11 +243,21 @@ pub impl Option { } /// Applies a function to the contained value or returns a default + #[cfg(stage0)] #[inline(always)] fn map_default(&self, def: U, f: &fn(&'self T) -> U) -> U { match *self { None => def, Some(ref t) => f(t) } } + /// Applies a function to the contained value or returns a default + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { + match *self { None => def, Some(ref t) => f(t) } + } + /// As `map_default`, but consumes the option and gives `f` /// ownership to avoid copying. #[inline(always)] @@ -218,6 +296,7 @@ pub impl Option { case explicitly. */ #[inline(always)] + #[cfg(stage0)] fn get_ref(&self) -> &'self T { match *self { Some(ref x) => x, @@ -225,6 +304,31 @@ pub impl Option { } } + /** + Gets an immutable reference to the value inside an option. + + # Failure + + Fails if the value equals `None` + + # Safety note + + In general, because this function may fail, its use is discouraged + (calling `get` on `None` is akin to dereferencing a null pointer). + Instead, prefer to use pattern matching and handle the `None` + case explicitly. + */ + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get_ref<'a>(&'a self) -> &'a T { + match *self { + Some(ref x) => x, + None => fail!(~"option::get_ref none") + } + } + /** Gets a mutable reference to the value inside an option. @@ -240,6 +344,7 @@ pub impl Option { case explicitly. */ #[inline(always)] + #[cfg(stage0)] fn get_mut_ref(&mut self) -> &'self mut T { match *self { Some(ref mut x) => x, @@ -247,6 +352,31 @@ pub impl Option { } } + /** + Gets a mutable reference to the value inside an option. + + # Failure + + Fails if the value equals `None` + + # Safety note + + In general, because this function may fail, its use is discouraged + (calling `get` on `None` is akin to dereferencing a null pointer). + Instead, prefer to use pattern matching and handle the `None` + case explicitly. + */ + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { + match *self { + Some(ref mut x) => x, + None => fail!(~"option::get_mut_ref none") + } + } + #[inline(always)] fn unwrap(self) -> T { /*! diff --git a/src/libcore/path.rs b/src/libcore/path.rs index 7de0f355dd21d..0e8dbd144b143 100644 --- a/src/libcore/path.rs +++ b/src/libcore/path.rs @@ -389,13 +389,11 @@ impl GenericPath for PosixPath { } fn dirname(&self) -> ~str { - unsafe { - let s = self.dir_path().to_str(); - if s.len() == 0 { - ~"." - } else { - s - } + let s = self.dir_path().to_str(); + if s.len() == 0 { + ~"." + } else { + s } } @@ -439,10 +437,8 @@ impl GenericPath for PosixPath { } fn with_filename(&self, f: &str) -> PosixPath { - unsafe { - assert!(! str::any(f, |c| windows::is_sep(c as u8))); - self.dir_path().push(f) - } + assert!(! str::any(f, |c| windows::is_sep(c as u8))); + self.dir_path().push(f) } fn with_filestem(&self, s: &str) -> PosixPath { @@ -509,7 +505,7 @@ impl GenericPath for PosixPath { for str::each_split_nonempty(*e, |c| windows::is_sep(c as u8)) |s| { ss.push(s.to_owned()) } - unsafe { v.push_all_move(ss); } + v.push_all_move(ss); } PosixPath { is_absolute: self.is_absolute, components: v } @@ -521,14 +517,14 @@ impl GenericPath for PosixPath { for str::each_split_nonempty(s, |c| windows::is_sep(c as u8)) |s| { ss.push(s.to_owned()) } - unsafe { v.push_all_move(ss); } + v.push_all_move(ss); PosixPath { components: v, ..copy *self } } fn pop(&self) -> PosixPath { let mut cs = copy self.components; if cs.len() != 0 { - unsafe { cs.pop(); } + cs.pop(); } return PosixPath { is_absolute: self.is_absolute, @@ -607,13 +603,11 @@ impl GenericPath for WindowsPath { } fn dirname(&self) -> ~str { - unsafe { - let s = self.dir_path().to_str(); - if s.len() == 0 { - ~"." - } else { - s - } + let s = self.dir_path().to_str(); + if s.len() == 0 { + ~"." + } else { + s } } @@ -770,7 +764,7 @@ impl GenericPath for WindowsPath { for str::each_split_nonempty(*e, |c| windows::is_sep(c as u8)) |s| { ss.push(s.to_owned()) } - unsafe { v.push_all_move(ss); } + v.push_all_move(ss); } // tedious, but as-is, we can't use ..self return WindowsPath { @@ -787,14 +781,14 @@ impl GenericPath for WindowsPath { for str::each_split_nonempty(s, |c| windows::is_sep(c as u8)) |s| { ss.push(s.to_owned()) } - unsafe { v.push_all_move(ss); } + v.push_all_move(ss); return WindowsPath { components: v, ..copy *self } } fn pop(&self) -> WindowsPath { let mut cs = copy self.components; if cs.len() != 0 { - unsafe { cs.pop(); } + cs.pop(); } return WindowsPath { host: copy self.host, @@ -820,18 +814,14 @@ impl GenericPath for WindowsPath { pub fn normalize(components: &[~str]) -> ~[~str] { let mut cs = ~[]; - unsafe { - for components.each |c| { - unsafe { - if *c == ~"." && components.len() > 1 { loop; } - if *c == ~"" { loop; } - if *c == ~".." && cs.len() != 0 { - cs.pop(); - loop; - } - cs.push(copy *c); - } + for components.each |c| { + if *c == ~"." && components.len() > 1 { loop; } + if *c == ~"" { loop; } + if *c == ~".." && cs.len() != 0 { + cs.pop(); + loop; } + cs.push(copy *c); } cs } diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 18f8030d5b84e..fddb2af558709 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -957,13 +957,13 @@ pub mod rt { } #[cfg(test)] -pub mod test { +mod test { use either::Right; use comm::{Chan, Port, oneshot, recv_one, stream, Select2, GenericChan, Peekable}; #[test] - pub fn test_select2() { + fn test_select2() { let (p1, c1) = stream(); let (p2, c2) = stream(); @@ -978,7 +978,7 @@ pub mod test { } #[test] - pub fn test_oneshot() { + fn test_oneshot() { let (c, p) = oneshot::init(); oneshot::client::send(c, ()); diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 9c3bf04b2a8f5..e148493ca4512 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -34,7 +34,7 @@ pub use hash::Hash; pub use iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; pub use iter::{CopyableIter, CopyableOrderedIter, CopyableNonstrictIter}; pub use iter::Times; -pub use num::NumCast; +pub use num::{Num, NumCast}; pub use path::GenericPath; pub use path::Path; pub use path::PosixPath; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 70bdb6f41d8ba..ebde37e77b42f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -15,8 +15,6 @@ use libc; use libc::{c_void, size_t}; use sys; -#[cfg(test)] use vec; -#[cfg(test)] use str; #[cfg(notest)] use cmp::{Eq, Ord}; use uint; @@ -55,17 +53,13 @@ pub fn addr_of(val: &T) -> *T { unsafe { rusti::addr_of(*val) } } /// Calculate the offset from a pointer #[inline(always)] pub fn offset(ptr: *T, count: uint) -> *T { - unsafe { - (ptr as uint + count * sys::size_of::()) as *T - } + (ptr as uint + count * sys::size_of::()) as *T } /// Calculate the offset from a const pointer #[inline(always)] pub fn const_offset(ptr: *const T, count: uint) -> *const T { - unsafe { - (ptr as uint + count * sys::size_of::()) as *T - } + (ptr as uint + count * sys::size_of::()) as *T } /// Calculate the offset from a mut pointer @@ -345,101 +339,101 @@ impl<'self,T:Ord> Ord for &'self const T { } } -#[test] -pub fn test() { - unsafe { - struct Pair {mut fst: int, mut snd: int}; - let mut p = Pair {fst: 10, snd: 20}; - let pptr: *mut Pair = &mut p; - let iptr: *mut int = cast::reinterpret_cast(&pptr); - assert!((*iptr == 10));; - *iptr = 30; - assert!((*iptr == 30)); - assert!((p.fst == 30));; - - *pptr = Pair {fst: 50, snd: 60}; - assert!((*iptr == 50)); - assert!((p.fst == 50)); - assert!((p.snd == 60)); - - let mut v0 = ~[32000u16, 32001u16, 32002u16]; - let mut v1 = ~[0u16, 0u16, 0u16]; - - copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 1u), - offset(vec::raw::to_ptr(v0), 1u), 1u); - assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16)); - copy_memory(vec::raw::to_mut_ptr(v1), - offset(vec::raw::to_ptr(v0), 2u), 1u); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && - v1[2] == 0u16)); - copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 2u), - vec::raw::to_ptr(v0), 1u); - assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && - v1[2] == 32000u16)); +#[cfg(test)] +pub mod ptr_tests { + use super::*; + use prelude::*; + + #[test] + fn test() { + unsafe { + struct Pair {mut fst: int, mut snd: int}; + let mut p = Pair {fst: 10, snd: 20}; + let pptr: *mut Pair = &mut p; + let iptr: *mut int = cast::reinterpret_cast(&pptr); + assert!((*iptr == 10));; + *iptr = 30; + assert!((*iptr == 30)); + assert!((p.fst == 30));; + + *pptr = Pair {fst: 50, snd: 60}; + assert!((*iptr == 50)); + assert!((p.fst == 50)); + assert!((p.snd == 60)); + + let mut v0 = ~[32000u16, 32001u16, 32002u16]; + let mut v1 = ~[0u16, 0u16, 0u16]; + + copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 1u), + offset(vec::raw::to_ptr(v0), 1u), 1u); + assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16)); + copy_memory(vec::raw::to_mut_ptr(v1), + offset(vec::raw::to_ptr(v0), 2u), 1u); + assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && + v1[2] == 0u16)); + copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 2u), + vec::raw::to_ptr(v0), 1u); + assert!((v1[0] == 32002u16 && v1[1] == 32001u16 && + v1[2] == 32000u16)); + } } -} -#[test] -pub fn test_position() { - use str::as_c_str; - use libc::c_char; + #[test] + fn test_position() { + use str::as_c_str; + use libc::c_char; - let s = ~"hello"; - unsafe { - assert!(2u == as_c_str(s, |p| position(p, - |c| *c == 'l' as c_char))); - assert!(4u == as_c_str(s, |p| position(p, - |c| *c == 'o' as c_char))); - assert!(5u == as_c_str(s, |p| position(p, - |c| *c == 0 as c_char))); + let s = ~"hello"; + unsafe { + assert!(2u == as_c_str(s, |p| position(p, + |c| *c == 'l' as c_char))); + assert!(4u == as_c_str(s, |p| position(p, + |c| *c == 'o' as c_char))); + assert!(5u == as_c_str(s, |p| position(p, + |c| *c == 0 as c_char))); + } } -} -#[test] -pub fn test_buf_len() { - let s0 = ~"hello"; - let s1 = ~"there"; - let s2 = ~"thing"; - do str::as_c_str(s0) |p0| { - do str::as_c_str(s1) |p1| { - do str::as_c_str(s2) |p2| { - let v = ~[p0, p1, p2, null()]; - do vec::as_imm_buf(v) |vp, len| { - assert!(unsafe { buf_len(vp) } == 3u); - assert!(len == 4u); + #[test] + fn test_buf_len() { + let s0 = ~"hello"; + let s1 = ~"there"; + let s2 = ~"thing"; + do str::as_c_str(s0) |p0| { + do str::as_c_str(s1) |p1| { + do str::as_c_str(s2) |p2| { + let v = ~[p0, p1, p2, null()]; + do vec::as_imm_buf(v) |vp, len| { + assert!(unsafe { buf_len(vp) } == 3u); + assert!(len == 4u); + } } } } } -} - -#[test] -pub fn test_is_null() { - let p: *int = null(); - assert!(p.is_null()); - assert!(!p.is_not_null()); - let q = offset(p, 1u); - assert!(!q.is_null()); - assert!(q.is_not_null()); + #[test] + fn test_is_null() { + let p: *int = null(); + assert!(p.is_null()); + assert!(!p.is_not_null()); + + let q = offset(p, 1u); + assert!(!q.is_null()); + assert!(q.is_not_null()); + + let mp: *mut int = mut_null(); + assert!(mp.is_null()); + assert!(!mp.is_not_null()); + + let mq = mp.offset(1u); + assert!(!mq.is_null()); + assert!(mq.is_not_null()); + } - let mp: *mut int = mut_null(); - assert!(mp.is_null()); - assert!(!mp.is_not_null()); - let mq = mp.offset(1u); - assert!(!mq.is_null()); - assert!(mq.is_not_null()); -} - -#[cfg(test)] -pub mod ptr_tests { - use ptr; - use str; - use libc; - use vec; #[test] - pub fn test_ptr_array_each_with_len() { + fn test_ptr_array_each_with_len() { unsafe { let one = ~"oneOne"; let two = ~"twoTwo"; @@ -455,22 +449,22 @@ pub mod ptr_tests { let arr_ptr = &arr[0]; let mut ctr = 0; let mut iteration_count = 0; - ptr::array_each_with_len(arr_ptr, vec::len(arr), - |e| { - let actual = str::raw::from_c_str(e); - let expected = copy expected_arr[ctr]; - debug!( - "test_ptr_array_each e: %s, a: %s", - expected, actual); - assert!(actual == expected); - ctr += 1; - iteration_count += 1; - }); + array_each_with_len(arr_ptr, vec::len(arr), + |e| { + let actual = str::raw::from_c_str(e); + let expected = copy expected_arr[ctr]; + debug!( + "test_ptr_array_each e: %s, a: %s", + expected, actual); + assert!(actual == expected); + ctr += 1; + iteration_count += 1; + }); assert!(iteration_count == 3u); } } #[test] - pub fn test_ptr_array_each() { + fn test_ptr_array_each() { unsafe { let one = ~"oneOne"; let two = ~"twoTwo"; @@ -488,12 +482,12 @@ pub mod ptr_tests { let arr_ptr = &arr[0]; let mut ctr = 0; let mut iteration_count = 0; - ptr::array_each(arr_ptr, |e| { + array_each(arr_ptr, |e| { let actual = str::raw::from_c_str(e); let expected = copy expected_arr[ctr]; debug!( "test_ptr_array_each e: %s, a: %s", - expected, actual); + expected, actual); assert!(actual == expected); ctr += 1; iteration_count += 1; @@ -504,9 +498,9 @@ pub mod ptr_tests { #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_ptr_array_each_with_len_null_ptr() { + fn test_ptr_array_each_with_len_null_ptr() { unsafe { - ptr::array_each_with_len(0 as **libc::c_char, 1, |e| { + array_each_with_len(0 as **libc::c_char, 1, |e| { str::raw::from_c_str(e); }); } @@ -514,9 +508,9 @@ pub mod ptr_tests { #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_ptr_array_each_null_ptr() { + fn test_ptr_array_each_null_ptr() { unsafe { - ptr::array_each(0 as **libc::c_char, |e| { + array_each(0 as **libc::c_char, |e| { str::raw::from_c_str(e); }); } diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index a4e53418fc88e..0a93a651a8572 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -150,7 +150,21 @@ pub struct Weighted { pub trait RngUtil { fn gen(&self) -> T; - /// Return a random int + /** + * Return a random int + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(fmt!("%d",rng.gen_int())); + * } + * ~~~ + */ fn gen_int(&self) -> int; fn gen_int_range(&self, start: int, end: int) -> int; /// Return a random i8 @@ -176,7 +190,21 @@ pub trait RngUtil { fn gen_u32(&self) -> u32; /// Return a random u64 fn gen_u64(&self) -> u64; - /// Return a random float in the interval [0,1] + /** + * Return random float in the interval [0,1] + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(fmt!("%f",rng.gen_float())); + * } + * ~~~ + */ fn gen_float(&self) -> float; /// Return a random f32 in the interval [0,1] fn gen_f32(&self) -> f32; @@ -188,38 +216,184 @@ pub trait RngUtil { * Return a char randomly chosen from chars, failing if chars is empty */ fn gen_char_from(&self, chars: &str) -> char; - /// Return a random bool + /** + * Return a random bool + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(fmt!("%b",rng.gen_bool())); + * } + * ~~~ + */ fn gen_bool(&self) -> bool; - /// Return a bool with a 1 in n chance of true + /** + * Return a bool with a 1 in n chance of true + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(fmt!("%b",rng.gen_weighted_bool(3))); + * } + * ~~~ + */ fn gen_weighted_bool(&self, n: uint) -> bool; /** * Return a random string of the specified length composed of A-Z,a-z,0-9 + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(rng.gen_str(8)); + * } + * ~~~ */ fn gen_str(&self, len: uint) -> ~str; - /// Return a random byte string of the specified length + /** + * Return a random byte string of the specified length + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(fmt!("%?",rng.gen_bytes(8))); + * } + * ~~~ + */ fn gen_bytes(&self, len: uint) -> ~[u8]; - /// Choose an item randomly, failing if values is empty + /// + /** + * Choose an item randomly, failing if values is empty + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(fmt!("%d",rng.choose([1,2,4,8,16,32]))); + * } + * ~~~ + */ fn choose(&self, values: &[T]) -> T; /// Choose Some(item) randomly, returning None if values is empty fn choose_option(&self, values: &[T]) -> Option; /** * Choose an item respecting the relative weights, failing if the sum of * the weights is 0 + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * let x = [rand::Weighted {weight: 4, item: 'a'}, + * rand::Weighted {weight: 2, item: 'b'}, + * rand::Weighted {weight: 2, item: 'c'}]; + * println(fmt!("%c",rng.choose_weighted(x))); + * } + * ~~~ */ fn choose_weighted(&self, v : &[Weighted]) -> T; /** * Choose Some(item) respecting the relative weights, returning none if * the sum of the weights is 0 + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * let x = [rand::Weighted {weight: 4, item: 'a'}, + * rand::Weighted {weight: 2, item: 'b'}, + * rand::Weighted {weight: 2, item: 'c'}]; + * println(fmt!("%?",rng.choose_weighted_option(x))); + * } + * ~~~ */ fn choose_weighted_option(&self, v: &[Weighted]) -> Option; /** * Return a vec containing copies of the items, in order, where * the weight of the item determines how many copies there are + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * let x = [rand::Weighted {weight: 4, item: 'a'}, + * rand::Weighted {weight: 2, item: 'b'}, + * rand::Weighted {weight: 2, item: 'c'}]; + * println(fmt!("%?",rng.weighted_vec(x))); + * } + * ~~~ */ fn weighted_vec(&self, v: &[Weighted]) -> ~[T]; - /// Shuffle a vec + /** + * Shuffle a vec + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * println(fmt!("%?",rng.shuffle([1,2,3]))); + * } + * ~~~ + */ fn shuffle(&self, values: &[T]) -> ~[T]; - /// Shuffle a mutable vec in place + /** + * Shuffle a mutable vec in place + * + * *Example* + * + * ~~~ + * + * use core::rand::RngUtil; + * + * fn main() { + * rng = rand::Rng(); + * let mut y = [1,2,3]; + * rng.shuffle_mut(y); + * println(fmt!("%?",y)); + * rng.shuffle_mut(y); + * println(fmt!("%?",y)); + * } + * ~~~ + */ fn shuffle_mut(&self, values: &mut [T]); } @@ -337,7 +511,7 @@ impl RngUtil for @Rng { self.next() & 1u32 == 1u32 } - /// Return a bool with a 1 in n chance of true + /// Return a bool with a 1-in-n chance of true fn gen_weighted_bool(&self, n: uint) -> bool { if n == 0u { true @@ -573,12 +747,12 @@ pub fn random() -> uint { #[cfg(test)] -pub mod tests { +mod tests { use option::{Option, Some}; use rand; #[test] - pub fn rng_seeded() { + fn rng_seeded() { let seed = rand::seed(); let ra = rand::seeded_rng(seed); let rb = rand::seeded_rng(seed); @@ -586,7 +760,7 @@ pub mod tests { } #[test] - pub fn rng_seeded_custom_seed() { + fn rng_seeded_custom_seed() { // much shorter than generated seeds which are 1024 bytes let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; let ra = rand::seeded_rng(seed); @@ -595,7 +769,7 @@ pub mod tests { } #[test] - pub fn rng_seeded_custom_seed2() { + fn rng_seeded_custom_seed2() { let seed = [2u8, 32u8, 4u8, 32u8, 51u8]; let ra = rand::seeded_rng(seed); // Regression test that isaac is actually using the above vector @@ -606,7 +780,7 @@ pub mod tests { } #[test] - pub fn gen_int_range() { + fn gen_int_range() { let r = rand::Rng(); let a = r.gen_int_range(-3, 42); assert!(a >= -3 && a < 42); @@ -617,12 +791,12 @@ pub mod tests { #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn gen_int_from_fail() { + fn gen_int_from_fail() { rand::Rng().gen_int_range(5, -2); } #[test] - pub fn gen_uint_range() { + fn gen_uint_range() { let r = rand::Rng(); let a = r.gen_uint_range(3u, 42u); assert!(a >= 3u && a < 42u); @@ -633,12 +807,12 @@ pub mod tests { #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn gen_uint_range_fail() { + fn gen_uint_range_fail() { rand::Rng().gen_uint_range(5u, 2u); } #[test] - pub fn gen_float() { + fn gen_float() { let r = rand::Rng(); let a = r.gen_float(); let b = r.gen_float(); @@ -646,14 +820,14 @@ pub mod tests { } #[test] - pub fn gen_weighted_bool() { + fn gen_weighted_bool() { let r = rand::Rng(); assert!(r.gen_weighted_bool(0u) == true); assert!(r.gen_weighted_bool(1u) == true); } #[test] - pub fn gen_str() { + fn gen_str() { let r = rand::Rng(); debug!(r.gen_str(10u)); debug!(r.gen_str(10u)); @@ -664,7 +838,7 @@ pub mod tests { } #[test] - pub fn gen_bytes() { + fn gen_bytes() { let r = rand::Rng(); assert!(r.gen_bytes(0u).len() == 0u); assert!(r.gen_bytes(10u).len() == 10u); @@ -672,13 +846,13 @@ pub mod tests { } #[test] - pub fn choose() { + fn choose() { let r = rand::Rng(); assert!(r.choose([1, 1, 1]) == 1); } #[test] - pub fn choose_option() { + fn choose_option() { let r = rand::Rng(); let x: Option = r.choose_option([]); assert!(x.is_none()); @@ -686,7 +860,7 @@ pub mod tests { } #[test] - pub fn choose_weighted() { + fn choose_weighted() { let r = rand::Rng(); assert!(r.choose_weighted(~[ rand::Weighted { weight: 1u, item: 42 }, @@ -698,7 +872,7 @@ pub mod tests { } #[test] - pub fn choose_weighted_option() { + fn choose_weighted_option() { let r = rand::Rng(); assert!(r.choose_weighted_option(~[ rand::Weighted { weight: 1u, item: 42 }, @@ -712,7 +886,7 @@ pub mod tests { } #[test] - pub fn weighted_vec() { + fn weighted_vec() { let r = rand::Rng(); let empty: ~[int] = ~[]; assert!(r.weighted_vec(~[]) == empty); @@ -724,7 +898,7 @@ pub mod tests { } #[test] - pub fn shuffle() { + fn shuffle() { let r = rand::Rng(); let empty: ~[int] = ~[]; assert!(r.shuffle(~[]) == empty); @@ -732,7 +906,7 @@ pub mod tests { } #[test] - pub fn task_rng() { + fn task_rng() { let r = rand::task_rng(); r.gen_int(); assert!(r.shuffle(~[1, 1, 1]) == ~[1, 1, 1]); @@ -740,7 +914,7 @@ pub mod tests { } #[test] - pub fn random() { + fn random() { // not sure how to test this aside from just getting a number let _n : uint = rand::random(); } diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 3e11febc5bfaa..9a0526b4351ba 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -15,6 +15,7 @@ Runtime type reflection */ use intrinsic::{TyDesc, TyVisitor}; +#[cfg(not(stage0))] use intrinsic::Opaque; use libc::c_void; use sys; use vec; @@ -393,6 +394,7 @@ impl TyVisitor for MovePtrAdaptor { true } + #[cfg(stage0)] fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) -> bool { self.align(align); @@ -402,11 +404,23 @@ impl TyVisitor for MovePtrAdaptor { true } + #[cfg(not(stage0))] + fn visit_enter_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, + sz: uint, align: uint) + -> bool { + self.align(align); + if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) { + return false; + } + true + } + fn visit_enter_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool { - self.inner.push_ptr(); + self.inner.push_ptr(); // NOTE remove after next snapshot if ! self.inner.visit_enter_enum_variant(variant, disr_val, n_fields, name) { return false; @@ -414,6 +428,7 @@ impl TyVisitor for MovePtrAdaptor { true } + #[cfg(stage0)] fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { unsafe { self.align((*inner).align); } if ! self.inner.visit_enum_variant_field(i, inner) { return false; } @@ -421,6 +436,15 @@ impl TyVisitor for MovePtrAdaptor { true } + #[cfg(not(stage0))] + fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool { + self.inner.push_ptr(); + self.bump(offset); + if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; } + self.inner.pop_ptr(); + true + } + fn visit_leave_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, @@ -429,10 +453,11 @@ impl TyVisitor for MovePtrAdaptor { n_fields, name) { return false; } - self.inner.pop_ptr(); + self.inner.pop_ptr(); // NOTE remove after next snapshot true } + #[cfg(stage0)] fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) -> bool { if ! self.inner.visit_leave_enum(n_variants, sz, align) { @@ -442,10 +467,21 @@ impl TyVisitor for MovePtrAdaptor { true } + #[cfg(not(stage0))] + fn visit_leave_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, + sz: uint, align: uint) -> bool { + if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) { + return false; + } + self.bump(sz); + true + } + fn visit_trait(&self) -> bool { - self.align_to::(); + self.align_to::<@TyVisitor>(); if ! self.inner.visit_trait() { return false; } - self.bump_past::(); + self.bump_past::<@TyVisitor>(); true } diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index a51f874f3712c..530f80ef764cd 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -18,6 +18,7 @@ use cast::transmute; use char; use intrinsic; use intrinsic::{TyDesc, TyVisitor, visit_tydesc}; +#[cfg(not(stage0))] use intrinsic::Opaque; use io::{Writer, WriterUtil}; use libc::c_void; use managed; @@ -137,12 +138,20 @@ impl Repr for char { // New implementation using reflect::MovePtr +#[cfg(stage0)] enum VariantState { Degenerate, TagMatch, TagMismatch, } +#[cfg(not(stage0))] +enum VariantState { + SearchingFor(int), + Matched, + AlreadyFound +} + pub struct ReprVisitor { mut ptr: *c_void, mut ptr_stk: ~[*c_void], @@ -181,14 +190,14 @@ pub impl ReprVisitor { true } - #[inline(always)] + #[cfg(stage0)] #[inline(always)] fn bump(&self, sz: uint) { do self.move_ptr() |p| { ((p as uint) + sz) as *c_void }; } - #[inline(always)] + #[cfg(stage0)] #[inline(always)] fn bump_past(&self) { self.bump(sys::size_of::()); } @@ -458,6 +467,7 @@ impl TyVisitor for ReprVisitor { true } + #[cfg(stage0)] fn visit_enter_enum(&self, n_variants: uint, _sz: uint, _align: uint) -> bool { if n_variants == 1 { @@ -468,6 +478,16 @@ impl TyVisitor for ReprVisitor { true } + #[cfg(not(stage0))] + fn visit_enter_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, + _sz: uint, _align: uint) -> bool { + let disr = unsafe { get_disr(transmute(self.ptr)) }; + self.var_stk.push(SearchingFor(disr)); + true + } + + #[cfg(stage0)] fn visit_enter_enum_variant(&self, _variant: uint, disr_val: int, n_fields: uint, @@ -500,6 +520,36 @@ impl TyVisitor for ReprVisitor { true } + #[cfg(not(stage0))] + fn visit_enter_enum_variant(&self, _variant: uint, + disr_val: int, + n_fields: uint, + name: &str) -> bool { + let mut write = false; + match self.var_stk.pop() { + SearchingFor(sought) => { + if disr_val == sought { + self.var_stk.push(Matched); + write = true; + } else { + self.var_stk.push(SearchingFor(sought)); + } + } + Matched | AlreadyFound => { + self.var_stk.push(AlreadyFound); + } + } + + if write { + self.writer.write_str(name); + if n_fields > 0 { + self.writer.write_char('('); + } + } + true + } + + #[cfg(stage0)] fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { Degenerate | TagMatch => { @@ -515,6 +565,23 @@ impl TyVisitor for ReprVisitor { true } + #[cfg(not(stage0))] + fn visit_enum_variant_field(&self, i: uint, _offset: uint, inner: *TyDesc) -> bool { + match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { + Matched => { + if i != 0 { + self.writer.write_str(", "); + } + if ! self.visit_inner(inner) { + return false; + } + } + _ => () + } + true + } + + #[cfg(stage0)] fn visit_leave_enum_variant(&self, _variant: uint, _disr_val: int, n_fields: uint, @@ -530,12 +597,39 @@ impl TyVisitor for ReprVisitor { true } + #[cfg(not(stage0))] + fn visit_leave_enum_variant(&self, _variant: uint, + _disr_val: int, + n_fields: uint, + _name: &str) -> bool { + match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { + Matched => { + if n_fields > 0 { + self.writer.write_char(')'); + } + } + _ => () + } + true + } + + #[cfg(stage0)] fn visit_leave_enum(&self, _n_variants: uint, _sz: uint, _align: uint) -> bool { self.var_stk.pop(); true } + #[cfg(not(stage0))] + fn visit_leave_enum(&self, _n_variants: uint, + _get_disr: extern unsafe fn(ptr: *Opaque) -> int, + _sz: uint, _align: uint) -> bool { + match self.var_stk.pop() { + SearchingFor(*) => fail!(~"enum value matched no variant"), + _ => true + } + } + fn visit_enter_fn(&self, _purity: uint, _proto: uint, _n_inputs: uint, _retstyle: uint) -> bool { true } fn visit_fn_input(&self, _i: uint, _mode: uint, _inner: *TyDesc) -> bool { diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 24822f52e1e84..58e281c29c605 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -39,9 +39,8 @@ pub enum Result { pub fn get(res: &Result) -> T { match *res { Ok(copy t) => t, - Err(ref the_err) => unsafe { + Err(ref the_err) => fail!(fmt!("get called on error result: %?", *the_err)) - } } } @@ -56,9 +55,8 @@ pub fn get(res: &Result) -> T { pub fn get_ref<'a, T, U>(res: &'a Result) -> &'a T { match *res { Ok(ref t) => t, - Err(ref the_err) => unsafe { + Err(ref the_err) => fail!(fmt!("get_ref called on error result: %?", *the_err)) - } } } @@ -228,9 +226,16 @@ pub fn map_err(res: &Result, op: &fn(&E) -> F) } pub impl Result { + #[cfg(stage0)] #[inline(always)] fn get_ref(&self) -> &'self T { get_ref(self) } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn get_ref<'a>(&'a self) -> &'a T { get_ref(self) } + #[inline(always)] fn is_ok(&self) -> bool { is_ok(self) } diff --git a/src/libcore/rt/context.rs b/src/libcore/rt/context.rs index 224f28a0329f8..4714be9e3d520 100644 --- a/src/libcore/rt/context.rs +++ b/src/libcore/rt/context.rs @@ -189,6 +189,7 @@ fn initialize_call_frame(regs: &mut Registers, fptr: *c_void, arg: *c_void, sp: regs[4] = arg as uint; regs[29] = sp as uint; + regs[25] = fptr as uint; regs[31] = fptr as uint; } @@ -204,8 +205,6 @@ fn align_down(sp: *mut uint) -> *mut uint { #[inline(always)] pub fn mut_offset(ptr: *mut T, count: int) -> *mut T { use core::sys::size_of; - unsafe { - (ptr as int + count * (size_of::() as int)) as *mut T - } + (ptr as int + count * (size_of::() as int)) as *mut T } diff --git a/src/libcore/rt/rtio.rs b/src/libcore/rt/rtio.rs index 55e062de85b06..6a7c3970c0091 100644 --- a/src/libcore/rt/rtio.rs +++ b/src/libcore/rt/rtio.rs @@ -22,7 +22,12 @@ pub trait EventLoop { fn run(&mut self); fn callback(&mut self, ~fn()); /// The asynchronous I/O services. Not all event loops may provide one + #[cfg(stage0)] fn io(&mut self) -> Option<&'self mut IoFactoryObject>; + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; } pub trait IoFactory { diff --git a/src/libcore/rt/sched.rs b/src/libcore/rt/sched.rs index 46ea5713e2af3..25f446fb86d19 100644 --- a/src/libcore/rt/sched.rs +++ b/src/libcore/rt/sched.rs @@ -272,6 +272,7 @@ pub impl Scheduler { // XXX: Hack. This should return &'self mut but I don't know how to // make the borrowcheck happy + #[cfg(stage0)] fn task_from_last_cleanup_job(&mut self) -> &mut Task { assert!(!self.cleanup_jobs.is_empty()); let last_job: &'self mut CleanupJob = &mut self.cleanup_jobs[0]; @@ -285,6 +286,25 @@ pub impl Scheduler { // borrows return unsafe { transmute::<&Task, &mut Task>(last_task) }; } + + // XXX: Hack. This should return &'self mut but I don't know how to + // make the borrowcheck happy + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn task_from_last_cleanup_job<'a>(&'a mut self) -> &mut Task { + assert!(!self.cleanup_jobs.is_empty()); + let last_job: &'a mut CleanupJob = &mut self.cleanup_jobs[0]; + let last_task: &'a Task = match last_job { + &RescheduleTask(~ref task) => task, + &RecycleTask(~ref task) => task, + &GiveTask(~ref task, _) => task, + }; + // XXX: Pattern matching mutable pointers above doesn't work + // because borrowck thinks the three patterns are conflicting + // borrows + return unsafe { transmute::<&Task, &mut Task>(last_task) }; + } } static TASK_MIN_STACK_SIZE: uint = 10000000; // XXX: Too much stack @@ -354,6 +374,7 @@ impl ThreadLocalScheduler { } } + #[cfg(stage0)] fn get_scheduler(&mut self) -> &'self mut Scheduler { unsafe { let key = match self { &ThreadLocalScheduler(key) => key }; @@ -370,6 +391,25 @@ impl ThreadLocalScheduler { } } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get_scheduler<'a>(&'a mut self) -> &'a mut Scheduler { + unsafe { + let key = match self { &ThreadLocalScheduler(key) => key }; + let mut value: *mut c_void = tls::get(key); + assert!(value.is_not_null()); + { + let value_ptr = &mut value; + let sched: &mut ~Scheduler = { + transmute::<&mut *mut c_void, &mut ~Scheduler>(value_ptr) + }; + let sched: &mut Scheduler = &mut **sched; + return sched; + } + } + } + fn take_scheduler(&mut self) -> ~Scheduler { unsafe { let key = match self { &ThreadLocalScheduler(key) => key }; diff --git a/src/libcore/rt/thread_local_storage.rs b/src/libcore/rt/thread_local_storage.rs index c8a9689bbc67a..366996fb93560 100644 --- a/src/libcore/rt/thread_local_storage.rs +++ b/src/libcore/rt/thread_local_storage.rs @@ -21,17 +21,17 @@ pub type Key = pthread_key_t; #[cfg(unix)] pub unsafe fn create(key: &mut Key) { - unsafe { assert!(0 == pthread_key_create(key, null())); } + assert!(0 == pthread_key_create(key, null())); } #[cfg(unix)] pub unsafe fn set(key: Key, value: *mut c_void) { - unsafe { assert!(0 == pthread_setspecific(key, value)); } + assert!(0 == pthread_setspecific(key, value)); } #[cfg(unix)] pub unsafe fn get(key: Key) -> *mut c_void { - unsafe { pthread_getspecific(key) } + pthread_getspecific(key) } #[cfg(target_os="macos")] diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 37f29d1a5c0fe..7162ed27a9d77 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -67,9 +67,17 @@ impl EventLoop for UvEventLoop { } } + #[cfg(stage0)] fn io(&mut self) -> Option<&'self mut IoFactoryObject> { Some(&mut self.uvio) } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { + Some(&mut self.uvio) + } } #[test] @@ -89,9 +97,17 @@ fn test_callback_run_once() { pub struct UvIoFactory(Loop); pub impl UvIoFactory { + #[cfg(stage0)] fn uv_loop(&mut self) -> &'self mut Loop { match self { &UvIoFactory(ref mut ptr) => ptr } } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { + match self { &UvIoFactory(ref mut ptr) => ptr } + } } impl IoFactory for UvIoFactory { diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 8116ea952e425..8e247a25012f1 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -44,13 +44,13 @@ pub trait Program { /// Returns the process id of the program fn get_id(&mut self) -> pid_t; - /// Returns an io::writer that can be used to write to stdin + /// Returns an io::Writer that can be used to write to stdin fn input(&mut self) -> @io::Writer; - /// Returns an io::reader that can be used to read from stdout + /// Returns an io::Reader that can be used to read from stdout fn output(&mut self) -> @io::Reader; - /// Returns an io::reader that can be used to read from stderr + /// Returns an io::Reader that can be used to read from stderr fn err(&mut self) -> @io::Reader; /// Closes the handle to the child processes standard input @@ -62,8 +62,23 @@ pub trait Program { */ fn finish(&mut self) -> int; - /// Closes open handles + /** + * Terminate the program, giving it a chance to clean itself up if + * this is supported by the operating system. + * + * On Posix OSs SIGTERM will be sent to the process. On Win32 + * TerminateProcess(..) will be called. + */ fn destroy(&mut self); + + /** + * Terminate the program as soon as possible without giving it a + * chance to clean itself up. + * + * On Posix OSs SIGKILL will be sent to the process. On Win32 + * TerminateProcess(..) will be called. + */ + fn force_destroy(&mut self); } @@ -172,6 +187,14 @@ fn with_dirp(d: &Option<~str>, } } +/// helper function that closes non-NULL files and then makes them NULL +priv unsafe fn fclose_and_null(f: &mut *libc::FILE) { + if *f != 0 as *libc::FILE { + libc::fclose(*f); + *f = 0 as *libc::FILE; + } +} + /** * Spawns a process and waits for it to terminate * @@ -192,9 +215,9 @@ pub fn run_program(prog: &str, args: &[~str]) -> int { } /** - * Spawns a process and returns a program + * Spawns a process and returns a Program * - * The returned value is a boxed class containing a object that can + * The returned value is a boxed class containing a object that can * be used for sending and receiving data over the standard file descriptors. * The class will ensure that file descriptors are closed properly. * @@ -240,19 +263,49 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program { r.in_fd = invalid_fd; } } + + fn close_repr_outputs(r: &mut ProgRepr) { + unsafe { + fclose_and_null(&mut r.out_file); + fclose_and_null(&mut r.err_file); + } + } + fn finish_repr(r: &mut ProgRepr) -> int { if r.finished { return 0; } r.finished = true; close_repr_input(&mut *r); return waitpid(r.pid); } - fn destroy_repr(r: &mut ProgRepr) { - unsafe { - finish_repr(&mut *r); - libc::fclose(r.out_file); - libc::fclose(r.err_file); + + fn destroy_repr(r: &mut ProgRepr, force: bool) { + killpid(r.pid, force); + finish_repr(&mut *r); + close_repr_outputs(&mut *r); + + #[cfg(windows)] + fn killpid(pid: pid_t, _force: bool) { + unsafe { + libc::funcs::extra::kernel32::TerminateProcess( + cast::transmute(pid), 1); + } + } + + #[cfg(unix)] + fn killpid(pid: pid_t, force: bool) { + + let signal = if force { + libc::consts::os::posix88::SIGKILL + } else { + libc::consts::os::posix88::SIGTERM + }; + + unsafe { + libc::funcs::posix88::signal::kill(pid, signal as c_int); + } } } + struct ProgRes { r: ProgRepr, } @@ -260,8 +313,9 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program { impl Drop for ProgRes { fn finalize(&self) { unsafe { - // FIXME #4943: This is bad. - destroy_repr(cast::transmute(&self.r)); + // FIXME #4943: transmute is bad. + finish_repr(cast::transmute(&self.r)); + close_repr_outputs(cast::transmute(&self.r)); } } } @@ -285,8 +339,10 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program { } fn close_input(&mut self) { close_repr_input(&mut self.r); } fn finish(&mut self) -> int { finish_repr(&mut self.r) } - fn destroy(&mut self) { destroy_repr(&mut self.r); } + fn destroy(&mut self) { destroy_repr(&mut self.r, false); } + fn force_destroy(&mut self) { destroy_repr(&mut self.r, true); } } + let mut repr = ProgRepr { pid: pid, in_fd: pipe_input.out, @@ -298,7 +354,7 @@ pub fn start_program(prog: &str, args: &[~str]) -> @Program { @ProgRes(repr) as @Program } -fn read_all(rd: io::Reader) -> ~str { +fn read_all(rd: @io::Reader) -> ~str { let buf = io::with_bytes_writer(|wr| { let mut bytes = [0, ..4096]; while !rd.eof() { @@ -326,64 +382,62 @@ pub struct ProgramOutput {status: int, out: ~str, err: ~str} * the contents of stdout and the contents of stderr. */ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput { - unsafe { - let pipe_in = os::pipe(); - let pipe_out = os::pipe(); - let pipe_err = os::pipe(); - let pid = spawn_process(prog, args, &None, &None, - pipe_in.in, pipe_out.out, pipe_err.out); - - os::close(pipe_in.in); - os::close(pipe_out.out); - os::close(pipe_err.out); - if pid == -1i32 { - os::close(pipe_in.out); - os::close(pipe_out.in); - os::close(pipe_err.in); - fail!(); - } + let pipe_in = os::pipe(); + let pipe_out = os::pipe(); + let pipe_err = os::pipe(); + let pid = spawn_process(prog, args, &None, &None, + pipe_in.in, pipe_out.out, pipe_err.out); + os::close(pipe_in.in); + os::close(pipe_out.out); + os::close(pipe_err.out); + if pid == -1i32 { os::close(pipe_in.out); + os::close(pipe_out.in); + os::close(pipe_err.in); + fail!(); + } - // Spawn two entire schedulers to read both stdout and sterr - // in parallel so we don't deadlock while blocking on one - // or the other. FIXME (#2625): Surely there's a much more - // clever way to do this. - let (p, ch) = stream(); - let ch = SharedChan(ch); - let ch_clone = ch.clone(); - do task::spawn_sched(task::SingleThreaded) { - let errput = readclose(pipe_err.in); - ch.send((2, errput)); - }; - do task::spawn_sched(task::SingleThreaded) { - let output = readclose(pipe_out.in); - ch_clone.send((1, output)); - }; - let status = run::waitpid(pid); - let mut errs = ~""; - let mut outs = ~""; - let mut count = 2; - while count > 0 { - let stream = p.recv(); - match stream { - (1, copy s) => { - outs = s; - } - (2, copy s) => { - errs = s; - } - (n, _) => { - fail!(fmt!("program_output received an unexpected file \ - number: %u", n)); - } - }; - count -= 1; + os::close(pipe_in.out); + + // Spawn two entire schedulers to read both stdout and sterr + // in parallel so we don't deadlock while blocking on one + // or the other. FIXME (#2625): Surely there's a much more + // clever way to do this. + let (p, ch) = stream(); + let ch = SharedChan(ch); + let ch_clone = ch.clone(); + do task::spawn_sched(task::SingleThreaded) { + let errput = readclose(pipe_err.in); + ch.send((2, errput)); + }; + do task::spawn_sched(task::SingleThreaded) { + let output = readclose(pipe_out.in); + ch_clone.send((1, output)); + }; + let status = run::waitpid(pid); + let mut errs = ~""; + let mut outs = ~""; + let mut count = 2; + while count > 0 { + let stream = p.recv(); + match stream { + (1, copy s) => { + outs = s; + } + (2, copy s) => { + errs = s; + } + (n, _) => { + fail!(fmt!("program_output received an unexpected file \ + number: %u", n)); + } }; - return ProgramOutput {status: status, - out: outs, - err: errs}; - } + count -= 1; + }; + return ProgramOutput {status: status, + out: outs, + err: errs}; } pub fn writeclose(fd: c_int, s: ~str) { @@ -458,14 +512,16 @@ pub fn waitpid(pid: pid_t) -> int { #[cfg(test)] mod tests { + use libc; use option::None; use os; + use path::Path; use run::{readclose, writeclose}; use run; // Regression test for memory leaks #[ignore(cfg(windows))] // FIXME (#2626) - pub fn test_leaks() { + fn test_leaks() { run::run_program("echo", []); run::start_program("echo", []); run::program_output("echo", []); @@ -473,7 +529,7 @@ mod tests { #[test] #[allow(non_implicitly_copyable_typarams)] - pub fn test_pipes() { + fn test_pipes() { let pipe_in = os::pipe(); let pipe_out = os::pipe(); let pipe_err = os::pipe(); @@ -499,7 +555,7 @@ mod tests { } #[test] - pub fn waitpid() { + fn waitpid() { let pid = run::spawn_process("false", [], &None, &None, 0i32, 0i32, 0i32); @@ -507,6 +563,50 @@ mod tests { assert!(status == 1); } + #[test] + fn test_destroy_once() { + let mut p = run::start_program("echo", []); + p.destroy(); // this shouldn't crash (and nor should the destructor) + } + + #[test] + fn test_destroy_twice() { + let mut p = run::start_program("echo", []); + p.destroy(); // this shouldnt crash... + p.destroy(); // ...and nor should this (and nor should the destructor) + } + + #[cfg(unix)] // there is no way to sleep on windows from inside libcore... + fn test_destroy_actually_kills(force: bool) { + let path = Path(fmt!("test/core-run-test-destroy-actually-kills-%?.tmp", force)); + + os::remove_file(&path); + + let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str()); + let mut p = run::start_program("sh", [~"-c", cmd]); + + p.destroy(); // destroy the program before it has a chance to echo its message + + unsafe { + // wait to ensure the program is really destroyed and not just waiting itself + libc::sleep(10); + } + + // the program should not have had chance to echo its message + assert!(!path.exists()); + } + + #[test] + #[cfg(unix)] + fn test_unforced_destroy_actually_kills() { + test_destroy_actually_kills(false); + } + + #[test] + #[cfg(unix)] + fn test_forced_destroy_actually_kills() { + test_destroy_actually_kills(true); + } } // Local Variables: diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 67fd37996cda0..b0653db365e03 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -38,7 +38,7 @@ Section: Creating a string */ /** - * Convert a vector of bytes to a UTF-8 string + * Convert a vector of bytes to a new UTF-8 string * * # Failure * @@ -49,9 +49,26 @@ pub fn from_bytes(vv: &const [u8]) -> ~str { return unsafe { raw::from_bytes(vv) }; } +/** + * Convert a vector of bytes to a UTF-8 string. + * The vector needs to be one byte longer than the string, and end with a 0 byte. + * + * Compared to `from_bytes()`, this fn doesn't need to allocate a new owned str. + * + * # Failure + * + * Fails if invalid UTF-8 + * Fails if not null terminated + */ +pub fn from_bytes_with_null<'a>(vv: &'a [u8]) -> &'a str { + assert!(vv[vv.len() - 1] == 0); + assert!(is_utf8(vv)); + return unsafe { raw::from_bytes_with_null(vv) }; +} + /// Copy a slice into a new unique str pub fn from_slice(s: &str) -> ~str { - unsafe { raw::slice_bytes_unique(s, 0, len(s)) } + unsafe { raw::slice_bytes_owned(s, 0, len(s)) } } impl ToStr for ~str { @@ -153,18 +170,16 @@ pub fn push_char(s: &mut ~str, ch: char) { /// Convert a char to a string pub fn from_char(ch: char) -> ~str { let mut buf = ~""; - unsafe { push_char(&mut buf, ch); } + push_char(&mut buf, ch); buf } /// Convert a vector of chars to a string pub fn from_chars(chs: &[char]) -> ~str { let mut buf = ~""; - unsafe { - reserve(&mut buf, chs.len()); - for vec::each(chs) |ch| { - push_char(&mut buf, *ch); - } + reserve(&mut buf, chs.len()); + for vec::each(chs) |ch| { + push_char(&mut buf, *ch); } buf } @@ -209,9 +224,7 @@ pub fn push_str(lhs: &mut ~str, rhs: &str) { #[inline(always)] pub fn append(lhs: ~str, rhs: &str) -> ~str { let mut v = lhs; - unsafe { - push_str_no_overallocate(&mut v, rhs); - } + push_str_no_overallocate(&mut v, rhs); v } @@ -219,7 +232,7 @@ pub fn append(lhs: ~str, rhs: &str) -> ~str { pub fn concat(v: &[~str]) -> ~str { let mut s: ~str = ~""; for vec::each(v) |ss| { - unsafe { push_str(&mut s, *ss) }; + push_str(&mut s, *ss); } s } @@ -228,8 +241,8 @@ pub fn concat(v: &[~str]) -> ~str { pub fn connect(v: &[~str], sep: &str) -> ~str { let mut s = ~"", first = true; for vec::each(v) |ss| { - if first { first = false; } else { unsafe { push_str(&mut s, sep); } } - unsafe { push_str(&mut s, *ss) }; + if first { first = false; } else { push_str(&mut s, sep); } + push_str(&mut s, *ss); } s } @@ -238,8 +251,8 @@ pub fn connect(v: &[~str], sep: &str) -> ~str { pub fn connect_slices(v: &[&str], sep: &str) -> ~str { let mut s = ~"", first = true; for vec::each(v) |ss| { - if first { first = false; } else { unsafe { push_str(&mut s, sep); } } - unsafe { push_str(&mut s, *ss) }; + if first { first = false; } else { push_str(&mut s, sep); } + push_str(&mut s, *ss); } s } @@ -279,7 +292,7 @@ pub fn pop_char(s: &mut ~str) -> char { */ pub fn shift_char(s: &mut ~str) -> char { let CharRange {ch, next} = char_range_at(*s, 0u); - *s = unsafe { raw::slice_bytes_unique(*s, next, len(*s)) }; + *s = unsafe { raw::slice_bytes_owned(*s, next, len(*s)) }; return ch; } @@ -301,7 +314,11 @@ pub fn slice_shift_char<'a>(s: &'a str) -> (char, &'a str) { /// Prepend a char to a string pub fn unshift_char(s: &mut ~str, ch: char) { - *s = from_char(ch) + *s; + // This could be more efficient. + let mut new_str = ~""; + new_str.push_char(ch); + new_str.push_str(*s); + *s = new_str; } /** @@ -784,9 +801,9 @@ pub fn replace(s: &str, from: &str, to: &str) -> ~str { if first { first = false; } else { - unsafe { push_str(&mut result, to); } + push_str(&mut result, to); } - unsafe { push_str(&mut result, raw::slice_bytes_unique(s, start, end)); } + push_str(&mut result, unsafe{raw::slice_bytes(s, start, end)}); } result } @@ -1020,11 +1037,9 @@ pub fn any(ss: &str, pred: &fn(char) -> bool) -> bool { /// Apply a function to each character pub fn map(ss: &str, ff: &fn(char) -> char) -> ~str { let mut result = ~""; - unsafe { - reserve(&mut result, len(ss)); - for ss.each_char |cc| { - str::push_char(&mut result, ff(cc)); - } + reserve(&mut result, len(ss)); + for ss.each_char |cc| { + str::push_char(&mut result, ff(cc)); } result } @@ -1660,20 +1675,18 @@ pub fn to_utf16(s: &str) -> ~[u16] { // Arithmetic with u32 literals is easier on the eyes than chars. let mut ch = ch as u32; - unsafe { - if (ch & 0xFFFF_u32) == ch { - // The BMP falls through (assuming non-surrogate, as it - // should) - assert!(ch <= 0xD7FF_u32 || ch >= 0xE000_u32); - u.push(ch as u16) - } else { - // Supplementary planes break into surrogates. - assert!(ch >= 0x1_0000_u32 && ch <= 0x10_FFFF_u32); - ch -= 0x1_0000_u32; - let w1 = 0xD800_u16 | ((ch >> 10) as u16); - let w2 = 0xDC00_u16 | ((ch as u16) & 0x3FF_u16); - u.push_all(~[w1, w2]) - } + if (ch & 0xFFFF_u32) == ch { + // The BMP falls through (assuming non-surrogate, as it + // should) + assert!(ch <= 0xD7FF_u32 || ch >= 0xE000_u32); + u.push(ch as u16) + } else { + // Supplementary planes break into surrogates. + assert!(ch >= 0x1_0000_u32 && ch <= 0x10_FFFF_u32); + ch -= 0x1_0000_u32; + let w1 = 0xD800_u16 | ((ch >> 10) as u16); + let w2 = 0xDC00_u16 | ((ch as u16) & 0x3FF_u16); + u.push_all(~[w1, w2]) } } u @@ -1705,16 +1718,14 @@ pub fn utf16_chars(v: &[u16], f: &fn(char)) { pub fn from_utf16(v: &[u16]) -> ~str { let mut buf = ~""; - unsafe { - reserve(&mut buf, vec::len(v)); - utf16_chars(v, |ch| push_char(&mut buf, ch)); - } + reserve(&mut buf, vec::len(v)); + utf16_chars(v, |ch| push_char(&mut buf, ch)); buf } pub fn with_capacity(capacity: uint) -> ~str { let mut buf = ~""; - unsafe { reserve(&mut buf, capacity); } + reserve(&mut buf, capacity); buf } @@ -2043,6 +2054,37 @@ pub fn as_buf(s: &str, f: &fn(*u8, uint) -> T) -> T { } } +/** + * Returns the byte offset of an inner slice relative to an enclosing outer slice + * + * # Example + * + * ~~~ + * let string = "a\nb\nc"; + * let mut lines = ~[]; + * for each_line(string) |line| { lines.push(line) } + * + * assert!(subslice_offset(string, lines[0]) == 0); // &"a" + * assert!(subslice_offset(string, lines[1]) == 2); // &"b" + * assert!(subslice_offset(string, lines[2]) == 4); // &"c" + * ~~~ + */ +#[inline(always)] +pub fn subslice_offset(outer: &str, inner: &str) -> uint { + do as_buf(outer) |a, a_len| { + do as_buf(inner) |b, b_len| { + let a_start: uint, a_end: uint, b_start: uint, b_end: uint; + unsafe { + a_start = cast::transmute(a); a_end = a_len + cast::transmute(a); + b_start = cast::transmute(b); b_end = b_len + cast::transmute(b); + } + assert!(a_start <= b_start); + assert!(b_end <= a_end); + b_start - a_start + } + } +} + /** * Reserves capacity for exactly `n` bytes in the given string, not including * the null terminator. @@ -2105,11 +2147,9 @@ pub fn capacity(s: &const ~str) -> uint { /// Escape each char in `s` with char::escape_default. pub fn escape_default(s: &str) -> ~str { let mut out: ~str = ~""; - unsafe { - reserve_at_least(&mut out, str::len(s)); - for s.each_char |c| { - push_str(&mut out, char::escape_default(c)); - } + reserve_at_least(&mut out, str::len(s)); + for s.each_char |c| { + push_str(&mut out, char::escape_default(c)); } out } @@ -2117,11 +2157,9 @@ pub fn escape_default(s: &str) -> ~str { /// Escape each char in `s` with char::escape_unicode. pub fn escape_unicode(s: &str) -> ~str { let mut out: ~str = ~""; - unsafe { - reserve_at_least(&mut out, str::len(s)); - for s.each_char |c| { - push_str(&mut out, char::escape_unicode(c)); - } + reserve_at_least(&mut out, str::len(s)); + for s.each_char |c| { + push_str(&mut out, char::escape_unicode(c)); } out } @@ -2168,13 +2206,20 @@ pub mod raw { from_buf_len(::cast::reinterpret_cast(&c_str), len) } - /// Converts a vector of bytes to a string. + /// Converts a vector of bytes to a new owned string. pub unsafe fn from_bytes(v: &const [u8]) -> ~str { do vec::as_const_buf(v) |buf, len| { from_buf_len(buf, len) } } + /// Converts a vector of bytes to a string. + /// The byte slice needs to contain valid utf8 and needs to be one byte longer than + /// the string, if possible ending in a 0 byte. + pub unsafe fn from_bytes_with_null<'a>(v: &'a [u8]) -> &'a str { + cast::transmute(v) + } + /// Converts a byte to a string. pub unsafe fn from_byte(u: u8) -> ~str { raw::from_bytes([u]) } @@ -2196,22 +2241,20 @@ pub mod raw { * If begin is greater than end. * If end is greater than the length of the string. */ - pub unsafe fn slice_bytes_unique(s: &str, begin: uint, end: uint) -> ~str { + pub unsafe fn slice_bytes_owned(s: &str, begin: uint, end: uint) -> ~str { do as_buf(s) |sbuf, n| { assert!((begin <= end)); assert!((end <= n)); let mut v = vec::with_capacity(end - begin + 1u); - unsafe { - do vec::as_imm_buf(v) |vbuf, _vlen| { - let vbuf = ::cast::transmute_mut_unsafe(vbuf); - let src = ptr::offset(sbuf, begin); - ptr::copy_memory(vbuf, src, end - begin); - } - vec::raw::set_len(&mut v, end - begin); - v.push(0u8); - ::cast::transmute(v) + do vec::as_imm_buf(v) |vbuf, _vlen| { + let vbuf = ::cast::transmute_mut_unsafe(vbuf); + let src = ptr::offset(sbuf, begin); + ptr::copy_memory(vbuf, src, end - begin); } + vec::raw::set_len(&mut v, end - begin); + v.push(0u8); + ::cast::transmute(v) } } @@ -2255,7 +2298,7 @@ pub mod raw { } /// Removes the last byte from a string and returns it. (Not UTF-8 safe). - pub unsafe fn pop_byte(s: &mut ~str) -> u8 { + pub fn pop_byte(s: &mut ~str) -> u8 { let len = len(*s); assert!((len > 0u)); let b = s[len - 1u]; @@ -2264,18 +2307,18 @@ pub mod raw { } /// Removes the first byte from a string and returns it. (Not UTF-8 safe). - pub unsafe fn shift_byte(s: &mut ~str) -> u8 { + pub fn shift_byte(s: &mut ~str) -> u8 { let len = len(*s); assert!((len > 0u)); let b = s[0]; - *s = unsafe { raw::slice_bytes_unique(*s, 1u, len) }; + *s = unsafe { raw::slice_bytes_owned(*s, 1u, len) }; return b; } /// Sets the length of the string and adds the null terminator pub unsafe fn set_len(v: &mut ~str, new_len: uint) { - let v: **vec::raw::VecRepr = cast::transmute(v); - let repr: *vec::raw::VecRepr = *v; + let v: **mut vec::raw::VecRepr = cast::transmute(v); + let repr: *mut vec::raw::VecRepr = *v; (*repr).unboxed.fill = new_len + 1u; let null = ptr::mut_offset(cast::transmute(&((*repr).unboxed.data)), new_len); @@ -3299,6 +3342,66 @@ mod tests { let _x = from_bytes(bb); } + #[test] + fn test_unsafe_from_bytes_with_null() { + let a = [65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 65u8, 0u8]; + let b = unsafe { raw::from_bytes_with_null(a) }; + assert_eq!(b, "AAAAAAA"); + } + + #[test] + fn test_from_bytes_with_null() { + let ss = "ศไทย中华Việt Nam"; + let bb = [0xe0_u8, 0xb8_u8, 0xa8_u8, + 0xe0_u8, 0xb9_u8, 0x84_u8, + 0xe0_u8, 0xb8_u8, 0x97_u8, + 0xe0_u8, 0xb8_u8, 0xa2_u8, + 0xe4_u8, 0xb8_u8, 0xad_u8, + 0xe5_u8, 0x8d_u8, 0x8e_u8, + 0x56_u8, 0x69_u8, 0xe1_u8, + 0xbb_u8, 0x87_u8, 0x74_u8, + 0x20_u8, 0x4e_u8, 0x61_u8, + 0x6d_u8, 0x0_u8]; + + assert_eq!(ss, from_bytes_with_null(bb)); + } + + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_from_bytes_with_null_fail() { + let bb = [0xff_u8, 0xb8_u8, 0xa8_u8, + 0xe0_u8, 0xb9_u8, 0x84_u8, + 0xe0_u8, 0xb8_u8, 0x97_u8, + 0xe0_u8, 0xb8_u8, 0xa2_u8, + 0xe4_u8, 0xb8_u8, 0xad_u8, + 0xe5_u8, 0x8d_u8, 0x8e_u8, + 0x56_u8, 0x69_u8, 0xe1_u8, + 0xbb_u8, 0x87_u8, 0x74_u8, + 0x20_u8, 0x4e_u8, 0x61_u8, + 0x6d_u8, 0x0_u8]; + + let _x = from_bytes_with_null(bb); + } + + #[test] + #[should_fail] + #[ignore(cfg(windows))] + fn test_from_bytes_with_null_fail_2() { + let bb = [0xff_u8, 0xb8_u8, 0xa8_u8, + 0xe0_u8, 0xb9_u8, 0x84_u8, + 0xe0_u8, 0xb8_u8, 0x97_u8, + 0xe0_u8, 0xb8_u8, 0xa2_u8, + 0xe4_u8, 0xb8_u8, 0xad_u8, + 0xe5_u8, 0x8d_u8, 0x8e_u8, + 0x56_u8, 0x69_u8, 0xe1_u8, + 0xbb_u8, 0x87_u8, 0x74_u8, + 0x20_u8, 0x4e_u8, 0x61_u8, + 0x6d_u8, 0x60_u8]; + + let _x = from_bytes_with_null(bb); + } + #[test] fn test_from_buf() { unsafe { @@ -3361,6 +3464,30 @@ mod tests { } } + #[test] + fn test_subslice_offset() { + let a = "kernelsprite"; + let b = slice(a, 7, len(a)); + let c = slice(a, 0, len(a) - 6); + assert!(subslice_offset(a, b) == 7); + assert!(subslice_offset(a, c) == 0); + + let string = "a\nb\nc"; + let mut lines = ~[]; + for each_line(string) |line| { lines.push(line) } + assert!(subslice_offset(string, lines[0]) == 0); + assert!(subslice_offset(string, lines[1]) == 2); + assert!(subslice_offset(string, lines[2]) == 4); + } + + #[test] + #[should_fail] + fn test_subslice_offset_2() { + let a = "alchemiter"; + let b = "cruxtruder"; + subslice_offset(a, b); + } + #[test] fn vec_str_conversions() { let s1: ~str = ~"All mimsy were the borogoves"; diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 52ca020412676..04f96f5eb229e 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -127,10 +127,8 @@ pub fn refcount(t: @T) -> uint { } pub fn log_str(t: &T) -> ~str { - unsafe { - do io::with_str_writer |wr| { - repr::write_repr(wr, t) - } + do io::with_str_writer |wr| { + repr::write_repr(wr, t) } } @@ -157,19 +155,17 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { } pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! { - unsafe { - let (msg, file) = (msg.to_owned(), file.to_owned()); - begin_unwind(~"assertion failed: " + msg, file, line) - } + let (msg, file) = (msg.to_owned(), file.to_owned()); + begin_unwind(~"assertion failed: " + msg, file, line) } #[cfg(test)] -pub mod tests { +mod tests { use cast; use sys::{Closure, pref_align_of, size_of, nonzero_size_of}; #[test] - pub fn size_of_basic() { + fn size_of_basic() { assert!(size_of::() == 1u); assert!(size_of::() == 2u); assert!(size_of::() == 4u); @@ -180,20 +176,20 @@ pub mod tests { #[cfg(target_arch = "x86")] #[cfg(target_arch = "arm")] #[cfg(target_arch = "mips")] - pub fn size_of_32() { + fn size_of_32() { assert!(size_of::() == 4u); assert!(size_of::<*uint>() == 4u); } #[test] #[cfg(target_arch = "x86_64")] - pub fn size_of_64() { + fn size_of_64() { assert!(size_of::() == 8u); assert!(size_of::<*uint>() == 8u); } #[test] - pub fn nonzero_size_of_basic() { + fn nonzero_size_of_basic() { type Z = [i8, ..0]; assert!(size_of::() == 0u); assert!(nonzero_size_of::() == 1u); @@ -201,7 +197,7 @@ pub mod tests { } #[test] - pub fn align_of_basic() { + fn align_of_basic() { assert!(pref_align_of::() == 1u); assert!(pref_align_of::() == 2u); assert!(pref_align_of::() == 4u); @@ -211,20 +207,20 @@ pub mod tests { #[cfg(target_arch = "x86")] #[cfg(target_arch = "arm")] #[cfg(target_arch = "mips")] - pub fn align_of_32() { + fn align_of_32() { assert!(pref_align_of::() == 4u); assert!(pref_align_of::<*uint>() == 4u); } #[test] #[cfg(target_arch = "x86_64")] - pub fn align_of_64() { + fn align_of_64() { assert!(pref_align_of::() == 8u); assert!(pref_align_of::<*uint>() == 8u); } #[test] - pub fn synthesize_closure() { + fn synthesize_closure() { unsafe { let x = 10; let f: &fn(int) -> int = |y| x + y; diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index ee454312e0443..a6c4b6c526862 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -580,12 +580,10 @@ pub unsafe fn unkillable(f: &fn() -> U) -> U { } } - unsafe { - let t = rt::rust_get_task(); - let _allow_failure = AllowFailure(t); - rt::rust_task_inhibit_kill(t); - f() - } + let t = rt::rust_get_task(); + let _allow_failure = AllowFailure(t); + rt::rust_task_inhibit_kill(t); + f() } /// The inverse of unkillable. Only ever to be used nested in unkillable(). @@ -605,12 +603,10 @@ pub unsafe fn rekillable(f: &fn() -> U) -> U { } } - unsafe { - let t = rt::rust_get_task(); - let _allow_failure = DisallowFailure(t); - rt::rust_task_allow_kill(t); - f() - } + let t = rt::rust_get_task(); + let _allow_failure = DisallowFailure(t); + rt::rust_task_allow_kill(t); + f() } /** @@ -634,13 +630,11 @@ pub unsafe fn atomically(f: &fn() -> U) -> U { } } - unsafe { - let t = rt::rust_get_task(); - let _interrupts = DeferInterrupts(t); - rt::rust_task_inhibit_kill(t); - rt::rust_task_inhibit_yield(t); - f() - } + let t = rt::rust_get_task(); + let _interrupts = DeferInterrupts(t); + rt::rust_task_inhibit_kill(t); + rt::rust_task_inhibit_yield(t); + f() } #[test] #[should_fail] #[ignore(cfg(windows))] @@ -931,7 +925,7 @@ fn test_spawn_sched_childs_on_default_sched() { } #[cfg(test)] -pub mod testrt { +mod testrt { use libc; #[nolink] diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index 39e43ba6fc5e8..c71f7d26d40f1 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -79,7 +79,7 @@ use comm::{Chan, GenericChan}; use prelude::*; use unstable; use ptr; -use hashmap::linear::LinearSet; +use hashmap::HashSet; use task::local_data_priv::{local_get, local_set}; use task::rt::rust_task; use task::rt; @@ -96,10 +96,10 @@ macro_rules! move_it ( { $x:expr } => ( unsafe { let y = *ptr::addr_of(&($x)); y } ) ) -type TaskSet = LinearSet<*rust_task>; +type TaskSet = HashSet<*rust_task>; fn new_taskset() -> TaskSet { - LinearSet::new() + HashSet::new() } fn taskset_insert(tasks: &mut TaskSet, task: *rust_task) { let didnt_overwrite = tasks.insert(task); @@ -157,13 +157,13 @@ struct AncestorList(Option>); // Accessors for taskgroup arcs and ancestor arcs that wrap the unsafety. #[inline(always)] fn access_group(x: &TaskGroupArc, blk: &fn(TaskGroupInner) -> U) -> U { - unsafe { x.with(blk) } + x.with(blk) } #[inline(always)] fn access_ancestors(x: &unstable::Exclusive, blk: &fn(x: &mut AncestorNode) -> U) -> U { - unsafe { x.with(blk) } + x.with(blk) } // Iterates over an ancestor list. diff --git a/src/libcore/to_str.rs b/src/libcore/to_str.rs index a6004ed124174..980d4b445d04d 100644 --- a/src/libcore/to_str.rs +++ b/src/libcore/to_str.rs @@ -72,63 +72,42 @@ impl ToStr for (A, B, C) { impl<'self,A:ToStr> ToStr for &'self [A] { #[inline(always)] fn to_str(&self) -> ~str { - unsafe { - // FIXME #4568 - // Bleh -- not really unsafe - // push_str and push_char - let mut acc = ~"[", first = true; - for self.each |elt| { - unsafe { - if first { first = false; } - else { str::push_str(&mut acc, ~", "); } - str::push_str(&mut acc, elt.to_str()); - } - } - str::push_char(&mut acc, ']'); - acc + let mut acc = ~"[", first = true; + for self.each |elt| { + if first { first = false; } + else { str::push_str(&mut acc, ~", "); } + str::push_str(&mut acc, elt.to_str()); } + str::push_char(&mut acc, ']'); + acc } } impl ToStr for ~[A] { #[inline(always)] fn to_str(&self) -> ~str { - unsafe { - // FIXME #4568 - // Bleh -- not really unsafe - // push_str and push_char - let mut acc = ~"[", first = true; - for self.each |elt| { - unsafe { - if first { first = false; } - else { str::push_str(&mut acc, ~", "); } - str::push_str(&mut acc, elt.to_str()); - } - } - str::push_char(&mut acc, ']'); - acc + let mut acc = ~"[", first = true; + for self.each |elt| { + if first { first = false; } + else { str::push_str(&mut acc, ~", "); } + str::push_str(&mut acc, elt.to_str()); } + str::push_char(&mut acc, ']'); + acc } } impl ToStr for @[A] { #[inline(always)] fn to_str(&self) -> ~str { - unsafe { - // FIXME #4568 - // Bleh -- not really unsafe - // push_str and push_char - let mut acc = ~"[", first = true; - for self.each |elt| { - unsafe { - if first { first = false; } - else { str::push_str(&mut acc, ~", "); } - str::push_str(&mut acc, elt.to_str()); - } - } - str::push_char(&mut acc, ']'); - acc + let mut acc = ~"[", first = true; + for self.each |elt| { + if first { first = false; } + else { str::push_str(&mut acc, ~", "); } + str::push_str(&mut acc, elt.to_str()); } + str::push_char(&mut acc, ']'); + acc } } diff --git a/src/libcore/trie.rs b/src/libcore/trie.rs index 5d87e2a296d3d..f4e9ddbdd90a1 100644 --- a/src/libcore/trie.rs +++ b/src/libcore/trie.rs @@ -28,24 +28,6 @@ pub struct TrieMap { priv length: uint } -impl<'self,T> BaseIter<(uint, &'self T)> for TrieMap { - /// Visit all key-value pairs in order - #[inline(always)] - fn each(&self, f: &fn(&(uint, &'self T)) -> bool) { - self.root.each(f); - } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -impl<'self,T> ReverseIter<(uint, &'self T)> for TrieMap { - /// Visit all key-value pairs in reverse order - #[inline(always)] - fn each_reverse(&self, f: &fn(&(uint, &'self T)) -> bool) { - self.root.each_reverse(f); - } -} - impl Container for TrieMap { /// Return the number of elements in the map #[inline(always)] @@ -72,16 +54,42 @@ impl Map for TrieMap { self.find(key).is_some() } + /// Visit all key-value pairs in order + #[inline(always)] + #[cfg(stage0)] + fn each(&self, f: &fn(&uint, &'self T) -> bool) { + self.root.each(f); + } + + /// Visit all key-value pairs in order + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { + self.root.each(f); + } + /// Visit all keys in order #[inline(always)] fn each_key(&self, f: &fn(&uint) -> bool) { - self.each(|&(k, _)| f(&k)) + self.each(|k, _| f(k)) } /// Visit all values in order #[inline(always)] + #[cfg(stage0)] fn each_value(&self, f: &fn(&T) -> bool) { - self.each(|&(_, v)| f(v)) + self.each(|_, v| f(v)) + } + + /// Visit all values in order + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) { + self.each(|_, v| f(v)) } /// Iterate over the map and mutate the contained values @@ -91,6 +99,7 @@ impl Map for TrieMap { } /// Return a reference to the value corresponding to the key + #[cfg(stage0)] #[inline(hint)] fn find(&self, key: &uint) -> Option<&'self T> { let mut node: &'self TrieNode = &self.root; @@ -111,12 +120,46 @@ impl Map for TrieMap { } } + /// Return a reference to the value corresponding to the key + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(hint)] + fn find<'a>(&'a self, key: &uint) -> Option<&'a T> { + let mut node: &'a TrieNode = &self.root; + let mut idx = 0; + loop { + match node.children[chunk(*key, idx)] { + Internal(ref x) => node = &**x, + External(stored, ref value) => { + if stored == *key { + return Some(value) + } else { + return None + } + } + Nothing => return None + } + idx += 1; + } + } + /// Return a mutable reference to the value corresponding to the key + #[cfg(stage0)] #[inline(always)] fn find_mut(&mut self, key: &uint) -> Option<&'self mut T> { find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) } + /// Return a mutable reference to the value corresponding to the key + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + #[inline(always)] + fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut T> { + find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) + } + /// Insert a key-value pair into the map. An existing value for a /// key is replaced by the new value. Return true if the key did /// not already exist in the map. @@ -148,16 +191,32 @@ pub impl TrieMap { TrieMap{root: TrieNode::new(), length: 0} } + /// Visit all key-value pairs in reverse order + #[inline(always)] + #[cfg(stage0)] + fn each_reverse(&self, f: &fn(&uint, &'self T) -> bool) { + self.root.each_reverse(f); + } + + /// Visit all key-value pairs in reverse order + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { + self.root.each_reverse(f); + } + /// Visit all keys in reverse order #[inline(always)] fn each_key_reverse(&self, f: &fn(&uint) -> bool) { - self.each_reverse(|&(k, _)| f(&k)) + self.each_reverse(|k, _| f(k)) } /// Visit all values in reverse order #[inline(always)] fn each_value_reverse(&self, f: &fn(&T) -> bool) { - self.each_reverse(|&(_, v)| f(v)) + self.each_reverse(|_, v| f(v)) } } @@ -239,29 +298,59 @@ impl TrieNode { } impl TrieNode { - fn each(&self, f: &fn(&(uint, &'self T)) -> bool) -> bool { + #[cfg(stage0)] + fn each(&self, f: &fn(&uint, &'self T) -> bool) -> bool { + for uint::range(0, self.children.len()) |idx| { + match self.children[idx] { + Internal(ref x) => if !x.each(f) { return false }, + External(k, ref v) => if !f(&k, v) { return false }, + Nothing => () + } + } + true + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range(0, self.children.len()) |idx| { match self.children[idx] { Internal(ref x) => if !x.each(f) { return false }, - External(k, ref v) => if !f(&(k, v)) { return false }, + External(k, ref v) => if !f(&k, v) { return false }, + Nothing => () + } + } + true + } + + #[cfg(stage0)] + fn each_reverse(&self, f: &fn(&uint, &'self T) -> bool) -> bool { + for uint::range_rev(self.children.len(), 0) |idx| { + match self.children[idx - 1] { + Internal(ref x) => if !x.each_reverse(f) { return false }, + External(k, ref v) => if !f(&k, v) { return false }, Nothing => () } } true } - fn each_reverse(&self, f: &fn(&(uint, &'self T)) -> bool) -> bool { + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range_rev(self.children.len(), 0) |idx| { match self.children[idx - 1] { Internal(ref x) => if !x.each_reverse(f) { return false }, - External(k, ref v) => if !f(&(k, v)) { return false }, + External(k, ref v) => if !f(&k, v) { return false }, Nothing => () } } true } - fn mutate_values(&mut self, f: &fn(&uint, &mut T) -> bool) -> bool { + fn mutate_values<'a>(&'a mut self, f: &fn(&uint, &mut T) -> bool) -> bool { for vec::each_mut(self.children) |child| { match *child { Internal(ref mut x) => if !x.mutate_values(f) { @@ -438,8 +527,8 @@ mod tests { assert!(m.insert(1, 2)); let mut n = 0; - for m.each |&(k, v)| { - assert!(k == n); + for m.each |k, v| { + assert!(*k == n); assert!(*v == n * 2); n += 1; } @@ -454,11 +543,11 @@ mod tests { } let mut n = uint::max_value - 9999; - for m.each |&(k, v)| { + for m.each |k, v| { if n == uint::max_value - 5000 { break } assert!(n < uint::max_value - 5000); - assert!(k == n); + assert!(*k == n); assert!(*v == n / 2); n += 1; } @@ -475,8 +564,8 @@ mod tests { assert!(m.insert(1, 2)); let mut n = 4; - for m.each_reverse |&(k, v)| { - assert!(k == n); + for m.each_reverse |k, v| { + assert!(*k == n); assert!(*v == n * 2); n -= 1; } @@ -491,11 +580,11 @@ mod tests { } let mut n = uint::max_value; - for m.each_reverse |&(k, v)| { + for m.each_reverse |k, v| { if n == uint::max_value - 5000 { break } assert!(n > uint::max_value - 5000); - assert!(k == n); + assert!(*k == n); assert!(*v == n / 2); n -= 1; } diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index a5c86d592c636..8e908435f3543 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -10,6 +10,7 @@ //! Operations on tuples +use clone::Clone; use kinds::Copy; use vec; @@ -46,11 +47,22 @@ impl CopyableTuple for (T, U) { } +impl Clone for (T, U) { + fn clone(&self) -> (T, U) { + let (a, b) = match *self { + (ref a, ref b) => (a, b) + }; + (a.clone(), b.clone()) + } +} + +#[cfg(stage0)] pub trait ImmutableTuple { fn first_ref(&self) -> &'self T; fn second_ref(&self) -> &'self U; } +#[cfg(stage0)] impl ImmutableTuple for (T, U) { #[inline(always)] fn first_ref(&self) -> &'self T { @@ -66,6 +78,32 @@ impl ImmutableTuple for (T, U) { } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub trait ImmutableTuple { + fn first_ref<'a>(&'a self) -> &'a T; + fn second_ref<'a>(&'a self) -> &'a U; +} + +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +impl ImmutableTuple for (T, U) { + #[inline(always)] + fn first_ref<'a>(&'a self) -> &'a T { + match *self { + (ref t, _) => t, + } + } + #[inline(always)] + fn second_ref<'a>(&'a self) -> &'a U { + match *self { + (_, ref u) => u, + } + } +} + pub trait ExtendedTupleOps { fn zip(&self) -> ~[(A, B)]; fn map(&self, f: &fn(a: &A, b: &B) -> C) -> ~[C]; @@ -151,7 +189,6 @@ impl Ord for (A,) { fn gt(&self, other: &(A,)) -> bool { other.lt(&(*self)) } } - #[cfg(notest)] impl Eq for (A, B) { #[inline(always)] @@ -252,3 +289,10 @@ fn test_tuple() { assert!(('a', 2).swap() == (2, 'a')); } +#[test] +fn test_clone() { + let a = (1, ~"2"); + let b = a.clone(); + assert!(a.first() == b.first()); + assert!(a.second() == b.second()); +} diff --git a/src/libcore/unicode.rs b/src/libcore/unicode.rs index 9f2ab66d5c207..a13d66c48ee0c 100644 --- a/src/libcore/unicode.rs +++ b/src/libcore/unicode.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -11,4680 +11,2633 @@ #[doc(hidden)]; // FIXME #3538 pub mod general_category { + + fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { + use cmp::{Equal, Less, Greater}; + use vec::bsearch; + use option::None; + (do bsearch(r) |&(lo,hi)| { + if lo <= c && c <= hi { Equal } + else if hi < c { Less } + else { Greater } + }) != None + } + + + static Cc_table : &'static [(char,char)] = &[ + ('\x00', '\x1f'), ('\x7f', '\x9f') + ]; + pub fn Cc(c: char) -> bool { - return match c { - '\x00' .. '\x1f' - | '\x7f' .. '\x9f' => true, - _ => false - }; + bsearch_range_table(c, Cc_table) } + static Cf_table : &'static [(char,char)] = &[ + ('\xad', '\xad'), ('\u0600', '\u0604'), + ('\u06dd', '\u06dd'), ('\u070f', '\u070f'), + ('\u200b', '\u200f'), ('\u202a', '\u202e'), + ('\u2060', '\u206f'), ('\ufeff', '\ufeff'), + ('\ufff9', '\ufffb'), ('\U000110bd', '\U000110bd'), + ('\U0001d173', '\U0001d17a'), ('\U000e0001', '\U000e007f') + ]; + pub fn Cf(c: char) -> bool { - return match c { - '\xad' - | '\u0600' .. '\u0603' - | '\u06dd' - | '\u070f' - | '\u17b4' .. '\u17b5' - | '\u200b' .. '\u200f' - | '\u202a' .. '\u202e' - | '\u2060' .. '\u206f' - | '\ufeff' - | '\ufff9' .. '\ufffb' - | '\U000110bd' - | '\U0001d173' .. '\U0001d17a' - | '\U000e0001' .. '\U000e007f' => true, - _ => false - }; + bsearch_range_table(c, Cf_table) } + static Co_table : &'static [(char,char)] = &[ + ('\ue000', '\uf8ff') + ]; + pub fn Co(c: char) -> bool { - return match c { - '\ue000' .. '\uf8ff' => true, - _ => false - }; + bsearch_range_table(c, Co_table) } + static Cs_table : &'static [(char,char)] = &[ + ('\ud800', '\udfff') + ]; + pub fn Cs(c: char) -> bool { - return match c { - '\ud800' .. '\udfff' => true, - _ => false - }; + bsearch_range_table(c, Cs_table) } + static Ll_table : &'static [(char,char)] = &[ + ('\x61', '\x7a'), ('\xb5', '\xb5'), + ('\xdf', '\xf6'), ('\xf8', '\xff'), + ('\u0101', '\u0101'), ('\u0103', '\u0103'), + ('\u0105', '\u0105'), ('\u0107', '\u0107'), + ('\u0109', '\u0109'), ('\u010b', '\u010b'), + ('\u010d', '\u010d'), ('\u010f', '\u010f'), + ('\u0111', '\u0111'), ('\u0113', '\u0113'), + ('\u0115', '\u0115'), ('\u0117', '\u0117'), + ('\u0119', '\u0119'), ('\u011b', '\u011b'), + ('\u011d', '\u011d'), ('\u011f', '\u011f'), + ('\u0121', '\u0121'), ('\u0123', '\u0123'), + ('\u0125', '\u0125'), ('\u0127', '\u0127'), + ('\u0129', '\u0129'), ('\u012b', '\u012b'), + ('\u012d', '\u012d'), ('\u012f', '\u012f'), + ('\u0131', '\u0131'), ('\u0133', '\u0133'), + ('\u0135', '\u0135'), ('\u0137', '\u0138'), + ('\u013a', '\u013a'), ('\u013c', '\u013c'), + ('\u013e', '\u013e'), ('\u0140', '\u0140'), + ('\u0142', '\u0142'), ('\u0144', '\u0144'), + ('\u0146', '\u0146'), ('\u0148', '\u0149'), + ('\u014b', '\u014b'), ('\u014d', '\u014d'), + ('\u014f', '\u014f'), ('\u0151', '\u0151'), + ('\u0153', '\u0153'), ('\u0155', '\u0155'), + ('\u0157', '\u0157'), ('\u0159', '\u0159'), + ('\u015b', '\u015b'), ('\u015d', '\u015d'), + ('\u015f', '\u015f'), ('\u0161', '\u0161'), + ('\u0163', '\u0163'), ('\u0165', '\u0165'), + ('\u0167', '\u0167'), ('\u0169', '\u0169'), + ('\u016b', '\u016b'), ('\u016d', '\u016d'), + ('\u016f', '\u016f'), ('\u0171', '\u0171'), + ('\u0173', '\u0173'), ('\u0175', '\u0175'), + ('\u0177', '\u0177'), ('\u017a', '\u017a'), + ('\u017c', '\u017c'), ('\u017e', '\u0180'), + ('\u0183', '\u0183'), ('\u0185', '\u0185'), + ('\u0188', '\u0188'), ('\u018c', '\u018d'), + ('\u0192', '\u0192'), ('\u0195', '\u0195'), + ('\u0199', '\u019b'), ('\u019e', '\u019e'), + ('\u01a1', '\u01a1'), ('\u01a3', '\u01a3'), + ('\u01a5', '\u01a5'), ('\u01a8', '\u01a8'), + ('\u01aa', '\u01ab'), ('\u01ad', '\u01ad'), + ('\u01b0', '\u01b0'), ('\u01b4', '\u01b4'), + ('\u01b6', '\u01b6'), ('\u01b9', '\u01ba'), + ('\u01bd', '\u01bf'), ('\u01c6', '\u01c6'), + ('\u01c9', '\u01c9'), ('\u01cc', '\u01cc'), + ('\u01ce', '\u01ce'), ('\u01d0', '\u01d0'), + ('\u01d2', '\u01d2'), ('\u01d4', '\u01d4'), + ('\u01d6', '\u01d6'), ('\u01d8', '\u01d8'), + ('\u01da', '\u01da'), ('\u01dc', '\u01dd'), + ('\u01df', '\u01df'), ('\u01e1', '\u01e1'), + ('\u01e3', '\u01e3'), ('\u01e5', '\u01e5'), + ('\u01e7', '\u01e7'), ('\u01e9', '\u01e9'), + ('\u01eb', '\u01eb'), ('\u01ed', '\u01ed'), + ('\u01ef', '\u01f0'), ('\u01f3', '\u01f3'), + ('\u01f5', '\u01f5'), ('\u01f9', '\u01f9'), + ('\u01fb', '\u01fb'), ('\u01fd', '\u01fd'), + ('\u01ff', '\u01ff'), ('\u0201', '\u0201'), + ('\u0203', '\u0203'), ('\u0205', '\u0205'), + ('\u0207', '\u0207'), ('\u0209', '\u0209'), + ('\u020b', '\u020b'), ('\u020d', '\u020d'), + ('\u020f', '\u020f'), ('\u0211', '\u0211'), + ('\u0213', '\u0213'), ('\u0215', '\u0215'), + ('\u0217', '\u0217'), ('\u0219', '\u0219'), + ('\u021b', '\u021b'), ('\u021d', '\u021d'), + ('\u021f', '\u021f'), ('\u0221', '\u0221'), + ('\u0223', '\u0223'), ('\u0225', '\u0225'), + ('\u0227', '\u0227'), ('\u0229', '\u0229'), + ('\u022b', '\u022b'), ('\u022d', '\u022d'), + ('\u022f', '\u022f'), ('\u0231', '\u0231'), + ('\u0233', '\u0239'), ('\u023c', '\u023c'), + ('\u023f', '\u0240'), ('\u0242', '\u0242'), + ('\u0247', '\u0247'), ('\u0249', '\u0249'), + ('\u024b', '\u024b'), ('\u024d', '\u024d'), + ('\u024f', '\u0293'), ('\u0295', '\u02af'), + ('\u0371', '\u0371'), ('\u0373', '\u0373'), + ('\u0377', '\u0377'), ('\u037b', '\u037d'), + ('\u0390', '\u0390'), ('\u03ac', '\u03ce'), + ('\u03d0', '\u03d1'), ('\u03d5', '\u03d7'), + ('\u03d9', '\u03d9'), ('\u03db', '\u03db'), + ('\u03dd', '\u03dd'), ('\u03df', '\u03df'), + ('\u03e1', '\u03e1'), ('\u03e3', '\u03e3'), + ('\u03e5', '\u03e5'), ('\u03e7', '\u03e7'), + ('\u03e9', '\u03e9'), ('\u03eb', '\u03eb'), + ('\u03ed', '\u03ed'), ('\u03ef', '\u03f3'), + ('\u03f5', '\u03f5'), ('\u03f8', '\u03f8'), + ('\u03fb', '\u03fc'), ('\u0430', '\u045f'), + ('\u0461', '\u0461'), ('\u0463', '\u0463'), + ('\u0465', '\u0465'), ('\u0467', '\u0467'), + ('\u0469', '\u0469'), ('\u046b', '\u046b'), + ('\u046d', '\u046d'), ('\u046f', '\u046f'), + ('\u0471', '\u0471'), ('\u0473', '\u0473'), + ('\u0475', '\u0475'), ('\u0477', '\u0477'), + ('\u0479', '\u0479'), ('\u047b', '\u047b'), + ('\u047d', '\u047d'), ('\u047f', '\u047f'), + ('\u0481', '\u0481'), ('\u048b', '\u048b'), + ('\u048d', '\u048d'), ('\u048f', '\u048f'), + ('\u0491', '\u0491'), ('\u0493', '\u0493'), + ('\u0495', '\u0495'), ('\u0497', '\u0497'), + ('\u0499', '\u0499'), ('\u049b', '\u049b'), + ('\u049d', '\u049d'), ('\u049f', '\u049f'), + ('\u04a1', '\u04a1'), ('\u04a3', '\u04a3'), + ('\u04a5', '\u04a5'), ('\u04a7', '\u04a7'), + ('\u04a9', '\u04a9'), ('\u04ab', '\u04ab'), + ('\u04ad', '\u04ad'), ('\u04af', '\u04af'), + ('\u04b1', '\u04b1'), ('\u04b3', '\u04b3'), + ('\u04b5', '\u04b5'), ('\u04b7', '\u04b7'), + ('\u04b9', '\u04b9'), ('\u04bb', '\u04bb'), + ('\u04bd', '\u04bd'), ('\u04bf', '\u04bf'), + ('\u04c2', '\u04c2'), ('\u04c4', '\u04c4'), + ('\u04c6', '\u04c6'), ('\u04c8', '\u04c8'), + ('\u04ca', '\u04ca'), ('\u04cc', '\u04cc'), + ('\u04ce', '\u04cf'), ('\u04d1', '\u04d1'), + ('\u04d3', '\u04d3'), ('\u04d5', '\u04d5'), + ('\u04d7', '\u04d7'), ('\u04d9', '\u04d9'), + ('\u04db', '\u04db'), ('\u04dd', '\u04dd'), + ('\u04df', '\u04df'), ('\u04e1', '\u04e1'), + ('\u04e3', '\u04e3'), ('\u04e5', '\u04e5'), + ('\u04e7', '\u04e7'), ('\u04e9', '\u04e9'), + ('\u04eb', '\u04eb'), ('\u04ed', '\u04ed'), + ('\u04ef', '\u04ef'), ('\u04f1', '\u04f1'), + ('\u04f3', '\u04f3'), ('\u04f5', '\u04f5'), + ('\u04f7', '\u04f7'), ('\u04f9', '\u04f9'), + ('\u04fb', '\u04fb'), ('\u04fd', '\u04fd'), + ('\u04ff', '\u04ff'), ('\u0501', '\u0501'), + ('\u0503', '\u0503'), ('\u0505', '\u0505'), + ('\u0507', '\u0507'), ('\u0509', '\u0509'), + ('\u050b', '\u050b'), ('\u050d', '\u050d'), + ('\u050f', '\u050f'), ('\u0511', '\u0511'), + ('\u0513', '\u0513'), ('\u0515', '\u0515'), + ('\u0517', '\u0517'), ('\u0519', '\u0519'), + ('\u051b', '\u051b'), ('\u051d', '\u051d'), + ('\u051f', '\u051f'), ('\u0521', '\u0521'), + ('\u0523', '\u0523'), ('\u0525', '\u0525'), + ('\u0527', '\u0527'), ('\u0561', '\u0587'), + ('\u1d00', '\u1d2b'), ('\u1d6b', '\u1d77'), + ('\u1d79', '\u1d9a'), ('\u1e01', '\u1e01'), + ('\u1e03', '\u1e03'), ('\u1e05', '\u1e05'), + ('\u1e07', '\u1e07'), ('\u1e09', '\u1e09'), + ('\u1e0b', '\u1e0b'), ('\u1e0d', '\u1e0d'), + ('\u1e0f', '\u1e0f'), ('\u1e11', '\u1e11'), + ('\u1e13', '\u1e13'), ('\u1e15', '\u1e15'), + ('\u1e17', '\u1e17'), ('\u1e19', '\u1e19'), + ('\u1e1b', '\u1e1b'), ('\u1e1d', '\u1e1d'), + ('\u1e1f', '\u1e1f'), ('\u1e21', '\u1e21'), + ('\u1e23', '\u1e23'), ('\u1e25', '\u1e25'), + ('\u1e27', '\u1e27'), ('\u1e29', '\u1e29'), + ('\u1e2b', '\u1e2b'), ('\u1e2d', '\u1e2d'), + ('\u1e2f', '\u1e2f'), ('\u1e31', '\u1e31'), + ('\u1e33', '\u1e33'), ('\u1e35', '\u1e35'), + ('\u1e37', '\u1e37'), ('\u1e39', '\u1e39'), + ('\u1e3b', '\u1e3b'), ('\u1e3d', '\u1e3d'), + ('\u1e3f', '\u1e3f'), ('\u1e41', '\u1e41'), + ('\u1e43', '\u1e43'), ('\u1e45', '\u1e45'), + ('\u1e47', '\u1e47'), ('\u1e49', '\u1e49'), + ('\u1e4b', '\u1e4b'), ('\u1e4d', '\u1e4d'), + ('\u1e4f', '\u1e4f'), ('\u1e51', '\u1e51'), + ('\u1e53', '\u1e53'), ('\u1e55', '\u1e55'), + ('\u1e57', '\u1e57'), ('\u1e59', '\u1e59'), + ('\u1e5b', '\u1e5b'), ('\u1e5d', '\u1e5d'), + ('\u1e5f', '\u1e5f'), ('\u1e61', '\u1e61'), + ('\u1e63', '\u1e63'), ('\u1e65', '\u1e65'), + ('\u1e67', '\u1e67'), ('\u1e69', '\u1e69'), + ('\u1e6b', '\u1e6b'), ('\u1e6d', '\u1e6d'), + ('\u1e6f', '\u1e6f'), ('\u1e71', '\u1e71'), + ('\u1e73', '\u1e73'), ('\u1e75', '\u1e75'), + ('\u1e77', '\u1e77'), ('\u1e79', '\u1e79'), + ('\u1e7b', '\u1e7b'), ('\u1e7d', '\u1e7d'), + ('\u1e7f', '\u1e7f'), ('\u1e81', '\u1e81'), + ('\u1e83', '\u1e83'), ('\u1e85', '\u1e85'), + ('\u1e87', '\u1e87'), ('\u1e89', '\u1e89'), + ('\u1e8b', '\u1e8b'), ('\u1e8d', '\u1e8d'), + ('\u1e8f', '\u1e8f'), ('\u1e91', '\u1e91'), + ('\u1e93', '\u1e93'), ('\u1e95', '\u1e9d'), + ('\u1e9f', '\u1e9f'), ('\u1ea1', '\u1ea1'), + ('\u1ea3', '\u1ea3'), ('\u1ea5', '\u1ea5'), + ('\u1ea7', '\u1ea7'), ('\u1ea9', '\u1ea9'), + ('\u1eab', '\u1eab'), ('\u1ead', '\u1ead'), + ('\u1eaf', '\u1eaf'), ('\u1eb1', '\u1eb1'), + ('\u1eb3', '\u1eb3'), ('\u1eb5', '\u1eb5'), + ('\u1eb7', '\u1eb7'), ('\u1eb9', '\u1eb9'), + ('\u1ebb', '\u1ebb'), ('\u1ebd', '\u1ebd'), + ('\u1ebf', '\u1ebf'), ('\u1ec1', '\u1ec1'), + ('\u1ec3', '\u1ec3'), ('\u1ec5', '\u1ec5'), + ('\u1ec7', '\u1ec7'), ('\u1ec9', '\u1ec9'), + ('\u1ecb', '\u1ecb'), ('\u1ecd', '\u1ecd'), + ('\u1ecf', '\u1ecf'), ('\u1ed1', '\u1ed1'), + ('\u1ed3', '\u1ed3'), ('\u1ed5', '\u1ed5'), + ('\u1ed7', '\u1ed7'), ('\u1ed9', '\u1ed9'), + ('\u1edb', '\u1edb'), ('\u1edd', '\u1edd'), + ('\u1edf', '\u1edf'), ('\u1ee1', '\u1ee1'), + ('\u1ee3', '\u1ee3'), ('\u1ee5', '\u1ee5'), + ('\u1ee7', '\u1ee7'), ('\u1ee9', '\u1ee9'), + ('\u1eeb', '\u1eeb'), ('\u1eed', '\u1eed'), + ('\u1eef', '\u1eef'), ('\u1ef1', '\u1ef1'), + ('\u1ef3', '\u1ef3'), ('\u1ef5', '\u1ef5'), + ('\u1ef7', '\u1ef7'), ('\u1ef9', '\u1ef9'), + ('\u1efb', '\u1efb'), ('\u1efd', '\u1efd'), + ('\u1eff', '\u1f07'), ('\u1f10', '\u1f15'), + ('\u1f20', '\u1f27'), ('\u1f30', '\u1f37'), + ('\u1f40', '\u1f45'), ('\u1f50', '\u1f57'), + ('\u1f60', '\u1f67'), ('\u1f70', '\u1f87'), + ('\u1f90', '\u1f97'), ('\u1fa0', '\u1fa7'), + ('\u1fb0', '\u1fb7'), ('\u1fbe', '\u1fbe'), + ('\u1fc2', '\u1fc7'), ('\u1fd0', '\u1fd7'), + ('\u1fe0', '\u1fe7'), ('\u1ff2', '\u1ff7'), + ('\u210a', '\u210a'), ('\u210e', '\u210f'), + ('\u2113', '\u2113'), ('\u212f', '\u212f'), + ('\u2134', '\u2134'), ('\u2139', '\u2139'), + ('\u213c', '\u213d'), ('\u2146', '\u2149'), + ('\u214e', '\u214e'), ('\u2184', '\u2184'), + ('\u2c30', '\u2c5e'), ('\u2c61', '\u2c61'), + ('\u2c65', '\u2c66'), ('\u2c68', '\u2c68'), + ('\u2c6a', '\u2c6a'), ('\u2c6c', '\u2c6c'), + ('\u2c71', '\u2c71'), ('\u2c73', '\u2c74'), + ('\u2c76', '\u2c7b'), ('\u2c81', '\u2c81'), + ('\u2c83', '\u2c83'), ('\u2c85', '\u2c85'), + ('\u2c87', '\u2c87'), ('\u2c89', '\u2c89'), + ('\u2c8b', '\u2c8b'), ('\u2c8d', '\u2c8d'), + ('\u2c8f', '\u2c8f'), ('\u2c91', '\u2c91'), + ('\u2c93', '\u2c93'), ('\u2c95', '\u2c95'), + ('\u2c97', '\u2c97'), ('\u2c99', '\u2c99'), + ('\u2c9b', '\u2c9b'), ('\u2c9d', '\u2c9d'), + ('\u2c9f', '\u2c9f'), ('\u2ca1', '\u2ca1'), + ('\u2ca3', '\u2ca3'), ('\u2ca5', '\u2ca5'), + ('\u2ca7', '\u2ca7'), ('\u2ca9', '\u2ca9'), + ('\u2cab', '\u2cab'), ('\u2cad', '\u2cad'), + ('\u2caf', '\u2caf'), ('\u2cb1', '\u2cb1'), + ('\u2cb3', '\u2cb3'), ('\u2cb5', '\u2cb5'), + ('\u2cb7', '\u2cb7'), ('\u2cb9', '\u2cb9'), + ('\u2cbb', '\u2cbb'), ('\u2cbd', '\u2cbd'), + ('\u2cbf', '\u2cbf'), ('\u2cc1', '\u2cc1'), + ('\u2cc3', '\u2cc3'), ('\u2cc5', '\u2cc5'), + ('\u2cc7', '\u2cc7'), ('\u2cc9', '\u2cc9'), + ('\u2ccb', '\u2ccb'), ('\u2ccd', '\u2ccd'), + ('\u2ccf', '\u2ccf'), ('\u2cd1', '\u2cd1'), + ('\u2cd3', '\u2cd3'), ('\u2cd5', '\u2cd5'), + ('\u2cd7', '\u2cd7'), ('\u2cd9', '\u2cd9'), + ('\u2cdb', '\u2cdb'), ('\u2cdd', '\u2cdd'), + ('\u2cdf', '\u2cdf'), ('\u2ce1', '\u2ce1'), + ('\u2ce3', '\u2ce4'), ('\u2cec', '\u2cec'), + ('\u2cee', '\u2cee'), ('\u2cf3', '\u2cf3'), + ('\u2d00', '\u2d2d'), ('\ua641', '\ua641'), + ('\ua643', '\ua643'), ('\ua645', '\ua645'), + ('\ua647', '\ua647'), ('\ua649', '\ua649'), + ('\ua64b', '\ua64b'), ('\ua64d', '\ua64d'), + ('\ua64f', '\ua64f'), ('\ua651', '\ua651'), + ('\ua653', '\ua653'), ('\ua655', '\ua655'), + ('\ua657', '\ua657'), ('\ua659', '\ua659'), + ('\ua65b', '\ua65b'), ('\ua65d', '\ua65d'), + ('\ua65f', '\ua65f'), ('\ua661', '\ua661'), + ('\ua663', '\ua663'), ('\ua665', '\ua665'), + ('\ua667', '\ua667'), ('\ua669', '\ua669'), + ('\ua66b', '\ua66b'), ('\ua66d', '\ua66d'), + ('\ua681', '\ua681'), ('\ua683', '\ua683'), + ('\ua685', '\ua685'), ('\ua687', '\ua687'), + ('\ua689', '\ua689'), ('\ua68b', '\ua68b'), + ('\ua68d', '\ua68d'), ('\ua68f', '\ua68f'), + ('\ua691', '\ua691'), ('\ua693', '\ua693'), + ('\ua695', '\ua695'), ('\ua697', '\ua697'), + ('\ua723', '\ua723'), ('\ua725', '\ua725'), + ('\ua727', '\ua727'), ('\ua729', '\ua729'), + ('\ua72b', '\ua72b'), ('\ua72d', '\ua72d'), + ('\ua72f', '\ua731'), ('\ua733', '\ua733'), + ('\ua735', '\ua735'), ('\ua737', '\ua737'), + ('\ua739', '\ua739'), ('\ua73b', '\ua73b'), + ('\ua73d', '\ua73d'), ('\ua73f', '\ua73f'), + ('\ua741', '\ua741'), ('\ua743', '\ua743'), + ('\ua745', '\ua745'), ('\ua747', '\ua747'), + ('\ua749', '\ua749'), ('\ua74b', '\ua74b'), + ('\ua74d', '\ua74d'), ('\ua74f', '\ua74f'), + ('\ua751', '\ua751'), ('\ua753', '\ua753'), + ('\ua755', '\ua755'), ('\ua757', '\ua757'), + ('\ua759', '\ua759'), ('\ua75b', '\ua75b'), + ('\ua75d', '\ua75d'), ('\ua75f', '\ua75f'), + ('\ua761', '\ua761'), ('\ua763', '\ua763'), + ('\ua765', '\ua765'), ('\ua767', '\ua767'), + ('\ua769', '\ua769'), ('\ua76b', '\ua76b'), + ('\ua76d', '\ua76d'), ('\ua76f', '\ua76f'), + ('\ua771', '\ua778'), ('\ua77a', '\ua77a'), + ('\ua77c', '\ua77c'), ('\ua77f', '\ua77f'), + ('\ua781', '\ua781'), ('\ua783', '\ua783'), + ('\ua785', '\ua785'), ('\ua787', '\ua787'), + ('\ua78c', '\ua78c'), ('\ua78e', '\ua78e'), + ('\ua791', '\ua791'), ('\ua793', '\ua793'), + ('\ua7a1', '\ua7a1'), ('\ua7a3', '\ua7a3'), + ('\ua7a5', '\ua7a5'), ('\ua7a7', '\ua7a7'), + ('\ua7a9', '\ua7a9'), ('\ua7fa', '\ua7fa'), + ('\ufb00', '\ufb17'), ('\uff41', '\uff5a'), + ('\U00010428', '\U0001044f'), ('\U0001d41a', '\U0001d433'), + ('\U0001d44e', '\U0001d467'), ('\U0001d482', '\U0001d49b'), + ('\U0001d4b6', '\U0001d4cf'), ('\U0001d4ea', '\U0001d503'), + ('\U0001d51e', '\U0001d537'), ('\U0001d552', '\U0001d56b'), + ('\U0001d586', '\U0001d59f'), ('\U0001d5ba', '\U0001d5d3'), + ('\U0001d5ee', '\U0001d607'), ('\U0001d622', '\U0001d63b'), + ('\U0001d656', '\U0001d66f'), ('\U0001d68a', '\U0001d6a5'), + ('\U0001d6c2', '\U0001d6da'), ('\U0001d6dc', '\U0001d6e1'), + ('\U0001d6fc', '\U0001d714'), ('\U0001d716', '\U0001d71b'), + ('\U0001d736', '\U0001d74e'), ('\U0001d750', '\U0001d755'), + ('\U0001d770', '\U0001d788'), ('\U0001d78a', '\U0001d78f'), + ('\U0001d7aa', '\U0001d7c2'), ('\U0001d7c4', '\U0001d7c9'), + ('\U0001d7cb', '\U0001d7cb') + ]; + pub fn Ll(c: char) -> bool { - return match c { - '\x61' .. '\x7a' - | '\xaa' - | '\xb5' - | '\xba' - | '\xdf' .. '\xf6' - | '\xf8' .. '\xff' - | '\u0101' - | '\u0103' - | '\u0105' - | '\u0107' - | '\u0109' - | '\u010b' - | '\u010d' - | '\u010f' - | '\u0111' - | '\u0113' - | '\u0115' - | '\u0117' - | '\u0119' - | '\u011b' - | '\u011d' - | '\u011f' - | '\u0121' - | '\u0123' - | '\u0125' - | '\u0127' - | '\u0129' - | '\u012b' - | '\u012d' - | '\u012f' - | '\u0131' - | '\u0133' - | '\u0135' - | '\u0137' .. '\u0138' - | '\u013a' - | '\u013c' - | '\u013e' - | '\u0140' - | '\u0142' - | '\u0144' - | '\u0146' - | '\u0148' .. '\u0149' - | '\u014b' - | '\u014d' - | '\u014f' - | '\u0151' - | '\u0153' - | '\u0155' - | '\u0157' - | '\u0159' - | '\u015b' - | '\u015d' - | '\u015f' - | '\u0161' - | '\u0163' - | '\u0165' - | '\u0167' - | '\u0169' - | '\u016b' - | '\u016d' - | '\u016f' - | '\u0171' - | '\u0173' - | '\u0175' - | '\u0177' - | '\u017a' - | '\u017c' - | '\u017e' .. '\u0180' - | '\u0183' - | '\u0185' - | '\u0188' - | '\u018c' .. '\u018d' - | '\u0192' - | '\u0195' - | '\u0199' .. '\u019b' - | '\u019e' - | '\u01a1' - | '\u01a3' - | '\u01a5' - | '\u01a8' - | '\u01aa' .. '\u01ab' - | '\u01ad' - | '\u01b0' - | '\u01b4' - | '\u01b6' - | '\u01b9' .. '\u01ba' - | '\u01bd' .. '\u01bf' - | '\u01c6' - | '\u01c9' - | '\u01cc' - | '\u01ce' - | '\u01d0' - | '\u01d2' - | '\u01d4' - | '\u01d6' - | '\u01d8' - | '\u01da' - | '\u01dc' .. '\u01dd' - | '\u01df' - | '\u01e1' - | '\u01e3' - | '\u01e5' - | '\u01e7' - | '\u01e9' - | '\u01eb' - | '\u01ed' - | '\u01ef' .. '\u01f0' - | '\u01f3' - | '\u01f5' - | '\u01f9' - | '\u01fb' - | '\u01fd' - | '\u01ff' - | '\u0201' - | '\u0203' - | '\u0205' - | '\u0207' - | '\u0209' - | '\u020b' - | '\u020d' - | '\u020f' - | '\u0211' - | '\u0213' - | '\u0215' - | '\u0217' - | '\u0219' - | '\u021b' - | '\u021d' - | '\u021f' - | '\u0221' - | '\u0223' - | '\u0225' - | '\u0227' - | '\u0229' - | '\u022b' - | '\u022d' - | '\u022f' - | '\u0231' - | '\u0233' .. '\u0239' - | '\u023c' - | '\u023f' .. '\u0240' - | '\u0242' - | '\u0247' - | '\u0249' - | '\u024b' - | '\u024d' - | '\u024f' .. '\u0293' - | '\u0295' .. '\u02af' - | '\u0371' - | '\u0373' - | '\u0377' - | '\u037b' .. '\u037d' - | '\u0390' - | '\u03ac' .. '\u03ce' - | '\u03d0' .. '\u03d1' - | '\u03d5' .. '\u03d7' - | '\u03d9' - | '\u03db' - | '\u03dd' - | '\u03df' - | '\u03e1' - | '\u03e3' - | '\u03e5' - | '\u03e7' - | '\u03e9' - | '\u03eb' - | '\u03ed' - | '\u03ef' .. '\u03f3' - | '\u03f5' - | '\u03f8' - | '\u03fb' .. '\u03fc' - | '\u0430' .. '\u045f' - | '\u0461' - | '\u0463' - | '\u0465' - | '\u0467' - | '\u0469' - | '\u046b' - | '\u046d' - | '\u046f' - | '\u0471' - | '\u0473' - | '\u0475' - | '\u0477' - | '\u0479' - | '\u047b' - | '\u047d' - | '\u047f' - | '\u0481' - | '\u048b' - | '\u048d' - | '\u048f' - | '\u0491' - | '\u0493' - | '\u0495' - | '\u0497' - | '\u0499' - | '\u049b' - | '\u049d' - | '\u049f' - | '\u04a1' - | '\u04a3' - | '\u04a5' - | '\u04a7' - | '\u04a9' - | '\u04ab' - | '\u04ad' - | '\u04af' - | '\u04b1' - | '\u04b3' - | '\u04b5' - | '\u04b7' - | '\u04b9' - | '\u04bb' - | '\u04bd' - | '\u04bf' - | '\u04c2' - | '\u04c4' - | '\u04c6' - | '\u04c8' - | '\u04ca' - | '\u04cc' - | '\u04ce' .. '\u04cf' - | '\u04d1' - | '\u04d3' - | '\u04d5' - | '\u04d7' - | '\u04d9' - | '\u04db' - | '\u04dd' - | '\u04df' - | '\u04e1' - | '\u04e3' - | '\u04e5' - | '\u04e7' - | '\u04e9' - | '\u04eb' - | '\u04ed' - | '\u04ef' - | '\u04f1' - | '\u04f3' - | '\u04f5' - | '\u04f7' - | '\u04f9' - | '\u04fb' - | '\u04fd' - | '\u04ff' - | '\u0501' - | '\u0503' - | '\u0505' - | '\u0507' - | '\u0509' - | '\u050b' - | '\u050d' - | '\u050f' - | '\u0511' - | '\u0513' - | '\u0515' - | '\u0517' - | '\u0519' - | '\u051b' - | '\u051d' - | '\u051f' - | '\u0521' - | '\u0523' - | '\u0525' - | '\u0527' - | '\u0561' .. '\u0587' - | '\u1d00' .. '\u1d2b' - | '\u1d62' .. '\u1d77' - | '\u1d79' .. '\u1d9a' - | '\u1e01' - | '\u1e03' - | '\u1e05' - | '\u1e07' - | '\u1e09' - | '\u1e0b' - | '\u1e0d' - | '\u1e0f' - | '\u1e11' - | '\u1e13' - | '\u1e15' - | '\u1e17' - | '\u1e19' - | '\u1e1b' - | '\u1e1d' - | '\u1e1f' - | '\u1e21' - | '\u1e23' - | '\u1e25' - | '\u1e27' - | '\u1e29' - | '\u1e2b' - | '\u1e2d' - | '\u1e2f' - | '\u1e31' - | '\u1e33' - | '\u1e35' - | '\u1e37' - | '\u1e39' - | '\u1e3b' - | '\u1e3d' - | '\u1e3f' - | '\u1e41' - | '\u1e43' - | '\u1e45' - | '\u1e47' - | '\u1e49' - | '\u1e4b' - | '\u1e4d' - | '\u1e4f' - | '\u1e51' - | '\u1e53' - | '\u1e55' - | '\u1e57' - | '\u1e59' - | '\u1e5b' - | '\u1e5d' - | '\u1e5f' - | '\u1e61' - | '\u1e63' - | '\u1e65' - | '\u1e67' - | '\u1e69' - | '\u1e6b' - | '\u1e6d' - | '\u1e6f' - | '\u1e71' - | '\u1e73' - | '\u1e75' - | '\u1e77' - | '\u1e79' - | '\u1e7b' - | '\u1e7d' - | '\u1e7f' - | '\u1e81' - | '\u1e83' - | '\u1e85' - | '\u1e87' - | '\u1e89' - | '\u1e8b' - | '\u1e8d' - | '\u1e8f' - | '\u1e91' - | '\u1e93' - | '\u1e95' .. '\u1e9d' - | '\u1e9f' - | '\u1ea1' - | '\u1ea3' - | '\u1ea5' - | '\u1ea7' - | '\u1ea9' - | '\u1eab' - | '\u1ead' - | '\u1eaf' - | '\u1eb1' - | '\u1eb3' - | '\u1eb5' - | '\u1eb7' - | '\u1eb9' - | '\u1ebb' - | '\u1ebd' - | '\u1ebf' - | '\u1ec1' - | '\u1ec3' - | '\u1ec5' - | '\u1ec7' - | '\u1ec9' - | '\u1ecb' - | '\u1ecd' - | '\u1ecf' - | '\u1ed1' - | '\u1ed3' - | '\u1ed5' - | '\u1ed7' - | '\u1ed9' - | '\u1edb' - | '\u1edd' - | '\u1edf' - | '\u1ee1' - | '\u1ee3' - | '\u1ee5' - | '\u1ee7' - | '\u1ee9' - | '\u1eeb' - | '\u1eed' - | '\u1eef' - | '\u1ef1' - | '\u1ef3' - | '\u1ef5' - | '\u1ef7' - | '\u1ef9' - | '\u1efb' - | '\u1efd' - | '\u1eff' .. '\u1f07' - | '\u1f10' .. '\u1f15' - | '\u1f20' .. '\u1f27' - | '\u1f30' .. '\u1f37' - | '\u1f40' .. '\u1f45' - | '\u1f50' .. '\u1f57' - | '\u1f60' .. '\u1f67' - | '\u1f70' .. '\u1f87' - | '\u1f90' .. '\u1f97' - | '\u1fa0' .. '\u1fa7' - | '\u1fb0' .. '\u1fb7' - | '\u1fbe' - | '\u1fc2' .. '\u1fc7' - | '\u1fd0' .. '\u1fd7' - | '\u1fe0' .. '\u1fe7' - | '\u1ff2' .. '\u1ff7' - | '\u210a' - | '\u210e' .. '\u210f' - | '\u2113' - | '\u212f' - | '\u2134' - | '\u2139' - | '\u213c' .. '\u213d' - | '\u2146' .. '\u2149' - | '\u214e' - | '\u2184' - | '\u2c30' .. '\u2c5e' - | '\u2c61' - | '\u2c65' .. '\u2c66' - | '\u2c68' - | '\u2c6a' - | '\u2c6c' - | '\u2c71' - | '\u2c73' .. '\u2c74' - | '\u2c76' .. '\u2c7c' - | '\u2c81' - | '\u2c83' - | '\u2c85' - | '\u2c87' - | '\u2c89' - | '\u2c8b' - | '\u2c8d' - | '\u2c8f' - | '\u2c91' - | '\u2c93' - | '\u2c95' - | '\u2c97' - | '\u2c99' - | '\u2c9b' - | '\u2c9d' - | '\u2c9f' - | '\u2ca1' - | '\u2ca3' - | '\u2ca5' - | '\u2ca7' - | '\u2ca9' - | '\u2cab' - | '\u2cad' - | '\u2caf' - | '\u2cb1' - | '\u2cb3' - | '\u2cb5' - | '\u2cb7' - | '\u2cb9' - | '\u2cbb' - | '\u2cbd' - | '\u2cbf' - | '\u2cc1' - | '\u2cc3' - | '\u2cc5' - | '\u2cc7' - | '\u2cc9' - | '\u2ccb' - | '\u2ccd' - | '\u2ccf' - | '\u2cd1' - | '\u2cd3' - | '\u2cd5' - | '\u2cd7' - | '\u2cd9' - | '\u2cdb' - | '\u2cdd' - | '\u2cdf' - | '\u2ce1' - | '\u2ce3' .. '\u2ce4' - | '\u2cec' - | '\u2cee' - | '\u2d00' .. '\u2d25' - | '\ua641' - | '\ua643' - | '\ua645' - | '\ua647' - | '\ua649' - | '\ua64b' - | '\ua64d' - | '\ua64f' - | '\ua651' - | '\ua653' - | '\ua655' - | '\ua657' - | '\ua659' - | '\ua65b' - | '\ua65d' - | '\ua65f' - | '\ua661' - | '\ua663' - | '\ua665' - | '\ua667' - | '\ua669' - | '\ua66b' - | '\ua66d' - | '\ua681' - | '\ua683' - | '\ua685' - | '\ua687' - | '\ua689' - | '\ua68b' - | '\ua68d' - | '\ua68f' - | '\ua691' - | '\ua693' - | '\ua695' - | '\ua697' - | '\ua723' - | '\ua725' - | '\ua727' - | '\ua729' - | '\ua72b' - | '\ua72d' - | '\ua72f' .. '\ua731' - | '\ua733' - | '\ua735' - | '\ua737' - | '\ua739' - | '\ua73b' - | '\ua73d' - | '\ua73f' - | '\ua741' - | '\ua743' - | '\ua745' - | '\ua747' - | '\ua749' - | '\ua74b' - | '\ua74d' - | '\ua74f' - | '\ua751' - | '\ua753' - | '\ua755' - | '\ua757' - | '\ua759' - | '\ua75b' - | '\ua75d' - | '\ua75f' - | '\ua761' - | '\ua763' - | '\ua765' - | '\ua767' - | '\ua769' - | '\ua76b' - | '\ua76d' - | '\ua76f' - | '\ua771' .. '\ua778' - | '\ua77a' - | '\ua77c' - | '\ua77f' - | '\ua781' - | '\ua783' - | '\ua785' - | '\ua787' - | '\ua78c' - | '\ua78e' - | '\ua791' - | '\ua7a1' - | '\ua7a3' - | '\ua7a5' - | '\ua7a7' - | '\ua7a9' .. '\ua7fa' - | '\ufb00' .. '\ufb17' - | '\uff41' .. '\uff5a' - | '\U00010428' .. '\U0001044f' - | '\U0001d41a' .. '\U0001d433' - | '\U0001d44e' .. '\U0001d467' - | '\U0001d482' .. '\U0001d49b' - | '\U0001d4b6' .. '\U0001d4cf' - | '\U0001d4ea' .. '\U0001d503' - | '\U0001d51e' .. '\U0001d537' - | '\U0001d552' .. '\U0001d56b' - | '\U0001d586' .. '\U0001d59f' - | '\U0001d5ba' .. '\U0001d5d3' - | '\U0001d5ee' .. '\U0001d607' - | '\U0001d622' .. '\U0001d63b' - | '\U0001d656' .. '\U0001d66f' - | '\U0001d68a' .. '\U0001d6a5' - | '\U0001d6c2' .. '\U0001d6da' - | '\U0001d6dc' .. '\U0001d6e1' - | '\U0001d6fc' .. '\U0001d714' - | '\U0001d716' .. '\U0001d71b' - | '\U0001d736' .. '\U0001d74e' - | '\U0001d750' .. '\U0001d755' - | '\U0001d770' .. '\U0001d788' - | '\U0001d78a' .. '\U0001d78f' - | '\U0001d7aa' .. '\U0001d7c2' - | '\U0001d7c4' .. '\U0001d7c9' - | '\U0001d7cb' - => true, - _ => false - }; + bsearch_range_table(c, Ll_table) } + static Lm_table : &'static [(char,char)] = &[ + ('\u02b0', '\u02c1'), ('\u02c6', '\u02d1'), + ('\u02e0', '\u02e4'), ('\u02ec', '\u02ec'), + ('\u02ee', '\u02ee'), ('\u0374', '\u0374'), + ('\u037a', '\u037a'), ('\u0559', '\u0559'), + ('\u0640', '\u0640'), ('\u06e5', '\u06e6'), + ('\u07f4', '\u07f5'), ('\u07fa', '\u07fa'), + ('\u081a', '\u081a'), ('\u0824', '\u0824'), + ('\u0828', '\u0828'), ('\u0971', '\u0971'), + ('\u0e46', '\u0e46'), ('\u0ec6', '\u0ec6'), + ('\u10fc', '\u10fc'), ('\u17d7', '\u17d7'), + ('\u1843', '\u1843'), ('\u1aa7', '\u1aa7'), + ('\u1c78', '\u1c7d'), ('\u1d2c', '\u1d6a'), + ('\u1d78', '\u1d78'), ('\u1d9b', '\u1dbf'), + ('\u2071', '\u2071'), ('\u207f', '\u207f'), + ('\u2090', '\u209c'), ('\u2c7c', '\u2c7d'), + ('\u2d6f', '\u2d6f'), ('\u2e2f', '\u2e2f'), + ('\u3005', '\u3005'), ('\u3031', '\u3035'), + ('\u303b', '\u303b'), ('\u309d', '\u309e'), + ('\u30fc', '\u30fe'), ('\ua015', '\ua015'), + ('\ua4f8', '\ua4fd'), ('\ua60c', '\ua60c'), + ('\ua67f', '\ua67f'), ('\ua717', '\ua71f'), + ('\ua770', '\ua770'), ('\ua788', '\ua788'), + ('\ua7f8', '\ua7f9'), ('\ua9cf', '\ua9cf'), + ('\uaa70', '\uaa70'), ('\uaadd', '\uaadd'), + ('\uaaf3', '\uaaf4'), ('\uff70', '\uff70'), + ('\uff9e', '\uff9f'), ('\U00016f93', '\U00016f9f') + ]; + pub fn Lm(c: char) -> bool { - return match c { - '\u02b0' .. '\u02c1' - | '\u02c6' .. '\u02d1' - | '\u02e0' .. '\u02e4' - | '\u02ec' - | '\u02ee' - | '\u0374' - | '\u037a' - | '\u0559' - | '\u0640' - | '\u06e5' .. '\u06e6' - | '\u07f4' .. '\u07f5' - | '\u07fa' - | '\u081a' - | '\u0824' - | '\u0828' - | '\u0971' - | '\u0e46' - | '\u0ec6' - | '\u10fc' - | '\u17d7' - | '\u1843' - | '\u1aa7' - | '\u1c78' .. '\u1c7d' - | '\u1d2c' .. '\u1d61' - | '\u1d78' - | '\u1d9b' .. '\u1dbf' - | '\u2071' - | '\u207f' - | '\u2090' .. '\u209c' - | '\u2c7d' - | '\u2d6f' - | '\u2e2f' - | '\u3005' - | '\u3031' .. '\u3035' - | '\u303b' - | '\u309d' .. '\u309e' - | '\u30fc' .. '\u30fe' - | '\ua015' - | '\ua4f8' .. '\ua4fd' - | '\ua60c' - | '\ua67f' - | '\ua717' .. '\ua71f' - | '\ua770' - | '\ua788' - | '\ua9cf' - | '\uaa70' - | '\uaadd' - | '\uff70' - | '\uff9e' .. '\uff9f' - => true, - _ => false - }; + bsearch_range_table(c, Lm_table) } + static Lo_table : &'static [(char,char)] = &[ + ('\xaa', '\xaa'), ('\xba', '\xba'), + ('\u01bb', '\u01bb'), ('\u01c0', '\u01c3'), + ('\u0294', '\u0294'), ('\u05d0', '\u05f2'), + ('\u0620', '\u063f'), ('\u0641', '\u064a'), + ('\u066e', '\u066f'), ('\u0671', '\u06d3'), + ('\u06d5', '\u06d5'), ('\u06ee', '\u06ef'), + ('\u06fa', '\u06fc'), ('\u06ff', '\u06ff'), + ('\u0710', '\u0710'), ('\u0712', '\u072f'), + ('\u074d', '\u07a5'), ('\u07b1', '\u07b1'), + ('\u07ca', '\u07ea'), ('\u0800', '\u0815'), + ('\u0840', '\u0858'), ('\u08a0', '\u08ac'), + ('\u0904', '\u0939'), ('\u093d', '\u093d'), + ('\u0950', '\u0950'), ('\u0958', '\u0961'), + ('\u0972', '\u097f'), ('\u0985', '\u09b9'), + ('\u09bd', '\u09bd'), ('\u09ce', '\u09ce'), + ('\u09dc', '\u09e1'), ('\u09f0', '\u09f1'), + ('\u0a05', '\u0a39'), ('\u0a59', '\u0a5e'), + ('\u0a72', '\u0a74'), ('\u0a85', '\u0ab9'), + ('\u0abd', '\u0abd'), ('\u0ad0', '\u0ae1'), + ('\u0b05', '\u0b39'), ('\u0b3d', '\u0b3d'), + ('\u0b5c', '\u0b61'), ('\u0b71', '\u0b71'), + ('\u0b83', '\u0bb9'), ('\u0bd0', '\u0bd0'), + ('\u0c05', '\u0c3d'), ('\u0c58', '\u0c61'), + ('\u0c85', '\u0cb9'), ('\u0cbd', '\u0cbd'), + ('\u0cde', '\u0ce1'), ('\u0cf1', '\u0cf2'), + ('\u0d05', '\u0d3d'), ('\u0d4e', '\u0d4e'), + ('\u0d60', '\u0d61'), ('\u0d7a', '\u0d7f'), + ('\u0d85', '\u0dc6'), ('\u0e01', '\u0e30'), + ('\u0e32', '\u0e33'), ('\u0e40', '\u0e45'), + ('\u0e81', '\u0eb0'), ('\u0eb2', '\u0eb3'), + ('\u0ebd', '\u0ec4'), ('\u0edc', '\u0f00'), + ('\u0f40', '\u0f6c'), ('\u0f88', '\u0f8c'), + ('\u1000', '\u102a'), ('\u103f', '\u103f'), + ('\u1050', '\u1055'), ('\u105a', '\u105d'), + ('\u1061', '\u1061'), ('\u1065', '\u1066'), + ('\u106e', '\u1070'), ('\u1075', '\u1081'), + ('\u108e', '\u108e'), ('\u10d0', '\u10fa'), + ('\u10fd', '\u135a'), ('\u1380', '\u138f'), + ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), + ('\u166f', '\u167f'), ('\u1681', '\u169a'), + ('\u16a0', '\u16ea'), ('\u1700', '\u1711'), + ('\u1720', '\u1731'), ('\u1740', '\u1751'), + ('\u1760', '\u1770'), ('\u1780', '\u17b3'), + ('\u17dc', '\u17dc'), ('\u1820', '\u1842'), + ('\u1844', '\u18a8'), ('\u18aa', '\u191c'), + ('\u1950', '\u19ab'), ('\u19c1', '\u19c7'), + ('\u1a00', '\u1a16'), ('\u1a20', '\u1a54'), + ('\u1b05', '\u1b33'), ('\u1b45', '\u1b4b'), + ('\u1b83', '\u1ba0'), ('\u1bae', '\u1baf'), + ('\u1bba', '\u1be5'), ('\u1c00', '\u1c23'), + ('\u1c4d', '\u1c4f'), ('\u1c5a', '\u1c77'), + ('\u1ce9', '\u1cec'), ('\u1cee', '\u1cf1'), + ('\u1cf5', '\u1cf6'), ('\u2135', '\u2138'), + ('\u2d30', '\u2d67'), ('\u2d80', '\u2dde'), + ('\u3006', '\u3006'), ('\u303c', '\u303c'), + ('\u3041', '\u3096'), ('\u309f', '\u309f'), + ('\u30a1', '\u30fa'), ('\u30ff', '\u318e'), + ('\u31a0', '\u31ba'), ('\u31f0', '\u31ff'), + ('\u3400', '\u4db5'), ('\u4e00', '\ua014'), + ('\ua016', '\ua48c'), ('\ua4d0', '\ua4f7'), + ('\ua500', '\ua60b'), ('\ua610', '\ua61f'), + ('\ua62a', '\ua62b'), ('\ua66e', '\ua66e'), + ('\ua6a0', '\ua6e5'), ('\ua7fb', '\ua801'), + ('\ua803', '\ua805'), ('\ua807', '\ua80a'), + ('\ua80c', '\ua822'), ('\ua840', '\ua873'), + ('\ua882', '\ua8b3'), ('\ua8f2', '\ua8f7'), + ('\ua8fb', '\ua8fb'), ('\ua90a', '\ua925'), + ('\ua930', '\ua946'), ('\ua960', '\ua97c'), + ('\ua984', '\ua9b2'), ('\uaa00', '\uaa28'), + ('\uaa40', '\uaa42'), ('\uaa44', '\uaa4b'), + ('\uaa60', '\uaa6f'), ('\uaa71', '\uaa76'), + ('\uaa7a', '\uaa7a'), ('\uaa80', '\uaaaf'), + ('\uaab1', '\uaab1'), ('\uaab5', '\uaab6'), + ('\uaab9', '\uaabd'), ('\uaac0', '\uaac0'), + ('\uaac2', '\uaadc'), ('\uaae0', '\uaaea'), + ('\uaaf2', '\uaaf2'), ('\uab01', '\uabe2'), + ('\uac00', '\ud7fb'), ('\uf900', '\ufad9'), + ('\ufb1d', '\ufb1d'), ('\ufb1f', '\ufb28'), + ('\ufb2a', '\ufbb1'), ('\ufbd3', '\ufd3d'), + ('\ufd50', '\ufdfb'), ('\ufe70', '\ufefc'), + ('\uff66', '\uff6f'), ('\uff71', '\uff9d'), + ('\uffa0', '\uffdc'), ('\U00010000', '\U000100fa'), + ('\U00010280', '\U0001031e'), ('\U00010330', '\U00010340'), + ('\U00010342', '\U00010349'), ('\U00010380', '\U0001039d'), + ('\U000103a0', '\U000103cf'), ('\U00010450', '\U0001049d'), + ('\U00010800', '\U00010855'), ('\U00010900', '\U00010915'), + ('\U00010920', '\U00010939'), ('\U00010980', '\U00010a00'), + ('\U00010a10', '\U00010a33'), ('\U00010a60', '\U00010a7c'), + ('\U00010b00', '\U00010b35'), ('\U00010b40', '\U00010b55'), + ('\U00010b60', '\U00010b72'), ('\U00010c00', '\U00010c48'), + ('\U00011003', '\U00011037'), ('\U00011083', '\U000110af'), + ('\U000110d0', '\U000110e8'), ('\U00011103', '\U00011126'), + ('\U00011183', '\U000111b2'), ('\U000111c1', '\U000111c4'), + ('\U00011680', '\U000116aa'), ('\U00012000', '\U0001236e'), + ('\U00013000', '\U00016f50'), ('\U0001b000', '\U0001b001'), + ('\U0001ee00', '\U0001eebb'), ('\U00020000', '\U0002fa1d') + ]; + pub fn Lo(c: char) -> bool { - return match c { - '\u01bb' - | '\u01c0' .. '\u01c3' - | '\u0294' - | '\u05d0' .. '\u05f2' - | '\u0620' .. '\u063f' - | '\u0641' .. '\u064a' - | '\u066e' .. '\u066f' - | '\u0671' .. '\u06d3' - | '\u06d5' - | '\u06ee' .. '\u06ef' - | '\u06fa' .. '\u06fc' - | '\u06ff' - | '\u0710' - | '\u0712' .. '\u072f' - | '\u074d' .. '\u07a5' - | '\u07b1' - | '\u07ca' .. '\u07ea' - | '\u0800' .. '\u0815' - | '\u0840' .. '\u0858' - | '\u0904' .. '\u0939' - | '\u093d' - | '\u0950' - | '\u0958' .. '\u0961' - | '\u0972' .. '\u097f' - | '\u0985' .. '\u09b9' - | '\u09bd' - | '\u09ce' - | '\u09dc' .. '\u09e1' - | '\u09f0' .. '\u09f1' - | '\u0a05' .. '\u0a39' - | '\u0a59' .. '\u0a5e' - | '\u0a72' .. '\u0a74' - | '\u0a85' .. '\u0ab9' - | '\u0abd' - | '\u0ad0' .. '\u0ae1' - | '\u0b05' .. '\u0b39' - | '\u0b3d' - | '\u0b5c' .. '\u0b61' - | '\u0b71' - | '\u0b83' .. '\u0bb9' - | '\u0bd0' - | '\u0c05' .. '\u0c3d' - | '\u0c58' .. '\u0c61' - | '\u0c85' .. '\u0cb9' - | '\u0cbd' - | '\u0cde' .. '\u0ce1' - | '\u0cf1' .. '\u0cf2' - | '\u0d05' .. '\u0d3d' - | '\u0d4e' - | '\u0d60' .. '\u0d61' - | '\u0d7a' .. '\u0d7f' - | '\u0d85' .. '\u0dc6' - | '\u0e01' .. '\u0e30' - | '\u0e32' .. '\u0e33' - | '\u0e40' .. '\u0e45' - | '\u0e81' .. '\u0eb0' - | '\u0eb2' .. '\u0eb3' - | '\u0ebd' .. '\u0ec4' - | '\u0edc' .. '\u0f00' - | '\u0f40' .. '\u0f6c' - | '\u0f88' .. '\u0f8c' - | '\u1000' .. '\u102a' - | '\u103f' - | '\u1050' .. '\u1055' - | '\u105a' .. '\u105d' - | '\u1061' - | '\u1065' .. '\u1066' - | '\u106e' .. '\u1070' - | '\u1075' .. '\u1081' - | '\u108e' - | '\u10d0' .. '\u10fa' - | '\u1100' .. '\u135a' - | '\u1380' .. '\u138f' - | '\u13a0' .. '\u13f4' - | '\u1401' .. '\u166c' - | '\u166f' .. '\u167f' - | '\u1681' .. '\u169a' - | '\u16a0' .. '\u16ea' - | '\u1700' .. '\u1711' - | '\u1720' .. '\u1731' - | '\u1740' .. '\u1751' - | '\u1760' .. '\u1770' - | '\u1780' .. '\u17b3' - | '\u17dc' - | '\u1820' .. '\u1842' - | '\u1844' .. '\u18a8' - | '\u18aa' .. '\u191c' - | '\u1950' .. '\u19ab' - | '\u19c1' .. '\u19c7' - | '\u1a00' .. '\u1a16' - | '\u1a20' .. '\u1a54' - | '\u1b05' .. '\u1b33' - | '\u1b45' .. '\u1b4b' - | '\u1b83' .. '\u1ba0' - | '\u1bae' .. '\u1baf' - | '\u1bc0' .. '\u1be5' - | '\u1c00' .. '\u1c23' - | '\u1c4d' .. '\u1c4f' - | '\u1c5a' .. '\u1c77' - | '\u1ce9' .. '\u1cec' - | '\u1cee' .. '\u1cf1' - | '\u2135' .. '\u2138' - | '\u2d30' .. '\u2d65' - | '\u2d80' .. '\u2dde' - | '\u3006' - | '\u303c' - | '\u3041' .. '\u3096' - | '\u309f' - | '\u30a1' .. '\u30fa' - | '\u30ff' .. '\u318e' - | '\u31a0' .. '\u31ba' - | '\u31f0' .. '\u31ff' - | '\u3400' .. '\u4db5' - | '\u4e00' .. '\ua014' - | '\ua016' .. '\ua48c' - | '\ua4d0' .. '\ua4f7' - | '\ua500' .. '\ua60b' - | '\ua610' .. '\ua61f' - | '\ua62a' .. '\ua62b' - | '\ua66e' - | '\ua6a0' .. '\ua6e5' - | '\ua7fb' .. '\ua801' - | '\ua803' .. '\ua805' - | '\ua807' .. '\ua80a' - | '\ua80c' .. '\ua822' - | '\ua840' .. '\ua873' - | '\ua882' .. '\ua8b3' - | '\ua8f2' .. '\ua8f7' - | '\ua8fb' - | '\ua90a' .. '\ua925' - | '\ua930' .. '\ua946' - | '\ua960' .. '\ua97c' - | '\ua984' .. '\ua9b2' - | '\uaa00' .. '\uaa28' - | '\uaa40' .. '\uaa42' - | '\uaa44' .. '\uaa4b' - | '\uaa60' .. '\uaa6f' - | '\uaa71' .. '\uaa76' - | '\uaa7a' - | '\uaa80' .. '\uaaaf' - | '\uaab1' - | '\uaab5' .. '\uaab6' - | '\uaab9' .. '\uaabd' - | '\uaac0' - | '\uaac2' .. '\uaadc' - | '\uab01' .. '\uabe2' - | '\uac00' .. '\ud7fb' - | '\uf900' .. '\ufad9' - | '\ufb1d' - | '\ufb1f' .. '\ufb28' - | '\ufb2a' .. '\ufbb1' - | '\ufbd3' .. '\ufd3d' - | '\ufd50' .. '\ufdfb' - | '\ufe70' .. '\ufefc' - | '\uff66' .. '\uff6f' - | '\uff71' .. '\uff9d' - | '\uffa0' .. '\uffdc' - | '\U00010000' .. '\U000100fa' - | '\U00010280' .. '\U0001031e' - | '\U00010330' .. '\U00010340' - | '\U00010342' .. '\U00010349' - | '\U00010380' .. '\U0001039d' - | '\U000103a0' .. '\U000103cf' - | '\U00010450' .. '\U0001049d' - | '\U00010800' .. '\U00010855' - | '\U00010900' .. '\U00010915' - | '\U00010920' .. '\U00010939' - | '\U00010a00' - | '\U00010a10' .. '\U00010a33' - | '\U00010a60' .. '\U00010a7c' - | '\U00010b00' .. '\U00010b35' - | '\U00010b40' .. '\U00010b55' - | '\U00010b60' .. '\U00010b72' - | '\U00010c00' .. '\U00010c48' - | '\U00011003' .. '\U00011037' - | '\U00011083' .. '\U000110af' - | '\U00012000' .. '\U0001236e' - | '\U00013000' .. '\U0001b001' - | '\U00020000' .. '\U0002fa1d' - => true, - _ => false - }; + bsearch_range_table(c, Lo_table) } + static Lt_table : &'static [(char,char)] = &[ + ('\u01c5', '\u01c5'), ('\u01c8', '\u01c8'), + ('\u01cb', '\u01cb'), ('\u01f2', '\u01f2'), + ('\u1f88', '\u1f8f'), ('\u1f98', '\u1f9f'), + ('\u1fa8', '\u1faf'), ('\u1fbc', '\u1fbc'), + ('\u1fcc', '\u1fcc'), ('\u1ffc', '\u1ffc') + ]; + pub fn Lt(c: char) -> bool { - return match c { - '\u01c5' - | '\u01c8' - | '\u01cb' - | '\u01f2' - | '\u1f88' .. '\u1f8f' - | '\u1f98' .. '\u1f9f' - | '\u1fa8' .. '\u1faf' - | '\u1fbc' - | '\u1fcc' - | '\u1ffc' - => true, - _ => false - }; + bsearch_range_table(c, Lt_table) } + static Lu_table : &'static [(char,char)] = &[ + ('\x41', '\x5a'), ('\xc0', '\xd6'), + ('\xd8', '\xde'), ('\u0100', '\u0100'), + ('\u0102', '\u0102'), ('\u0104', '\u0104'), + ('\u0106', '\u0106'), ('\u0108', '\u0108'), + ('\u010a', '\u010a'), ('\u010c', '\u010c'), + ('\u010e', '\u010e'), ('\u0110', '\u0110'), + ('\u0112', '\u0112'), ('\u0114', '\u0114'), + ('\u0116', '\u0116'), ('\u0118', '\u0118'), + ('\u011a', '\u011a'), ('\u011c', '\u011c'), + ('\u011e', '\u011e'), ('\u0120', '\u0120'), + ('\u0122', '\u0122'), ('\u0124', '\u0124'), + ('\u0126', '\u0126'), ('\u0128', '\u0128'), + ('\u012a', '\u012a'), ('\u012c', '\u012c'), + ('\u012e', '\u012e'), ('\u0130', '\u0130'), + ('\u0132', '\u0132'), ('\u0134', '\u0134'), + ('\u0136', '\u0136'), ('\u0139', '\u0139'), + ('\u013b', '\u013b'), ('\u013d', '\u013d'), + ('\u013f', '\u013f'), ('\u0141', '\u0141'), + ('\u0143', '\u0143'), ('\u0145', '\u0145'), + ('\u0147', '\u0147'), ('\u014a', '\u014a'), + ('\u014c', '\u014c'), ('\u014e', '\u014e'), + ('\u0150', '\u0150'), ('\u0152', '\u0152'), + ('\u0154', '\u0154'), ('\u0156', '\u0156'), + ('\u0158', '\u0158'), ('\u015a', '\u015a'), + ('\u015c', '\u015c'), ('\u015e', '\u015e'), + ('\u0160', '\u0160'), ('\u0162', '\u0162'), + ('\u0164', '\u0164'), ('\u0166', '\u0166'), + ('\u0168', '\u0168'), ('\u016a', '\u016a'), + ('\u016c', '\u016c'), ('\u016e', '\u016e'), + ('\u0170', '\u0170'), ('\u0172', '\u0172'), + ('\u0174', '\u0174'), ('\u0176', '\u0176'), + ('\u0178', '\u0179'), ('\u017b', '\u017b'), + ('\u017d', '\u017d'), ('\u0181', '\u0182'), + ('\u0184', '\u0184'), ('\u0186', '\u0187'), + ('\u0189', '\u018b'), ('\u018e', '\u0191'), + ('\u0193', '\u0194'), ('\u0196', '\u0198'), + ('\u019c', '\u019d'), ('\u019f', '\u01a0'), + ('\u01a2', '\u01a2'), ('\u01a4', '\u01a4'), + ('\u01a6', '\u01a7'), ('\u01a9', '\u01a9'), + ('\u01ac', '\u01ac'), ('\u01ae', '\u01af'), + ('\u01b1', '\u01b3'), ('\u01b5', '\u01b5'), + ('\u01b7', '\u01b8'), ('\u01bc', '\u01bc'), + ('\u01c4', '\u01c4'), ('\u01c7', '\u01c7'), + ('\u01ca', '\u01ca'), ('\u01cd', '\u01cd'), + ('\u01cf', '\u01cf'), ('\u01d1', '\u01d1'), + ('\u01d3', '\u01d3'), ('\u01d5', '\u01d5'), + ('\u01d7', '\u01d7'), ('\u01d9', '\u01d9'), + ('\u01db', '\u01db'), ('\u01de', '\u01de'), + ('\u01e0', '\u01e0'), ('\u01e2', '\u01e2'), + ('\u01e4', '\u01e4'), ('\u01e6', '\u01e6'), + ('\u01e8', '\u01e8'), ('\u01ea', '\u01ea'), + ('\u01ec', '\u01ec'), ('\u01ee', '\u01ee'), + ('\u01f1', '\u01f1'), ('\u01f4', '\u01f4'), + ('\u01f6', '\u01f8'), ('\u01fa', '\u01fa'), + ('\u01fc', '\u01fc'), ('\u01fe', '\u01fe'), + ('\u0200', '\u0200'), ('\u0202', '\u0202'), + ('\u0204', '\u0204'), ('\u0206', '\u0206'), + ('\u0208', '\u0208'), ('\u020a', '\u020a'), + ('\u020c', '\u020c'), ('\u020e', '\u020e'), + ('\u0210', '\u0210'), ('\u0212', '\u0212'), + ('\u0214', '\u0214'), ('\u0216', '\u0216'), + ('\u0218', '\u0218'), ('\u021a', '\u021a'), + ('\u021c', '\u021c'), ('\u021e', '\u021e'), + ('\u0220', '\u0220'), ('\u0222', '\u0222'), + ('\u0224', '\u0224'), ('\u0226', '\u0226'), + ('\u0228', '\u0228'), ('\u022a', '\u022a'), + ('\u022c', '\u022c'), ('\u022e', '\u022e'), + ('\u0230', '\u0230'), ('\u0232', '\u0232'), + ('\u023a', '\u023b'), ('\u023d', '\u023e'), + ('\u0241', '\u0241'), ('\u0243', '\u0246'), + ('\u0248', '\u0248'), ('\u024a', '\u024a'), + ('\u024c', '\u024c'), ('\u024e', '\u024e'), + ('\u0370', '\u0370'), ('\u0372', '\u0372'), + ('\u0376', '\u0376'), ('\u0386', '\u0386'), + ('\u0388', '\u038f'), ('\u0391', '\u03ab'), + ('\u03cf', '\u03cf'), ('\u03d2', '\u03d4'), + ('\u03d8', '\u03d8'), ('\u03da', '\u03da'), + ('\u03dc', '\u03dc'), ('\u03de', '\u03de'), + ('\u03e0', '\u03e0'), ('\u03e2', '\u03e2'), + ('\u03e4', '\u03e4'), ('\u03e6', '\u03e6'), + ('\u03e8', '\u03e8'), ('\u03ea', '\u03ea'), + ('\u03ec', '\u03ec'), ('\u03ee', '\u03ee'), + ('\u03f4', '\u03f4'), ('\u03f7', '\u03f7'), + ('\u03f9', '\u03fa'), ('\u03fd', '\u042f'), + ('\u0460', '\u0460'), ('\u0462', '\u0462'), + ('\u0464', '\u0464'), ('\u0466', '\u0466'), + ('\u0468', '\u0468'), ('\u046a', '\u046a'), + ('\u046c', '\u046c'), ('\u046e', '\u046e'), + ('\u0470', '\u0470'), ('\u0472', '\u0472'), + ('\u0474', '\u0474'), ('\u0476', '\u0476'), + ('\u0478', '\u0478'), ('\u047a', '\u047a'), + ('\u047c', '\u047c'), ('\u047e', '\u047e'), + ('\u0480', '\u0480'), ('\u048a', '\u048a'), + ('\u048c', '\u048c'), ('\u048e', '\u048e'), + ('\u0490', '\u0490'), ('\u0492', '\u0492'), + ('\u0494', '\u0494'), ('\u0496', '\u0496'), + ('\u0498', '\u0498'), ('\u049a', '\u049a'), + ('\u049c', '\u049c'), ('\u049e', '\u049e'), + ('\u04a0', '\u04a0'), ('\u04a2', '\u04a2'), + ('\u04a4', '\u04a4'), ('\u04a6', '\u04a6'), + ('\u04a8', '\u04a8'), ('\u04aa', '\u04aa'), + ('\u04ac', '\u04ac'), ('\u04ae', '\u04ae'), + ('\u04b0', '\u04b0'), ('\u04b2', '\u04b2'), + ('\u04b4', '\u04b4'), ('\u04b6', '\u04b6'), + ('\u04b8', '\u04b8'), ('\u04ba', '\u04ba'), + ('\u04bc', '\u04bc'), ('\u04be', '\u04be'), + ('\u04c0', '\u04c1'), ('\u04c3', '\u04c3'), + ('\u04c5', '\u04c5'), ('\u04c7', '\u04c7'), + ('\u04c9', '\u04c9'), ('\u04cb', '\u04cb'), + ('\u04cd', '\u04cd'), ('\u04d0', '\u04d0'), + ('\u04d2', '\u04d2'), ('\u04d4', '\u04d4'), + ('\u04d6', '\u04d6'), ('\u04d8', '\u04d8'), + ('\u04da', '\u04da'), ('\u04dc', '\u04dc'), + ('\u04de', '\u04de'), ('\u04e0', '\u04e0'), + ('\u04e2', '\u04e2'), ('\u04e4', '\u04e4'), + ('\u04e6', '\u04e6'), ('\u04e8', '\u04e8'), + ('\u04ea', '\u04ea'), ('\u04ec', '\u04ec'), + ('\u04ee', '\u04ee'), ('\u04f0', '\u04f0'), + ('\u04f2', '\u04f2'), ('\u04f4', '\u04f4'), + ('\u04f6', '\u04f6'), ('\u04f8', '\u04f8'), + ('\u04fa', '\u04fa'), ('\u04fc', '\u04fc'), + ('\u04fe', '\u04fe'), ('\u0500', '\u0500'), + ('\u0502', '\u0502'), ('\u0504', '\u0504'), + ('\u0506', '\u0506'), ('\u0508', '\u0508'), + ('\u050a', '\u050a'), ('\u050c', '\u050c'), + ('\u050e', '\u050e'), ('\u0510', '\u0510'), + ('\u0512', '\u0512'), ('\u0514', '\u0514'), + ('\u0516', '\u0516'), ('\u0518', '\u0518'), + ('\u051a', '\u051a'), ('\u051c', '\u051c'), + ('\u051e', '\u051e'), ('\u0520', '\u0520'), + ('\u0522', '\u0522'), ('\u0524', '\u0524'), + ('\u0526', '\u0526'), ('\u0531', '\u0556'), + ('\u10a0', '\u10cd'), ('\u1e00', '\u1e00'), + ('\u1e02', '\u1e02'), ('\u1e04', '\u1e04'), + ('\u1e06', '\u1e06'), ('\u1e08', '\u1e08'), + ('\u1e0a', '\u1e0a'), ('\u1e0c', '\u1e0c'), + ('\u1e0e', '\u1e0e'), ('\u1e10', '\u1e10'), + ('\u1e12', '\u1e12'), ('\u1e14', '\u1e14'), + ('\u1e16', '\u1e16'), ('\u1e18', '\u1e18'), + ('\u1e1a', '\u1e1a'), ('\u1e1c', '\u1e1c'), + ('\u1e1e', '\u1e1e'), ('\u1e20', '\u1e20'), + ('\u1e22', '\u1e22'), ('\u1e24', '\u1e24'), + ('\u1e26', '\u1e26'), ('\u1e28', '\u1e28'), + ('\u1e2a', '\u1e2a'), ('\u1e2c', '\u1e2c'), + ('\u1e2e', '\u1e2e'), ('\u1e30', '\u1e30'), + ('\u1e32', '\u1e32'), ('\u1e34', '\u1e34'), + ('\u1e36', '\u1e36'), ('\u1e38', '\u1e38'), + ('\u1e3a', '\u1e3a'), ('\u1e3c', '\u1e3c'), + ('\u1e3e', '\u1e3e'), ('\u1e40', '\u1e40'), + ('\u1e42', '\u1e42'), ('\u1e44', '\u1e44'), + ('\u1e46', '\u1e46'), ('\u1e48', '\u1e48'), + ('\u1e4a', '\u1e4a'), ('\u1e4c', '\u1e4c'), + ('\u1e4e', '\u1e4e'), ('\u1e50', '\u1e50'), + ('\u1e52', '\u1e52'), ('\u1e54', '\u1e54'), + ('\u1e56', '\u1e56'), ('\u1e58', '\u1e58'), + ('\u1e5a', '\u1e5a'), ('\u1e5c', '\u1e5c'), + ('\u1e5e', '\u1e5e'), ('\u1e60', '\u1e60'), + ('\u1e62', '\u1e62'), ('\u1e64', '\u1e64'), + ('\u1e66', '\u1e66'), ('\u1e68', '\u1e68'), + ('\u1e6a', '\u1e6a'), ('\u1e6c', '\u1e6c'), + ('\u1e6e', '\u1e6e'), ('\u1e70', '\u1e70'), + ('\u1e72', '\u1e72'), ('\u1e74', '\u1e74'), + ('\u1e76', '\u1e76'), ('\u1e78', '\u1e78'), + ('\u1e7a', '\u1e7a'), ('\u1e7c', '\u1e7c'), + ('\u1e7e', '\u1e7e'), ('\u1e80', '\u1e80'), + ('\u1e82', '\u1e82'), ('\u1e84', '\u1e84'), + ('\u1e86', '\u1e86'), ('\u1e88', '\u1e88'), + ('\u1e8a', '\u1e8a'), ('\u1e8c', '\u1e8c'), + ('\u1e8e', '\u1e8e'), ('\u1e90', '\u1e90'), + ('\u1e92', '\u1e92'), ('\u1e94', '\u1e94'), + ('\u1e9e', '\u1e9e'), ('\u1ea0', '\u1ea0'), + ('\u1ea2', '\u1ea2'), ('\u1ea4', '\u1ea4'), + ('\u1ea6', '\u1ea6'), ('\u1ea8', '\u1ea8'), + ('\u1eaa', '\u1eaa'), ('\u1eac', '\u1eac'), + ('\u1eae', '\u1eae'), ('\u1eb0', '\u1eb0'), + ('\u1eb2', '\u1eb2'), ('\u1eb4', '\u1eb4'), + ('\u1eb6', '\u1eb6'), ('\u1eb8', '\u1eb8'), + ('\u1eba', '\u1eba'), ('\u1ebc', '\u1ebc'), + ('\u1ebe', '\u1ebe'), ('\u1ec0', '\u1ec0'), + ('\u1ec2', '\u1ec2'), ('\u1ec4', '\u1ec4'), + ('\u1ec6', '\u1ec6'), ('\u1ec8', '\u1ec8'), + ('\u1eca', '\u1eca'), ('\u1ecc', '\u1ecc'), + ('\u1ece', '\u1ece'), ('\u1ed0', '\u1ed0'), + ('\u1ed2', '\u1ed2'), ('\u1ed4', '\u1ed4'), + ('\u1ed6', '\u1ed6'), ('\u1ed8', '\u1ed8'), + ('\u1eda', '\u1eda'), ('\u1edc', '\u1edc'), + ('\u1ede', '\u1ede'), ('\u1ee0', '\u1ee0'), + ('\u1ee2', '\u1ee2'), ('\u1ee4', '\u1ee4'), + ('\u1ee6', '\u1ee6'), ('\u1ee8', '\u1ee8'), + ('\u1eea', '\u1eea'), ('\u1eec', '\u1eec'), + ('\u1eee', '\u1eee'), ('\u1ef0', '\u1ef0'), + ('\u1ef2', '\u1ef2'), ('\u1ef4', '\u1ef4'), + ('\u1ef6', '\u1ef6'), ('\u1ef8', '\u1ef8'), + ('\u1efa', '\u1efa'), ('\u1efc', '\u1efc'), + ('\u1efe', '\u1efe'), ('\u1f08', '\u1f0f'), + ('\u1f18', '\u1f1d'), ('\u1f28', '\u1f2f'), + ('\u1f38', '\u1f3f'), ('\u1f48', '\u1f4d'), + ('\u1f59', '\u1f5f'), ('\u1f68', '\u1f6f'), + ('\u1fb8', '\u1fbb'), ('\u1fc8', '\u1fcb'), + ('\u1fd8', '\u1fdb'), ('\u1fe8', '\u1fec'), + ('\u1ff8', '\u1ffb'), ('\u2102', '\u2102'), + ('\u2107', '\u2107'), ('\u210b', '\u210d'), + ('\u2110', '\u2112'), ('\u2115', '\u2115'), + ('\u2119', '\u211d'), ('\u2124', '\u2124'), + ('\u2126', '\u2126'), ('\u2128', '\u2128'), + ('\u212a', '\u212d'), ('\u2130', '\u2133'), + ('\u213e', '\u213f'), ('\u2145', '\u2145'), + ('\u2183', '\u2183'), ('\u2c00', '\u2c2e'), + ('\u2c60', '\u2c60'), ('\u2c62', '\u2c64'), + ('\u2c67', '\u2c67'), ('\u2c69', '\u2c69'), + ('\u2c6b', '\u2c6b'), ('\u2c6d', '\u2c70'), + ('\u2c72', '\u2c72'), ('\u2c75', '\u2c75'), + ('\u2c7e', '\u2c80'), ('\u2c82', '\u2c82'), + ('\u2c84', '\u2c84'), ('\u2c86', '\u2c86'), + ('\u2c88', '\u2c88'), ('\u2c8a', '\u2c8a'), + ('\u2c8c', '\u2c8c'), ('\u2c8e', '\u2c8e'), + ('\u2c90', '\u2c90'), ('\u2c92', '\u2c92'), + ('\u2c94', '\u2c94'), ('\u2c96', '\u2c96'), + ('\u2c98', '\u2c98'), ('\u2c9a', '\u2c9a'), + ('\u2c9c', '\u2c9c'), ('\u2c9e', '\u2c9e'), + ('\u2ca0', '\u2ca0'), ('\u2ca2', '\u2ca2'), + ('\u2ca4', '\u2ca4'), ('\u2ca6', '\u2ca6'), + ('\u2ca8', '\u2ca8'), ('\u2caa', '\u2caa'), + ('\u2cac', '\u2cac'), ('\u2cae', '\u2cae'), + ('\u2cb0', '\u2cb0'), ('\u2cb2', '\u2cb2'), + ('\u2cb4', '\u2cb4'), ('\u2cb6', '\u2cb6'), + ('\u2cb8', '\u2cb8'), ('\u2cba', '\u2cba'), + ('\u2cbc', '\u2cbc'), ('\u2cbe', '\u2cbe'), + ('\u2cc0', '\u2cc0'), ('\u2cc2', '\u2cc2'), + ('\u2cc4', '\u2cc4'), ('\u2cc6', '\u2cc6'), + ('\u2cc8', '\u2cc8'), ('\u2cca', '\u2cca'), + ('\u2ccc', '\u2ccc'), ('\u2cce', '\u2cce'), + ('\u2cd0', '\u2cd0'), ('\u2cd2', '\u2cd2'), + ('\u2cd4', '\u2cd4'), ('\u2cd6', '\u2cd6'), + ('\u2cd8', '\u2cd8'), ('\u2cda', '\u2cda'), + ('\u2cdc', '\u2cdc'), ('\u2cde', '\u2cde'), + ('\u2ce0', '\u2ce0'), ('\u2ce2', '\u2ce2'), + ('\u2ceb', '\u2ceb'), ('\u2ced', '\u2ced'), + ('\u2cf2', '\u2cf2'), ('\ua640', '\ua640'), + ('\ua642', '\ua642'), ('\ua644', '\ua644'), + ('\ua646', '\ua646'), ('\ua648', '\ua648'), + ('\ua64a', '\ua64a'), ('\ua64c', '\ua64c'), + ('\ua64e', '\ua64e'), ('\ua650', '\ua650'), + ('\ua652', '\ua652'), ('\ua654', '\ua654'), + ('\ua656', '\ua656'), ('\ua658', '\ua658'), + ('\ua65a', '\ua65a'), ('\ua65c', '\ua65c'), + ('\ua65e', '\ua65e'), ('\ua660', '\ua660'), + ('\ua662', '\ua662'), ('\ua664', '\ua664'), + ('\ua666', '\ua666'), ('\ua668', '\ua668'), + ('\ua66a', '\ua66a'), ('\ua66c', '\ua66c'), + ('\ua680', '\ua680'), ('\ua682', '\ua682'), + ('\ua684', '\ua684'), ('\ua686', '\ua686'), + ('\ua688', '\ua688'), ('\ua68a', '\ua68a'), + ('\ua68c', '\ua68c'), ('\ua68e', '\ua68e'), + ('\ua690', '\ua690'), ('\ua692', '\ua692'), + ('\ua694', '\ua694'), ('\ua696', '\ua696'), + ('\ua722', '\ua722'), ('\ua724', '\ua724'), + ('\ua726', '\ua726'), ('\ua728', '\ua728'), + ('\ua72a', '\ua72a'), ('\ua72c', '\ua72c'), + ('\ua72e', '\ua72e'), ('\ua732', '\ua732'), + ('\ua734', '\ua734'), ('\ua736', '\ua736'), + ('\ua738', '\ua738'), ('\ua73a', '\ua73a'), + ('\ua73c', '\ua73c'), ('\ua73e', '\ua73e'), + ('\ua740', '\ua740'), ('\ua742', '\ua742'), + ('\ua744', '\ua744'), ('\ua746', '\ua746'), + ('\ua748', '\ua748'), ('\ua74a', '\ua74a'), + ('\ua74c', '\ua74c'), ('\ua74e', '\ua74e'), + ('\ua750', '\ua750'), ('\ua752', '\ua752'), + ('\ua754', '\ua754'), ('\ua756', '\ua756'), + ('\ua758', '\ua758'), ('\ua75a', '\ua75a'), + ('\ua75c', '\ua75c'), ('\ua75e', '\ua75e'), + ('\ua760', '\ua760'), ('\ua762', '\ua762'), + ('\ua764', '\ua764'), ('\ua766', '\ua766'), + ('\ua768', '\ua768'), ('\ua76a', '\ua76a'), + ('\ua76c', '\ua76c'), ('\ua76e', '\ua76e'), + ('\ua779', '\ua779'), ('\ua77b', '\ua77b'), + ('\ua77d', '\ua77e'), ('\ua780', '\ua780'), + ('\ua782', '\ua782'), ('\ua784', '\ua784'), + ('\ua786', '\ua786'), ('\ua78b', '\ua78b'), + ('\ua78d', '\ua78d'), ('\ua790', '\ua790'), + ('\ua792', '\ua792'), ('\ua7a0', '\ua7a0'), + ('\ua7a2', '\ua7a2'), ('\ua7a4', '\ua7a4'), + ('\ua7a6', '\ua7a6'), ('\ua7a8', '\ua7a8'), + ('\ua7aa', '\ua7aa'), ('\uff21', '\uff3a'), + ('\U00010400', '\U00010427'), ('\U0001d400', '\U0001d419'), + ('\U0001d434', '\U0001d44d'), ('\U0001d468', '\U0001d481'), + ('\U0001d49c', '\U0001d4b5'), ('\U0001d4d0', '\U0001d4e9'), + ('\U0001d504', '\U0001d51c'), ('\U0001d538', '\U0001d550'), + ('\U0001d56c', '\U0001d585'), ('\U0001d5a0', '\U0001d5b9'), + ('\U0001d5d4', '\U0001d5ed'), ('\U0001d608', '\U0001d621'), + ('\U0001d63c', '\U0001d655'), ('\U0001d670', '\U0001d689'), + ('\U0001d6a8', '\U0001d6c0'), ('\U0001d6e2', '\U0001d6fa'), + ('\U0001d71c', '\U0001d734'), ('\U0001d756', '\U0001d76e'), + ('\U0001d790', '\U0001d7a8'), ('\U0001d7ca', '\U0001d7ca') + ]; + pub fn Lu(c: char) -> bool { - return match c { - '\x41' .. '\x5a' - | '\xc0' .. '\xd6' - | '\xd8' .. '\xde' - | '\u0100' - | '\u0102' - | '\u0104' - | '\u0106' - | '\u0108' - | '\u010a' - | '\u010c' - | '\u010e' - | '\u0110' - | '\u0112' - | '\u0114' - | '\u0116' - | '\u0118' - | '\u011a' - | '\u011c' - | '\u011e' - | '\u0120' - | '\u0122' - | '\u0124' - | '\u0126' - | '\u0128' - | '\u012a' - | '\u012c' - | '\u012e' - | '\u0130' - | '\u0132' - | '\u0134' - | '\u0136' - | '\u0139' - | '\u013b' - | '\u013d' - | '\u013f' - | '\u0141' - | '\u0143' - | '\u0145' - | '\u0147' - | '\u014a' - | '\u014c' - | '\u014e' - | '\u0150' - | '\u0152' - | '\u0154' - | '\u0156' - | '\u0158' - | '\u015a' - | '\u015c' - | '\u015e' - | '\u0160' - | '\u0162' - | '\u0164' - | '\u0166' - | '\u0168' - | '\u016a' - | '\u016c' - | '\u016e' - | '\u0170' - | '\u0172' - | '\u0174' - | '\u0176' - | '\u0178' .. '\u0179' - | '\u017b' - | '\u017d' - | '\u0181' .. '\u0182' - | '\u0184' - | '\u0186' .. '\u0187' - | '\u0189' .. '\u018b' - | '\u018e' .. '\u0191' - | '\u0193' .. '\u0194' - | '\u0196' .. '\u0198' - | '\u019c' .. '\u019d' - | '\u019f' .. '\u01a0' - | '\u01a2' - | '\u01a4' - | '\u01a6' .. '\u01a7' - | '\u01a9' - | '\u01ac' - | '\u01ae' .. '\u01af' - | '\u01b1' .. '\u01b3' - | '\u01b5' - | '\u01b7' .. '\u01b8' - | '\u01bc' - | '\u01c4' - | '\u01c7' - | '\u01ca' - | '\u01cd' - | '\u01cf' - | '\u01d1' - | '\u01d3' - | '\u01d5' - | '\u01d7' - | '\u01d9' - | '\u01db' - | '\u01de' - | '\u01e0' - | '\u01e2' - | '\u01e4' - | '\u01e6' - | '\u01e8' - | '\u01ea' - | '\u01ec' - | '\u01ee' - | '\u01f1' - | '\u01f4' - | '\u01f6' .. '\u01f8' - | '\u01fa' - | '\u01fc' - | '\u01fe' - | '\u0200' - | '\u0202' - | '\u0204' - | '\u0206' - | '\u0208' - | '\u020a' - | '\u020c' - | '\u020e' - | '\u0210' - | '\u0212' - | '\u0214' - | '\u0216' - | '\u0218' - | '\u021a' - | '\u021c' - | '\u021e' - | '\u0220' - | '\u0222' - | '\u0224' - | '\u0226' - | '\u0228' - | '\u022a' - | '\u022c' - | '\u022e' - | '\u0230' - | '\u0232' - | '\u023a' .. '\u023b' - | '\u023d' .. '\u023e' - | '\u0241' - | '\u0243' .. '\u0246' - | '\u0248' - | '\u024a' - | '\u024c' - | '\u024e' - | '\u0370' - | '\u0372' - | '\u0376' - | '\u0386' - | '\u0388' .. '\u038f' - | '\u0391' .. '\u03ab' - | '\u03cf' - | '\u03d2' .. '\u03d4' - | '\u03d8' - | '\u03da' - | '\u03dc' - | '\u03de' - | '\u03e0' - | '\u03e2' - | '\u03e4' - | '\u03e6' - | '\u03e8' - | '\u03ea' - | '\u03ec' - | '\u03ee' - | '\u03f4' - | '\u03f7' - | '\u03f9' .. '\u03fa' - | '\u03fd' .. '\u042f' - | '\u0460' - | '\u0462' - | '\u0464' - | '\u0466' - | '\u0468' - | '\u046a' - | '\u046c' - | '\u046e' - | '\u0470' - | '\u0472' - | '\u0474' - | '\u0476' - | '\u0478' - | '\u047a' - | '\u047c' - | '\u047e' - | '\u0480' - | '\u048a' - | '\u048c' - | '\u048e' - | '\u0490' - | '\u0492' - | '\u0494' - | '\u0496' - | '\u0498' - | '\u049a' - | '\u049c' - | '\u049e' - | '\u04a0' - | '\u04a2' - | '\u04a4' - | '\u04a6' - | '\u04a8' - | '\u04aa' - | '\u04ac' - | '\u04ae' - | '\u04b0' - | '\u04b2' - | '\u04b4' - | '\u04b6' - | '\u04b8' - | '\u04ba' - | '\u04bc' - | '\u04be' - | '\u04c0' .. '\u04c1' - | '\u04c3' - | '\u04c5' - | '\u04c7' - | '\u04c9' - | '\u04cb' - | '\u04cd' - | '\u04d0' - | '\u04d2' - | '\u04d4' - | '\u04d6' - | '\u04d8' - | '\u04da' - | '\u04dc' - | '\u04de' - | '\u04e0' - | '\u04e2' - | '\u04e4' - | '\u04e6' - | '\u04e8' - | '\u04ea' - | '\u04ec' - | '\u04ee' - | '\u04f0' - | '\u04f2' - | '\u04f4' - | '\u04f6' - | '\u04f8' - | '\u04fa' - | '\u04fc' - | '\u04fe' - | '\u0500' - | '\u0502' - | '\u0504' - | '\u0506' - | '\u0508' - | '\u050a' - | '\u050c' - | '\u050e' - | '\u0510' - | '\u0512' - | '\u0514' - | '\u0516' - | '\u0518' - | '\u051a' - | '\u051c' - | '\u051e' - | '\u0520' - | '\u0522' - | '\u0524' - | '\u0526' - | '\u0531' .. '\u0556' - | '\u10a0' .. '\u10c5' - | '\u1e00' - | '\u1e02' - | '\u1e04' - | '\u1e06' - | '\u1e08' - | '\u1e0a' - | '\u1e0c' - | '\u1e0e' - | '\u1e10' - | '\u1e12' - | '\u1e14' - | '\u1e16' - | '\u1e18' - | '\u1e1a' - | '\u1e1c' - | '\u1e1e' - | '\u1e20' - | '\u1e22' - | '\u1e24' - | '\u1e26' - | '\u1e28' - | '\u1e2a' - | '\u1e2c' - | '\u1e2e' - | '\u1e30' - | '\u1e32' - | '\u1e34' - | '\u1e36' - | '\u1e38' - | '\u1e3a' - | '\u1e3c' - | '\u1e3e' - | '\u1e40' - | '\u1e42' - | '\u1e44' - | '\u1e46' - | '\u1e48' - | '\u1e4a' - | '\u1e4c' - | '\u1e4e' - | '\u1e50' - | '\u1e52' - | '\u1e54' - | '\u1e56' - | '\u1e58' - | '\u1e5a' - | '\u1e5c' - | '\u1e5e' - | '\u1e60' - | '\u1e62' - | '\u1e64' - | '\u1e66' - | '\u1e68' - | '\u1e6a' - | '\u1e6c' - | '\u1e6e' - | '\u1e70' - | '\u1e72' - | '\u1e74' - | '\u1e76' - | '\u1e78' - | '\u1e7a' - | '\u1e7c' - | '\u1e7e' - | '\u1e80' - | '\u1e82' - | '\u1e84' - | '\u1e86' - | '\u1e88' - | '\u1e8a' - | '\u1e8c' - | '\u1e8e' - | '\u1e90' - | '\u1e92' - | '\u1e94' - | '\u1e9e' - | '\u1ea0' - | '\u1ea2' - | '\u1ea4' - | '\u1ea6' - | '\u1ea8' - | '\u1eaa' - | '\u1eac' - | '\u1eae' - | '\u1eb0' - | '\u1eb2' - | '\u1eb4' - | '\u1eb6' - | '\u1eb8' - | '\u1eba' - | '\u1ebc' - | '\u1ebe' - | '\u1ec0' - | '\u1ec2' - | '\u1ec4' - | '\u1ec6' - | '\u1ec8' - | '\u1eca' - | '\u1ecc' - | '\u1ece' - | '\u1ed0' - | '\u1ed2' - | '\u1ed4' - | '\u1ed6' - | '\u1ed8' - | '\u1eda' - | '\u1edc' - | '\u1ede' - | '\u1ee0' - | '\u1ee2' - | '\u1ee4' - | '\u1ee6' - | '\u1ee8' - | '\u1eea' - | '\u1eec' - | '\u1eee' - | '\u1ef0' - | '\u1ef2' - | '\u1ef4' - | '\u1ef6' - | '\u1ef8' - | '\u1efa' - | '\u1efc' - | '\u1efe' - | '\u1f08' .. '\u1f0f' - | '\u1f18' .. '\u1f1d' - | '\u1f28' .. '\u1f2f' - | '\u1f38' .. '\u1f3f' - | '\u1f48' .. '\u1f4d' - | '\u1f59' .. '\u1f5f' - | '\u1f68' .. '\u1f6f' - | '\u1fb8' .. '\u1fbb' - | '\u1fc8' .. '\u1fcb' - | '\u1fd8' .. '\u1fdb' - | '\u1fe8' .. '\u1fec' - | '\u1ff8' .. '\u1ffb' - | '\u2102' - | '\u2107' - | '\u210b' .. '\u210d' - | '\u2110' .. '\u2112' - | '\u2115' - | '\u2119' .. '\u211d' - | '\u2124' - | '\u2126' - | '\u2128' - | '\u212a' .. '\u212d' - | '\u2130' .. '\u2133' - | '\u213e' .. '\u213f' - | '\u2145' - | '\u2183' - | '\u2c00' .. '\u2c2e' - | '\u2c60' - | '\u2c62' .. '\u2c64' - | '\u2c67' - | '\u2c69' - | '\u2c6b' - | '\u2c6d' .. '\u2c70' - | '\u2c72' - | '\u2c75' - | '\u2c7e' .. '\u2c80' - | '\u2c82' - | '\u2c84' - | '\u2c86' - | '\u2c88' - | '\u2c8a' - | '\u2c8c' - | '\u2c8e' - | '\u2c90' - | '\u2c92' - | '\u2c94' - | '\u2c96' - | '\u2c98' - | '\u2c9a' - | '\u2c9c' - | '\u2c9e' - | '\u2ca0' - | '\u2ca2' - | '\u2ca4' - | '\u2ca6' - | '\u2ca8' - | '\u2caa' - | '\u2cac' - | '\u2cae' - | '\u2cb0' - | '\u2cb2' - | '\u2cb4' - | '\u2cb6' - | '\u2cb8' - | '\u2cba' - | '\u2cbc' - | '\u2cbe' - | '\u2cc0' - | '\u2cc2' - | '\u2cc4' - | '\u2cc6' - | '\u2cc8' - | '\u2cca' - | '\u2ccc' - | '\u2cce' - | '\u2cd0' - | '\u2cd2' - | '\u2cd4' - | '\u2cd6' - | '\u2cd8' - | '\u2cda' - | '\u2cdc' - | '\u2cde' - | '\u2ce0' - | '\u2ce2' - | '\u2ceb' - | '\u2ced' - | '\ua640' - | '\ua642' - | '\ua644' - | '\ua646' - | '\ua648' - | '\ua64a' - | '\ua64c' - | '\ua64e' - | '\ua650' - | '\ua652' - | '\ua654' - | '\ua656' - | '\ua658' - | '\ua65a' - | '\ua65c' - | '\ua65e' - | '\ua660' - | '\ua662' - | '\ua664' - | '\ua666' - | '\ua668' - | '\ua66a' - | '\ua66c' - | '\ua680' - | '\ua682' - | '\ua684' - | '\ua686' - | '\ua688' - | '\ua68a' - | '\ua68c' - | '\ua68e' - | '\ua690' - | '\ua692' - | '\ua694' - | '\ua696' - | '\ua722' - | '\ua724' - | '\ua726' - | '\ua728' - | '\ua72a' - | '\ua72c' - | '\ua72e' - | '\ua732' - | '\ua734' - | '\ua736' - | '\ua738' - | '\ua73a' - | '\ua73c' - | '\ua73e' - | '\ua740' - | '\ua742' - | '\ua744' - | '\ua746' - | '\ua748' - | '\ua74a' - | '\ua74c' - | '\ua74e' - | '\ua750' - | '\ua752' - | '\ua754' - | '\ua756' - | '\ua758' - | '\ua75a' - | '\ua75c' - | '\ua75e' - | '\ua760' - | '\ua762' - | '\ua764' - | '\ua766' - | '\ua768' - | '\ua76a' - | '\ua76c' - | '\ua76e' - | '\ua779' - | '\ua77b' - | '\ua77d' .. '\ua77e' - | '\ua780' - | '\ua782' - | '\ua784' - | '\ua786' - | '\ua78b' - | '\ua78d' - | '\ua790' - | '\ua7a0' - | '\ua7a2' - | '\ua7a4' - | '\ua7a6' - | '\ua7a8' - | '\uff21' .. '\uff3a' - | '\U00010400' .. '\U00010427' - | '\U0001d400' .. '\U0001d419' - | '\U0001d434' .. '\U0001d44d' - | '\U0001d468' .. '\U0001d481' - | '\U0001d49c' .. '\U0001d4b5' - | '\U0001d4d0' .. '\U0001d4e9' - | '\U0001d504' .. '\U0001d51c' - | '\U0001d538' .. '\U0001d550' - | '\U0001d56c' .. '\U0001d585' - | '\U0001d5a0' .. '\U0001d5b9' - | '\U0001d5d4' .. '\U0001d5ed' - | '\U0001d608' .. '\U0001d621' - | '\U0001d63c' .. '\U0001d655' - | '\U0001d670' .. '\U0001d689' - | '\U0001d6a8' .. '\U0001d6c0' - | '\U0001d6e2' .. '\U0001d6fa' - | '\U0001d71c' .. '\U0001d734' - | '\U0001d756' .. '\U0001d76e' - | '\U0001d790' .. '\U0001d7a8' - | '\U0001d7ca' - => true, - _ => false - }; + bsearch_range_table(c, Lu_table) } + static Mc_table : &'static [(char,char)] = &[ + ('\u0903', '\u0903'), ('\u093b', '\u093b'), + ('\u093e', '\u0940'), ('\u0949', '\u094c'), + ('\u094e', '\u094f'), ('\u0982', '\u0983'), + ('\u09be', '\u09c0'), ('\u09c7', '\u09cc'), + ('\u09d7', '\u09d7'), ('\u0a03', '\u0a03'), + ('\u0a3e', '\u0a40'), ('\u0a83', '\u0a83'), + ('\u0abe', '\u0ac0'), ('\u0ac9', '\u0acc'), + ('\u0b02', '\u0b03'), ('\u0b3e', '\u0b3e'), + ('\u0b40', '\u0b40'), ('\u0b47', '\u0b4c'), + ('\u0b57', '\u0b57'), ('\u0bbe', '\u0bbf'), + ('\u0bc1', '\u0bcc'), ('\u0bd7', '\u0bd7'), + ('\u0c01', '\u0c03'), ('\u0c41', '\u0c44'), + ('\u0c82', '\u0c83'), ('\u0cbe', '\u0cbe'), + ('\u0cc0', '\u0cc4'), ('\u0cc7', '\u0ccb'), + ('\u0cd5', '\u0cd6'), ('\u0d02', '\u0d03'), + ('\u0d3e', '\u0d40'), ('\u0d46', '\u0d4c'), + ('\u0d57', '\u0d57'), ('\u0d82', '\u0d83'), + ('\u0dcf', '\u0dd1'), ('\u0dd8', '\u0df3'), + ('\u0f3e', '\u0f3f'), ('\u0f7f', '\u0f7f'), + ('\u102b', '\u102c'), ('\u1031', '\u1031'), + ('\u1038', '\u1038'), ('\u103b', '\u103c'), + ('\u1056', '\u1057'), ('\u1062', '\u1064'), + ('\u1067', '\u106d'), ('\u1083', '\u1084'), + ('\u1087', '\u108c'), ('\u108f', '\u108f'), + ('\u109a', '\u109c'), ('\u17b6', '\u17b6'), + ('\u17be', '\u17c5'), ('\u17c7', '\u17c8'), + ('\u1923', '\u1926'), ('\u1929', '\u1931'), + ('\u1933', '\u1938'), ('\u19b0', '\u19c0'), + ('\u19c8', '\u19c9'), ('\u1a19', '\u1a1b'), + ('\u1a55', '\u1a55'), ('\u1a57', '\u1a57'), + ('\u1a61', '\u1a61'), ('\u1a63', '\u1a64'), + ('\u1a6d', '\u1a72'), ('\u1b04', '\u1b04'), + ('\u1b35', '\u1b35'), ('\u1b3b', '\u1b3b'), + ('\u1b3d', '\u1b41'), ('\u1b43', '\u1b44'), + ('\u1b82', '\u1b82'), ('\u1ba1', '\u1ba1'), + ('\u1ba6', '\u1ba7'), ('\u1baa', '\u1baa'), + ('\u1bac', '\u1bad'), ('\u1be7', '\u1be7'), + ('\u1bea', '\u1bec'), ('\u1bee', '\u1bee'), + ('\u1bf2', '\u1bf3'), ('\u1c24', '\u1c2b'), + ('\u1c34', '\u1c35'), ('\u1ce1', '\u1ce1'), + ('\u1cf2', '\u1cf3'), ('\u302e', '\u302f'), + ('\ua823', '\ua824'), ('\ua827', '\ua827'), + ('\ua880', '\ua881'), ('\ua8b4', '\ua8c3'), + ('\ua952', '\ua953'), ('\ua983', '\ua983'), + ('\ua9b4', '\ua9b5'), ('\ua9ba', '\ua9bb'), + ('\ua9bd', '\ua9c0'), ('\uaa2f', '\uaa30'), + ('\uaa33', '\uaa34'), ('\uaa4d', '\uaa4d'), + ('\uaa7b', '\uaa7b'), ('\uaaeb', '\uaaeb'), + ('\uaaee', '\uaaef'), ('\uaaf5', '\uaaf5'), + ('\uabe3', '\uabe4'), ('\uabe6', '\uabe7'), + ('\uabe9', '\uabea'), ('\uabec', '\uabec'), + ('\U00011000', '\U00011000'), ('\U00011002', '\U00011002'), + ('\U00011082', '\U00011082'), ('\U000110b0', '\U000110b2'), + ('\U000110b7', '\U000110b8'), ('\U0001112c', '\U0001112c'), + ('\U00011182', '\U00011182'), ('\U000111b3', '\U000111b5'), + ('\U000111bf', '\U000111c0'), ('\U000116ac', '\U000116ac'), + ('\U000116ae', '\U000116af'), ('\U000116b6', '\U000116b6'), + ('\U00016f51', '\U00016f7e'), ('\U0001d165', '\U0001d166'), + ('\U0001d16d', '\U0001d172') + ]; + pub fn Mc(c: char) -> bool { - return match c { - '\u0903' - | '\u093b' - | '\u093e' .. '\u0940' - | '\u0949' .. '\u094c' - | '\u094e' .. '\u094f' - | '\u0982' .. '\u0983' - | '\u09be' .. '\u09c0' - | '\u09c7' .. '\u09cc' - | '\u09d7' - | '\u0a03' - | '\u0a3e' .. '\u0a40' - | '\u0a83' - | '\u0abe' .. '\u0ac0' - | '\u0ac9' .. '\u0acc' - | '\u0b02' .. '\u0b03' - | '\u0b3e' - | '\u0b40' - | '\u0b47' .. '\u0b4c' - | '\u0b57' - | '\u0bbe' .. '\u0bbf' - | '\u0bc1' .. '\u0bcc' - | '\u0bd7' - | '\u0c01' .. '\u0c03' - | '\u0c41' .. '\u0c44' - | '\u0c82' .. '\u0c83' - | '\u0cbe' - | '\u0cc0' .. '\u0cc4' - | '\u0cc7' .. '\u0ccb' - | '\u0cd5' .. '\u0cd6' - | '\u0d02' .. '\u0d03' - | '\u0d3e' .. '\u0d40' - | '\u0d46' .. '\u0d4c' - | '\u0d57' - | '\u0d82' .. '\u0d83' - | '\u0dcf' .. '\u0dd1' - | '\u0dd8' .. '\u0df3' - | '\u0f3e' .. '\u0f3f' - | '\u0f7f' - | '\u102b' .. '\u102c' - | '\u1031' - | '\u1038' - | '\u103b' .. '\u103c' - | '\u1056' .. '\u1057' - | '\u1062' .. '\u1064' - | '\u1067' .. '\u106d' - | '\u1083' .. '\u1084' - | '\u1087' .. '\u108c' - | '\u108f' - | '\u109a' .. '\u109c' - | '\u17b6' - | '\u17be' .. '\u17c5' - | '\u17c7' .. '\u17c8' - | '\u1923' .. '\u1926' - | '\u1929' .. '\u1931' - | '\u1933' .. '\u1938' - | '\u19b0' .. '\u19c0' - | '\u19c8' .. '\u19c9' - | '\u1a19' .. '\u1a1b' - | '\u1a55' - | '\u1a57' - | '\u1a61' - | '\u1a63' .. '\u1a64' - | '\u1a6d' .. '\u1a72' - | '\u1b04' - | '\u1b35' - | '\u1b3b' - | '\u1b3d' .. '\u1b41' - | '\u1b43' .. '\u1b44' - | '\u1b82' - | '\u1ba1' - | '\u1ba6' .. '\u1ba7' - | '\u1baa' - | '\u1be7' - | '\u1bea' .. '\u1bec' - | '\u1bee' - | '\u1bf2' .. '\u1bf3' - | '\u1c24' .. '\u1c2b' - | '\u1c34' .. '\u1c35' - | '\u1ce1' - | '\u1cf2' - | '\ua823' .. '\ua824' - | '\ua827' - | '\ua880' .. '\ua881' - | '\ua8b4' .. '\ua8c3' - | '\ua952' .. '\ua953' - | '\ua983' - | '\ua9b4' .. '\ua9b5' - | '\ua9ba' .. '\ua9bb' - | '\ua9bd' .. '\ua9c0' - | '\uaa2f' .. '\uaa30' - | '\uaa33' .. '\uaa34' - | '\uaa4d' - | '\uaa7b' - | '\uabe3' .. '\uabe4' - | '\uabe6' .. '\uabe7' - | '\uabe9' .. '\uabea' - | '\uabec' - | '\U00011000' - | '\U00011002' - | '\U00011082' - | '\U000110b0' .. '\U000110b2' - | '\U000110b7' .. '\U000110b8' - | '\U0001d165' .. '\U0001d166' - | '\U0001d16d' .. '\U0001d172' - => true, - _ => false - }; + bsearch_range_table(c, Mc_table) } + static Me_table : &'static [(char,char)] = &[ + ('\u0488', '\u0489'), ('\u20dd', '\u20e0'), + ('\u20e2', '\u20e4'), ('\ua670', '\ua672') + ]; + pub fn Me(c: char) -> bool { - return match c { - '\u0488' .. '\u0489' - | '\u20dd' .. '\u20e0' - | '\u20e2' .. '\u20e4' - | '\ua670' .. '\ua672' - => true, - _ => false - }; + bsearch_range_table(c, Me_table) } + static Mn_table : &'static [(char,char)] = &[ + ('\u0300', '\u036f'), ('\u0483', '\u0487'), + ('\u0591', '\u05bd'), ('\u05bf', '\u05bf'), + ('\u05c1', '\u05c2'), ('\u05c4', '\u05c5'), + ('\u05c7', '\u05c7'), ('\u0610', '\u061a'), + ('\u064b', '\u065f'), ('\u0670', '\u0670'), + ('\u06d6', '\u06dc'), ('\u06df', '\u06e4'), + ('\u06e7', '\u06e8'), ('\u06ea', '\u06ed'), + ('\u0711', '\u0711'), ('\u0730', '\u074a'), + ('\u07a6', '\u07b0'), ('\u07eb', '\u07f3'), + ('\u0816', '\u0819'), ('\u081b', '\u0823'), + ('\u0825', '\u0827'), ('\u0829', '\u082d'), + ('\u0859', '\u085b'), ('\u08e4', '\u0902'), + ('\u093a', '\u093a'), ('\u093c', '\u093c'), + ('\u0941', '\u0948'), ('\u094d', '\u094d'), + ('\u0951', '\u0957'), ('\u0962', '\u0963'), + ('\u0981', '\u0981'), ('\u09bc', '\u09bc'), + ('\u09c1', '\u09c4'), ('\u09cd', '\u09cd'), + ('\u09e2', '\u09e3'), ('\u0a01', '\u0a02'), + ('\u0a3c', '\u0a3c'), ('\u0a41', '\u0a51'), + ('\u0a70', '\u0a71'), ('\u0a75', '\u0a82'), + ('\u0abc', '\u0abc'), ('\u0ac1', '\u0ac8'), + ('\u0acd', '\u0acd'), ('\u0ae2', '\u0ae3'), + ('\u0b01', '\u0b01'), ('\u0b3c', '\u0b3c'), + ('\u0b3f', '\u0b3f'), ('\u0b41', '\u0b44'), + ('\u0b4d', '\u0b56'), ('\u0b62', '\u0b63'), + ('\u0b82', '\u0b82'), ('\u0bc0', '\u0bc0'), + ('\u0bcd', '\u0bcd'), ('\u0c3e', '\u0c40'), + ('\u0c46', '\u0c56'), ('\u0c62', '\u0c63'), + ('\u0cbc', '\u0cbc'), ('\u0cbf', '\u0cbf'), + ('\u0cc6', '\u0cc6'), ('\u0ccc', '\u0ccd'), + ('\u0ce2', '\u0ce3'), ('\u0d41', '\u0d44'), + ('\u0d4d', '\u0d4d'), ('\u0d62', '\u0d63'), + ('\u0dca', '\u0dca'), ('\u0dd2', '\u0dd6'), + ('\u0e31', '\u0e31'), ('\u0e34', '\u0e3a'), + ('\u0e47', '\u0e4e'), ('\u0eb1', '\u0eb1'), + ('\u0eb4', '\u0ebc'), ('\u0ec8', '\u0ecd'), + ('\u0f18', '\u0f19'), ('\u0f35', '\u0f35'), + ('\u0f37', '\u0f37'), ('\u0f39', '\u0f39'), + ('\u0f71', '\u0f7e'), ('\u0f80', '\u0f84'), + ('\u0f86', '\u0f87'), ('\u0f8d', '\u0fbc'), + ('\u0fc6', '\u0fc6'), ('\u102d', '\u1030'), + ('\u1032', '\u1037'), ('\u1039', '\u103a'), + ('\u103d', '\u103e'), ('\u1058', '\u1059'), + ('\u105e', '\u1060'), ('\u1071', '\u1074'), + ('\u1082', '\u1082'), ('\u1085', '\u1086'), + ('\u108d', '\u108d'), ('\u109d', '\u109d'), + ('\u135d', '\u135f'), ('\u1712', '\u1714'), + ('\u1732', '\u1734'), ('\u1752', '\u1753'), + ('\u1772', '\u1773'), ('\u17b4', '\u17b5'), + ('\u17b7', '\u17bd'), ('\u17c6', '\u17c6'), + ('\u17c9', '\u17d3'), ('\u17dd', '\u17dd'), + ('\u180b', '\u180d'), ('\u18a9', '\u18a9'), + ('\u1920', '\u1922'), ('\u1927', '\u1928'), + ('\u1932', '\u1932'), ('\u1939', '\u193b'), + ('\u1a17', '\u1a18'), ('\u1a56', '\u1a56'), + ('\u1a58', '\u1a60'), ('\u1a62', '\u1a62'), + ('\u1a65', '\u1a6c'), ('\u1a73', '\u1a7f'), + ('\u1b00', '\u1b03'), ('\u1b34', '\u1b34'), + ('\u1b36', '\u1b3a'), ('\u1b3c', '\u1b3c'), + ('\u1b42', '\u1b42'), ('\u1b6b', '\u1b73'), + ('\u1b80', '\u1b81'), ('\u1ba2', '\u1ba5'), + ('\u1ba8', '\u1ba9'), ('\u1bab', '\u1bab'), + ('\u1be6', '\u1be6'), ('\u1be8', '\u1be9'), + ('\u1bed', '\u1bed'), ('\u1bef', '\u1bf1'), + ('\u1c2c', '\u1c33'), ('\u1c36', '\u1c37'), + ('\u1cd0', '\u1cd2'), ('\u1cd4', '\u1ce0'), + ('\u1ce2', '\u1ce8'), ('\u1ced', '\u1ced'), + ('\u1cf4', '\u1cf4'), ('\u1dc0', '\u1dff'), + ('\u20d0', '\u20dc'), ('\u20e1', '\u20e1'), + ('\u20e5', '\u20f0'), ('\u2cef', '\u2cf1'), + ('\u2d7f', '\u2d7f'), ('\u2de0', '\u2dff'), + ('\u302a', '\u302d'), ('\u3099', '\u309a'), + ('\ua66f', '\ua66f'), ('\ua674', '\ua67d'), + ('\ua69f', '\ua69f'), ('\ua6f0', '\ua6f1'), + ('\ua802', '\ua802'), ('\ua806', '\ua806'), + ('\ua80b', '\ua80b'), ('\ua825', '\ua826'), + ('\ua8c4', '\ua8c4'), ('\ua8e0', '\ua8f1'), + ('\ua926', '\ua92d'), ('\ua947', '\ua951'), + ('\ua980', '\ua982'), ('\ua9b3', '\ua9b3'), + ('\ua9b6', '\ua9b9'), ('\ua9bc', '\ua9bc'), + ('\uaa29', '\uaa2e'), ('\uaa31', '\uaa32'), + ('\uaa35', '\uaa36'), ('\uaa43', '\uaa43'), + ('\uaa4c', '\uaa4c'), ('\uaab0', '\uaab0'), + ('\uaab2', '\uaab4'), ('\uaab7', '\uaab8'), + ('\uaabe', '\uaabf'), ('\uaac1', '\uaac1'), + ('\uaaec', '\uaaed'), ('\uaaf6', '\uaaf6'), + ('\uabe5', '\uabe5'), ('\uabe8', '\uabe8'), + ('\uabed', '\uabed'), ('\ufb1e', '\ufb1e'), + ('\ufe00', '\ufe0f'), ('\ufe20', '\ufe26'), + ('\U000101fd', '\U000101fd'), ('\U00010a01', '\U00010a0f'), + ('\U00010a38', '\U00010a3f'), ('\U00011001', '\U00011001'), + ('\U00011038', '\U00011046'), ('\U00011080', '\U00011081'), + ('\U000110b3', '\U000110b6'), ('\U000110b9', '\U000110ba'), + ('\U00011100', '\U00011102'), ('\U00011127', '\U0001112b'), + ('\U0001112d', '\U00011134'), ('\U00011180', '\U00011181'), + ('\U000111b6', '\U000111be'), ('\U000116ab', '\U000116ab'), + ('\U000116ad', '\U000116ad'), ('\U000116b0', '\U000116b5'), + ('\U000116b7', '\U000116b7'), ('\U00016f8f', '\U00016f92'), + ('\U0001d167', '\U0001d169'), ('\U0001d17b', '\U0001d182'), + ('\U0001d185', '\U0001d18b'), ('\U0001d1aa', '\U0001d1ad'), + ('\U0001d242', '\U0001d244'), ('\U000e0100', '\U000e01ef') + ]; + pub fn Mn(c: char) -> bool { - return match c { - '\u0300' .. '\u036f' - | '\u0483' .. '\u0487' - | '\u0591' .. '\u05bd' - | '\u05bf' - | '\u05c1' .. '\u05c2' - | '\u05c4' .. '\u05c5' - | '\u05c7' - | '\u0610' .. '\u061a' - | '\u064b' .. '\u065f' - | '\u0670' - | '\u06d6' .. '\u06dc' - | '\u06df' .. '\u06e4' - | '\u06e7' .. '\u06e8' - | '\u06ea' .. '\u06ed' - | '\u0711' - | '\u0730' .. '\u074a' - | '\u07a6' .. '\u07b0' - | '\u07eb' .. '\u07f3' - | '\u0816' .. '\u0819' - | '\u081b' .. '\u0823' - | '\u0825' .. '\u0827' - | '\u0829' .. '\u082d' - | '\u0859' .. '\u085b' - | '\u0900' .. '\u0902' - | '\u093a' - | '\u093c' - | '\u0941' .. '\u0948' - | '\u094d' - | '\u0951' .. '\u0957' - | '\u0962' .. '\u0963' - | '\u0981' - | '\u09bc' - | '\u09c1' .. '\u09c4' - | '\u09cd' - | '\u09e2' .. '\u09e3' - | '\u0a01' .. '\u0a02' - | '\u0a3c' - | '\u0a41' .. '\u0a51' - | '\u0a70' .. '\u0a71' - | '\u0a75' .. '\u0a82' - | '\u0abc' - | '\u0ac1' .. '\u0ac8' - | '\u0acd' - | '\u0ae2' .. '\u0ae3' - | '\u0b01' - | '\u0b3c' - | '\u0b3f' - | '\u0b41' .. '\u0b44' - | '\u0b4d' .. '\u0b56' - | '\u0b62' .. '\u0b63' - | '\u0b82' - | '\u0bc0' - | '\u0bcd' - | '\u0c3e' .. '\u0c40' - | '\u0c46' .. '\u0c56' - | '\u0c62' .. '\u0c63' - | '\u0cbc' - | '\u0cbf' - | '\u0cc6' - | '\u0ccc' .. '\u0ccd' - | '\u0ce2' .. '\u0ce3' - | '\u0d41' .. '\u0d44' - | '\u0d4d' - | '\u0d62' .. '\u0d63' - | '\u0dca' - | '\u0dd2' .. '\u0dd6' - | '\u0e31' - | '\u0e34' .. '\u0e3a' - | '\u0e47' .. '\u0e4e' - | '\u0eb1' - | '\u0eb4' .. '\u0ebc' - | '\u0ec8' .. '\u0ecd' - | '\u0f18' .. '\u0f19' - | '\u0f35' - | '\u0f37' - | '\u0f39' - | '\u0f71' .. '\u0f7e' - | '\u0f80' .. '\u0f84' - | '\u0f86' .. '\u0f87' - | '\u0f8d' .. '\u0fbc' - | '\u0fc6' - | '\u102d' .. '\u1030' - | '\u1032' .. '\u1037' - | '\u1039' .. '\u103a' - | '\u103d' .. '\u103e' - | '\u1058' .. '\u1059' - | '\u105e' .. '\u1060' - | '\u1071' .. '\u1074' - | '\u1082' - | '\u1085' .. '\u1086' - | '\u108d' - | '\u109d' - | '\u135d' .. '\u135f' - | '\u1712' .. '\u1714' - | '\u1732' .. '\u1734' - | '\u1752' .. '\u1753' - | '\u1772' .. '\u1773' - | '\u17b7' .. '\u17bd' - | '\u17c6' - | '\u17c9' .. '\u17d3' - | '\u17dd' - | '\u180b' .. '\u180d' - | '\u18a9' - | '\u1920' .. '\u1922' - | '\u1927' .. '\u1928' - | '\u1932' - | '\u1939' .. '\u193b' - | '\u1a17' .. '\u1a18' - | '\u1a56' - | '\u1a58' .. '\u1a60' - | '\u1a62' - | '\u1a65' .. '\u1a6c' - | '\u1a73' .. '\u1a7f' - | '\u1b00' .. '\u1b03' - | '\u1b34' - | '\u1b36' .. '\u1b3a' - | '\u1b3c' - | '\u1b42' - | '\u1b6b' .. '\u1b73' - | '\u1b80' .. '\u1b81' - | '\u1ba2' .. '\u1ba5' - | '\u1ba8' .. '\u1ba9' - | '\u1be6' - | '\u1be8' .. '\u1be9' - | '\u1bed' - | '\u1bef' .. '\u1bf1' - | '\u1c2c' .. '\u1c33' - | '\u1c36' .. '\u1c37' - | '\u1cd0' .. '\u1cd2' - | '\u1cd4' .. '\u1ce0' - | '\u1ce2' .. '\u1ce8' - | '\u1ced' - | '\u1dc0' .. '\u1dff' - | '\u20d0' .. '\u20dc' - | '\u20e1' - | '\u20e5' .. '\u20f0' - | '\u2cef' .. '\u2cf1' - | '\u2d7f' - | '\u2de0' .. '\u2dff' - | '\u302a' .. '\u302f' - | '\u3099' .. '\u309a' - | '\ua66f' - | '\ua67c' .. '\ua67d' - | '\ua6f0' .. '\ua6f1' - | '\ua802' - | '\ua806' - | '\ua80b' - | '\ua825' .. '\ua826' - | '\ua8c4' - | '\ua8e0' .. '\ua8f1' - | '\ua926' .. '\ua92d' - | '\ua947' .. '\ua951' - | '\ua980' .. '\ua982' - | '\ua9b3' - | '\ua9b6' .. '\ua9b9' - | '\ua9bc' - | '\uaa29' .. '\uaa2e' - | '\uaa31' .. '\uaa32' - | '\uaa35' .. '\uaa36' - | '\uaa43' - | '\uaa4c' - | '\uaab0' - | '\uaab2' .. '\uaab4' - | '\uaab7' .. '\uaab8' - | '\uaabe' .. '\uaabf' - | '\uaac1' - | '\uabe5' - | '\uabe8' - | '\uabed' - | '\ufb1e' - | '\ufe00' .. '\ufe0f' - | '\ufe20' .. '\ufe26' - | '\U000101fd' - | '\U00010a01' .. '\U00010a0f' - | '\U00010a38' .. '\U00010a3f' - | '\U00011001' - | '\U00011038' .. '\U00011046' - | '\U00011080' .. '\U00011081' - | '\U000110b3' .. '\U000110b6' - | '\U000110b9' .. '\U000110ba' - | '\U0001d167' .. '\U0001d169' - | '\U0001d17b' .. '\U0001d182' - | '\U0001d185' .. '\U0001d18b' - | '\U0001d1aa' .. '\U0001d1ad' - | '\U0001d242' .. '\U0001d244' - | '\U000e0100' .. '\U000e01ef' - => true, - _ => false - }; + bsearch_range_table(c, Mn_table) } + static Nd_table : &'static [(char,char)] = &[ + ('\x30', '\x39'), ('\u0660', '\u0669'), + ('\u06f0', '\u06f9'), ('\u07c0', '\u07c9'), + ('\u0966', '\u096f'), ('\u09e6', '\u09ef'), + ('\u0a66', '\u0a6f'), ('\u0ae6', '\u0aef'), + ('\u0b66', '\u0b6f'), ('\u0be6', '\u0bef'), + ('\u0c66', '\u0c6f'), ('\u0ce6', '\u0cef'), + ('\u0d66', '\u0d6f'), ('\u0e50', '\u0e59'), + ('\u0ed0', '\u0ed9'), ('\u0f20', '\u0f29'), + ('\u1040', '\u1049'), ('\u1090', '\u1099'), + ('\u17e0', '\u17e9'), ('\u1810', '\u1819'), + ('\u1946', '\u194f'), ('\u19d0', '\u19d9'), + ('\u1a80', '\u1a99'), ('\u1b50', '\u1b59'), + ('\u1bb0', '\u1bb9'), ('\u1c40', '\u1c49'), + ('\u1c50', '\u1c59'), ('\ua620', '\ua629'), + ('\ua8d0', '\ua8d9'), ('\ua900', '\ua909'), + ('\ua9d0', '\ua9d9'), ('\uaa50', '\uaa59'), + ('\uabf0', '\uabf9'), ('\uff10', '\uff19'), + ('\U000104a0', '\U000104a9'), ('\U00011066', '\U0001106f'), + ('\U000110f0', '\U000110f9'), ('\U00011136', '\U0001113f'), + ('\U000111d0', '\U000111d9'), ('\U000116c0', '\U000116c9'), + ('\U0001d7ce', '\U0001d7ff') + ]; + pub fn Nd(c: char) -> bool { - return match c { - '\x30' .. '\x39' - | '\u0660' .. '\u0669' - | '\u06f0' .. '\u06f9' - | '\u07c0' .. '\u07c9' - | '\u0966' .. '\u096f' - | '\u09e6' .. '\u09ef' - | '\u0a66' .. '\u0a6f' - | '\u0ae6' .. '\u0aef' - | '\u0b66' .. '\u0b6f' - | '\u0be6' .. '\u0bef' - | '\u0c66' .. '\u0c6f' - | '\u0ce6' .. '\u0cef' - | '\u0d66' .. '\u0d6f' - | '\u0e50' .. '\u0e59' - | '\u0ed0' .. '\u0ed9' - | '\u0f20' .. '\u0f29' - | '\u1040' .. '\u1049' - | '\u1090' .. '\u1099' - | '\u17e0' .. '\u17e9' - | '\u1810' .. '\u1819' - | '\u1946' .. '\u194f' - | '\u19d0' .. '\u19d9' - | '\u1a80' .. '\u1a99' - | '\u1b50' .. '\u1b59' - | '\u1bb0' .. '\u1bb9' - | '\u1c40' .. '\u1c49' - | '\u1c50' .. '\u1c59' - | '\ua620' .. '\ua629' - | '\ua8d0' .. '\ua8d9' - | '\ua900' .. '\ua909' - | '\ua9d0' .. '\ua9d9' - | '\uaa50' .. '\uaa59' - | '\uabf0' .. '\uabf9' - | '\uff10' .. '\uff19' - | '\U000104a0' .. '\U000104a9' - | '\U00011066' .. '\U0001106f' - | '\U0001d7ce' .. '\U0001d7ff' - => true, - _ => false - }; + bsearch_range_table(c, Nd_table) } + static Nl_table : &'static [(char,char)] = &[ + ('\u16ee', '\u16f0'), ('\u2160', '\u2182'), + ('\u2185', '\u2188'), ('\u3007', '\u3007'), + ('\u3021', '\u3029'), ('\u3038', '\u303a'), + ('\ua6e6', '\ua6ef'), ('\U00010140', '\U00010174'), + ('\U00010341', '\U00010341'), ('\U0001034a', '\U0001034a'), + ('\U000103d1', '\U000103d5'), ('\U00012400', '\U00012462') + ]; + pub fn Nl(c: char) -> bool { - return match c { - '\u16ee' .. '\u16f0' - | '\u2160' .. '\u2182' - | '\u2185' .. '\u2188' - | '\u3007' - | '\u3021' .. '\u3029' - | '\u3038' .. '\u303a' - | '\ua6e6' .. '\ua6ef' - | '\U00010140' .. '\U00010174' - | '\U00010341' - | '\U0001034a' - | '\U000103d1' .. '\U000103d5' - | '\U00012400' .. '\U00012462' - => true, - _ => false - }; + bsearch_range_table(c, Nl_table) } + static No_table : &'static [(char,char)] = &[ + ('\xb2', '\xb3'), ('\xb9', '\xb9'), + ('\xbc', '\xbe'), ('\u09f4', '\u09f9'), + ('\u0b72', '\u0b77'), ('\u0bf0', '\u0bf2'), + ('\u0c78', '\u0c7e'), ('\u0d70', '\u0d75'), + ('\u0f2a', '\u0f33'), ('\u1369', '\u137c'), + ('\u17f0', '\u17f9'), ('\u19da', '\u19da'), + ('\u2070', '\u2070'), ('\u2074', '\u2079'), + ('\u2080', '\u2089'), ('\u2150', '\u215f'), + ('\u2189', '\u2189'), ('\u2460', '\u249b'), + ('\u24ea', '\u24ff'), ('\u2776', '\u2793'), + ('\u2cfd', '\u2cfd'), ('\u3192', '\u3195'), + ('\u3220', '\u3229'), ('\u3248', '\u324f'), + ('\u3251', '\u325f'), ('\u3280', '\u3289'), + ('\u32b1', '\u32bf'), ('\ua830', '\ua835'), + ('\U00010107', '\U00010133'), ('\U00010175', '\U00010178'), + ('\U0001018a', '\U0001018a'), ('\U00010320', '\U00010323'), + ('\U00010858', '\U0001085f'), ('\U00010916', '\U0001091b'), + ('\U00010a40', '\U00010a47'), ('\U00010a7d', '\U00010a7e'), + ('\U00010b58', '\U00010b5f'), ('\U00010b78', '\U00010b7f'), + ('\U00010e60', '\U00010e7e'), ('\U00011052', '\U00011065'), + ('\U0001d360', '\U0001d371'), ('\U0001f100', '\U0001f10a') + ]; + pub fn No(c: char) -> bool { - return match c { - '\xb2' .. '\xb3' - | '\xb9' - | '\xbc' .. '\xbe' - | '\u09f4' .. '\u09f9' - | '\u0b72' .. '\u0b77' - | '\u0bf0' .. '\u0bf2' - | '\u0c78' .. '\u0c7e' - | '\u0d70' .. '\u0d75' - | '\u0f2a' .. '\u0f33' - | '\u1369' .. '\u137c' - | '\u17f0' .. '\u17f9' - | '\u19da' - | '\u2070' - | '\u2074' .. '\u2079' - | '\u2080' .. '\u2089' - | '\u2150' .. '\u215f' - | '\u2189' - | '\u2460' .. '\u249b' - | '\u24ea' .. '\u24ff' - | '\u2776' .. '\u2793' - | '\u2cfd' - | '\u3192' .. '\u3195' - | '\u3220' .. '\u3229' - | '\u3251' .. '\u325f' - | '\u3280' .. '\u3289' - | '\u32b1' .. '\u32bf' - | '\ua830' .. '\ua835' - | '\U00010107' .. '\U00010133' - | '\U00010175' .. '\U00010178' - | '\U0001018a' - | '\U00010320' .. '\U00010323' - | '\U00010858' .. '\U0001085f' - | '\U00010916' .. '\U0001091b' - | '\U00010a40' .. '\U00010a47' - | '\U00010a7d' .. '\U00010a7e' - | '\U00010b58' .. '\U00010b5f' - | '\U00010b78' .. '\U00010b7f' - | '\U00010e60' .. '\U00010e7e' - | '\U00011052' .. '\U00011065' - | '\U0001d360' .. '\U0001d371' - | '\U0001f100' .. '\U0001f10a' - => true, - _ => false - }; + bsearch_range_table(c, No_table) } + static Pc_table : &'static [(char,char)] = &[ + ('\x5f', '\x5f'), ('\u203f', '\u2040'), + ('\u2054', '\u2054'), ('\ufe33', '\ufe34'), + ('\ufe4d', '\ufe4f'), ('\uff3f', '\uff3f') + ]; + pub fn Pc(c: char) -> bool { - return match c { - '\x5f' - | '\u203f' .. '\u2040' - | '\u2054' - | '\ufe33' .. '\ufe34' - | '\ufe4d' .. '\ufe4f' - | '\uff3f' - => true, - _ => false - }; + bsearch_range_table(c, Pc_table) } + static Pd_table : &'static [(char,char)] = &[ + ('\x2d', '\x2d'), ('\u058a', '\u058a'), + ('\u05be', '\u05be'), ('\u1400', '\u1400'), + ('\u1806', '\u1806'), ('\u2010', '\u2015'), + ('\u2e17', '\u2e17'), ('\u2e1a', '\u2e1a'), + ('\u2e3a', '\u2e3b'), ('\u301c', '\u301c'), + ('\u3030', '\u3030'), ('\u30a0', '\u30a0'), + ('\ufe31', '\ufe32'), ('\ufe58', '\ufe58'), + ('\ufe63', '\ufe63'), ('\uff0d', '\uff0d') + ]; + pub fn Pd(c: char) -> bool { - return match c { - '\x2d' - | '\u058a' - | '\u05be' - | '\u1400' - | '\u1806' - | '\u2010' .. '\u2015' - | '\u2e17' - | '\u2e1a' - | '\u301c' - | '\u3030' - | '\u30a0' - | '\ufe31' .. '\ufe32' - | '\ufe58' - | '\ufe63' - | '\uff0d' - => true, - _ => false - }; + bsearch_range_table(c, Pd_table) } + static Pe_table : &'static [(char,char)] = &[ + ('\x29', '\x29'), ('\x5d', '\x5d'), + ('\x7d', '\x7d'), ('\u0f3b', '\u0f3b'), + ('\u0f3d', '\u0f3d'), ('\u169c', '\u169c'), + ('\u2046', '\u2046'), ('\u207e', '\u207e'), + ('\u208e', '\u208e'), ('\u232a', '\u232a'), + ('\u2769', '\u2769'), ('\u276b', '\u276b'), + ('\u276d', '\u276d'), ('\u276f', '\u276f'), + ('\u2771', '\u2771'), ('\u2773', '\u2773'), + ('\u2775', '\u2775'), ('\u27c6', '\u27c6'), + ('\u27e7', '\u27e7'), ('\u27e9', '\u27e9'), + ('\u27eb', '\u27eb'), ('\u27ed', '\u27ed'), + ('\u27ef', '\u27ef'), ('\u2984', '\u2984'), + ('\u2986', '\u2986'), ('\u2988', '\u2988'), + ('\u298a', '\u298a'), ('\u298c', '\u298c'), + ('\u298e', '\u298e'), ('\u2990', '\u2990'), + ('\u2992', '\u2992'), ('\u2994', '\u2994'), + ('\u2996', '\u2996'), ('\u2998', '\u2998'), + ('\u29d9', '\u29d9'), ('\u29db', '\u29db'), + ('\u29fd', '\u29fd'), ('\u2e23', '\u2e23'), + ('\u2e25', '\u2e25'), ('\u2e27', '\u2e27'), + ('\u2e29', '\u2e29'), ('\u3009', '\u3009'), + ('\u300b', '\u300b'), ('\u300d', '\u300d'), + ('\u300f', '\u300f'), ('\u3011', '\u3011'), + ('\u3015', '\u3015'), ('\u3017', '\u3017'), + ('\u3019', '\u3019'), ('\u301b', '\u301b'), + ('\u301e', '\u301f'), ('\ufd3f', '\ufd3f'), + ('\ufe18', '\ufe18'), ('\ufe36', '\ufe36'), + ('\ufe38', '\ufe38'), ('\ufe3a', '\ufe3a'), + ('\ufe3c', '\ufe3c'), ('\ufe3e', '\ufe3e'), + ('\ufe40', '\ufe40'), ('\ufe42', '\ufe42'), + ('\ufe44', '\ufe44'), ('\ufe48', '\ufe48'), + ('\ufe5a', '\ufe5a'), ('\ufe5c', '\ufe5c'), + ('\ufe5e', '\ufe5e'), ('\uff09', '\uff09'), + ('\uff3d', '\uff3d'), ('\uff5d', '\uff5d'), + ('\uff60', '\uff60'), ('\uff63', '\uff63') + ]; + pub fn Pe(c: char) -> bool { - return match c { - '\x29' - | '\x5d' - | '\x7d' - | '\u0f3b' - | '\u0f3d' - | '\u169c' - | '\u2046' - | '\u207e' - | '\u208e' - | '\u232a' - | '\u2769' - | '\u276b' - | '\u276d' - | '\u276f' - | '\u2771' - | '\u2773' - | '\u2775' - | '\u27c6' - | '\u27e7' - | '\u27e9' - | '\u27eb' - | '\u27ed' - | '\u27ef' - | '\u2984' - | '\u2986' - | '\u2988' - | '\u298a' - | '\u298c' - | '\u298e' - | '\u2990' - | '\u2992' - | '\u2994' - | '\u2996' - | '\u2998' - | '\u29d9' - | '\u29db' - | '\u29fd' - | '\u2e23' - | '\u2e25' - | '\u2e27' - | '\u2e29' - | '\u3009' - | '\u300b' - | '\u300d' - | '\u300f' - | '\u3011' - | '\u3015' - | '\u3017' - | '\u3019' - | '\u301b' - | '\u301e' .. '\u301f' - | '\ufd3f' - | '\ufe18' - | '\ufe36' - | '\ufe38' - | '\ufe3a' - | '\ufe3c' - | '\ufe3e' - | '\ufe40' - | '\ufe42' - | '\ufe44' - | '\ufe48' - | '\ufe5a' - | '\ufe5c' - | '\ufe5e' - | '\uff09' - | '\uff3d' - | '\uff5d' - | '\uff60' - | '\uff63' - => true, - _ => false - }; + bsearch_range_table(c, Pe_table) } + static Pf_table : &'static [(char,char)] = &[ + ('\xbb', '\xbb'), ('\u2019', '\u2019'), + ('\u201d', '\u201d'), ('\u203a', '\u203a'), + ('\u2e03', '\u2e03'), ('\u2e05', '\u2e05'), + ('\u2e0a', '\u2e0a'), ('\u2e0d', '\u2e0d'), + ('\u2e1d', '\u2e1d'), ('\u2e21', '\u2e21') + ]; + pub fn Pf(c: char) -> bool { - return match c { - '\xbb' - | '\u2019' - | '\u201d' - | '\u203a' - | '\u2e03' - | '\u2e05' - | '\u2e0a' - | '\u2e0d' - | '\u2e1d' - | '\u2e21' - => true, - _ => false - }; + bsearch_range_table(c, Pf_table) } + static Pi_table : &'static [(char,char)] = &[ + ('\xab', '\xab'), ('\u2018', '\u2018'), + ('\u201b', '\u201c'), ('\u201f', '\u201f'), + ('\u2039', '\u2039'), ('\u2e02', '\u2e02'), + ('\u2e04', '\u2e04'), ('\u2e09', '\u2e09'), + ('\u2e0c', '\u2e0c'), ('\u2e1c', '\u2e1c'), + ('\u2e20', '\u2e20') + ]; + pub fn Pi(c: char) -> bool { - return match c { - '\xab' - | '\u2018' - | '\u201b' .. '\u201c' - | '\u201f' - | '\u2039' - | '\u2e02' - | '\u2e04' - | '\u2e09' - | '\u2e0c' - | '\u2e1c' - | '\u2e20' - => true, - _ => false - }; + bsearch_range_table(c, Pi_table) } + static Po_table : &'static [(char,char)] = &[ + ('\x21', '\x23'), ('\x25', '\x27'), + ('\x2a', '\x2a'), ('\x2c', '\x2c'), + ('\x2e', '\x2f'), ('\x3a', '\x3b'), + ('\x3f', '\x40'), ('\x5c', '\x5c'), + ('\xa1', '\xa1'), ('\xa7', '\xa7'), + ('\xb6', '\xb7'), ('\xbf', '\xbf'), + ('\u037e', '\u037e'), ('\u0387', '\u0387'), + ('\u055a', '\u055f'), ('\u0589', '\u0589'), + ('\u05c0', '\u05c0'), ('\u05c3', '\u05c3'), + ('\u05c6', '\u05c6'), ('\u05f3', '\u05f4'), + ('\u0609', '\u060a'), ('\u060c', '\u060d'), + ('\u061b', '\u061f'), ('\u066a', '\u066d'), + ('\u06d4', '\u06d4'), ('\u0700', '\u070d'), + ('\u07f7', '\u07f9'), ('\u0830', '\u083e'), + ('\u085e', '\u085e'), ('\u0964', '\u0965'), + ('\u0970', '\u0970'), ('\u0af0', '\u0af0'), + ('\u0df4', '\u0df4'), ('\u0e4f', '\u0e4f'), + ('\u0e5a', '\u0e5b'), ('\u0f04', '\u0f12'), + ('\u0f14', '\u0f14'), ('\u0f85', '\u0f85'), + ('\u0fd0', '\u0fd4'), ('\u0fd9', '\u0fda'), + ('\u104a', '\u104f'), ('\u10fb', '\u10fb'), + ('\u1360', '\u1368'), ('\u166d', '\u166e'), + ('\u16eb', '\u16ed'), ('\u1735', '\u1736'), + ('\u17d4', '\u17d6'), ('\u17d8', '\u17da'), + ('\u1800', '\u1805'), ('\u1807', '\u180a'), + ('\u1944', '\u1945'), ('\u1a1e', '\u1a1f'), + ('\u1aa0', '\u1aa6'), ('\u1aa8', '\u1aad'), + ('\u1b5a', '\u1b60'), ('\u1bfc', '\u1bff'), + ('\u1c3b', '\u1c3f'), ('\u1c7e', '\u1cc7'), + ('\u1cd3', '\u1cd3'), ('\u2016', '\u2017'), + ('\u2020', '\u2027'), ('\u2030', '\u2038'), + ('\u203b', '\u203e'), ('\u2041', '\u2043'), + ('\u2047', '\u2051'), ('\u2053', '\u2053'), + ('\u2055', '\u205e'), ('\u2cf9', '\u2cfc'), + ('\u2cfe', '\u2cff'), ('\u2d70', '\u2d70'), + ('\u2e00', '\u2e01'), ('\u2e06', '\u2e08'), + ('\u2e0b', '\u2e0b'), ('\u2e0e', '\u2e16'), + ('\u2e18', '\u2e19'), ('\u2e1b', '\u2e1b'), + ('\u2e1e', '\u2e1f'), ('\u2e2a', '\u2e2e'), + ('\u2e30', '\u2e39'), ('\u3001', '\u3003'), + ('\u303d', '\u303d'), ('\u30fb', '\u30fb'), + ('\ua4fe', '\ua4ff'), ('\ua60d', '\ua60f'), + ('\ua673', '\ua673'), ('\ua67e', '\ua67e'), + ('\ua6f2', '\ua6f7'), ('\ua874', '\ua877'), + ('\ua8ce', '\ua8cf'), ('\ua8f8', '\ua8fa'), + ('\ua92e', '\ua92f'), ('\ua95f', '\ua95f'), + ('\ua9c1', '\ua9cd'), ('\ua9de', '\ua9df'), + ('\uaa5c', '\uaa5f'), ('\uaade', '\uaadf'), + ('\uaaf0', '\uaaf1'), ('\uabeb', '\uabeb'), + ('\ufe10', '\ufe16'), ('\ufe19', '\ufe19'), + ('\ufe30', '\ufe30'), ('\ufe45', '\ufe46'), + ('\ufe49', '\ufe4c'), ('\ufe50', '\ufe57'), + ('\ufe5f', '\ufe61'), ('\ufe68', '\ufe68'), + ('\ufe6a', '\ufe6b'), ('\uff01', '\uff03'), + ('\uff05', '\uff07'), ('\uff0a', '\uff0a'), + ('\uff0c', '\uff0c'), ('\uff0e', '\uff0f'), + ('\uff1a', '\uff1b'), ('\uff1f', '\uff20'), + ('\uff3c', '\uff3c'), ('\uff61', '\uff61'), + ('\uff64', '\uff65'), ('\U00010100', '\U00010102'), + ('\U0001039f', '\U0001039f'), ('\U000103d0', '\U000103d0'), + ('\U00010857', '\U00010857'), ('\U0001091f', '\U0001091f'), + ('\U0001093f', '\U0001093f'), ('\U00010a50', '\U00010a58'), + ('\U00010a7f', '\U00010a7f'), ('\U00010b39', '\U00010b3f'), + ('\U00011047', '\U0001104d'), ('\U000110bb', '\U000110bc'), + ('\U000110be', '\U000110c1'), ('\U00011140', '\U00011143'), + ('\U000111c5', '\U000111c8'), ('\U00012470', '\U00012473') + ]; + pub fn Po(c: char) -> bool { - return match c { - '\x21' .. '\x23' - | '\x25' .. '\x27' - | '\x2a' - | '\x2c' - | '\x2e' .. '\x2f' - | '\x3a' .. '\x3b' - | '\x3f' .. '\x40' - | '\x5c' - | '\xa1' - | '\xb7' - | '\xbf' - | '\u037e' - | '\u0387' - | '\u055a' .. '\u055f' - | '\u0589' - | '\u05c0' - | '\u05c3' - | '\u05c6' - | '\u05f3' .. '\u05f4' - | '\u0609' .. '\u060a' - | '\u060c' .. '\u060d' - | '\u061b' .. '\u061f' - | '\u066a' .. '\u066d' - | '\u06d4' - | '\u0700' .. '\u070d' - | '\u07f7' .. '\u07f9' - | '\u0830' .. '\u083e' - | '\u085e' - | '\u0964' .. '\u0965' - | '\u0970' - | '\u0df4' - | '\u0e4f' - | '\u0e5a' .. '\u0e5b' - | '\u0f04' .. '\u0f12' - | '\u0f85' - | '\u0fd0' .. '\u0fd4' - | '\u0fd9' .. '\u0fda' - | '\u104a' .. '\u104f' - | '\u10fb' - | '\u1361' .. '\u1368' - | '\u166d' .. '\u166e' - | '\u16eb' .. '\u16ed' - | '\u1735' .. '\u1736' - | '\u17d4' .. '\u17d6' - | '\u17d8' .. '\u17da' - | '\u1800' .. '\u1805' - | '\u1807' .. '\u180a' - | '\u1944' .. '\u1945' - | '\u1a1e' .. '\u1a1f' - | '\u1aa0' .. '\u1aa6' - | '\u1aa8' .. '\u1aad' - | '\u1b5a' .. '\u1b60' - | '\u1bfc' .. '\u1bff' - | '\u1c3b' .. '\u1c3f' - | '\u1c7e' .. '\u1c7f' - | '\u1cd3' - | '\u2016' .. '\u2017' - | '\u2020' .. '\u2027' - | '\u2030' .. '\u2038' - | '\u203b' .. '\u203e' - | '\u2041' .. '\u2043' - | '\u2047' .. '\u2051' - | '\u2053' - | '\u2055' .. '\u205e' - | '\u2cf9' .. '\u2cfc' - | '\u2cfe' .. '\u2cff' - | '\u2d70' - | '\u2e00' .. '\u2e01' - | '\u2e06' .. '\u2e08' - | '\u2e0b' - | '\u2e0e' .. '\u2e16' - | '\u2e18' .. '\u2e19' - | '\u2e1b' - | '\u2e1e' .. '\u2e1f' - | '\u2e2a' .. '\u2e2e' - | '\u2e30' .. '\u2e31' - | '\u3001' .. '\u3003' - | '\u303d' - | '\u30fb' - | '\ua4fe' .. '\ua4ff' - | '\ua60d' .. '\ua60f' - | '\ua673' - | '\ua67e' - | '\ua6f2' .. '\ua6f7' - | '\ua874' .. '\ua877' - | '\ua8ce' .. '\ua8cf' - | '\ua8f8' .. '\ua8fa' - | '\ua92e' .. '\ua92f' - | '\ua95f' - | '\ua9c1' .. '\ua9cd' - | '\ua9de' .. '\ua9df' - | '\uaa5c' .. '\uaa5f' - | '\uaade' .. '\uaadf' - | '\uabeb' - | '\ufe10' .. '\ufe16' - | '\ufe19' - | '\ufe30' - | '\ufe45' .. '\ufe46' - | '\ufe49' .. '\ufe4c' - | '\ufe50' .. '\ufe57' - | '\ufe5f' .. '\ufe61' - | '\ufe68' - | '\ufe6a' .. '\ufe6b' - | '\uff01' .. '\uff03' - | '\uff05' .. '\uff07' - | '\uff0a' - | '\uff0c' - | '\uff0e' .. '\uff0f' - | '\uff1a' .. '\uff1b' - | '\uff1f' .. '\uff20' - | '\uff3c' - | '\uff61' - | '\uff64' .. '\uff65' - | '\U00010100' .. '\U00010101' - | '\U0001039f' - | '\U000103d0' - | '\U00010857' - | '\U0001091f' - | '\U0001093f' - | '\U00010a50' .. '\U00010a58' - | '\U00010a7f' - | '\U00010b39' .. '\U00010b3f' - | '\U00011047' .. '\U0001104d' - | '\U000110bb' .. '\U000110bc' - | '\U000110be' .. '\U000110c1' - | '\U00012470' .. '\U00012473' - => true, - _ => false - }; + bsearch_range_table(c, Po_table) } + static Ps_table : &'static [(char,char)] = &[ + ('\x28', '\x28'), ('\x5b', '\x5b'), + ('\x7b', '\x7b'), ('\u0f3a', '\u0f3a'), + ('\u0f3c', '\u0f3c'), ('\u169b', '\u169b'), + ('\u201a', '\u201a'), ('\u201e', '\u201e'), + ('\u2045', '\u2045'), ('\u207d', '\u207d'), + ('\u208d', '\u208d'), ('\u2329', '\u2329'), + ('\u2768', '\u2768'), ('\u276a', '\u276a'), + ('\u276c', '\u276c'), ('\u276e', '\u276e'), + ('\u2770', '\u2770'), ('\u2772', '\u2772'), + ('\u2774', '\u2774'), ('\u27c5', '\u27c5'), + ('\u27e6', '\u27e6'), ('\u27e8', '\u27e8'), + ('\u27ea', '\u27ea'), ('\u27ec', '\u27ec'), + ('\u27ee', '\u27ee'), ('\u2983', '\u2983'), + ('\u2985', '\u2985'), ('\u2987', '\u2987'), + ('\u2989', '\u2989'), ('\u298b', '\u298b'), + ('\u298d', '\u298d'), ('\u298f', '\u298f'), + ('\u2991', '\u2991'), ('\u2993', '\u2993'), + ('\u2995', '\u2995'), ('\u2997', '\u2997'), + ('\u29d8', '\u29d8'), ('\u29da', '\u29da'), + ('\u29fc', '\u29fc'), ('\u2e22', '\u2e22'), + ('\u2e24', '\u2e24'), ('\u2e26', '\u2e26'), + ('\u2e28', '\u2e28'), ('\u3008', '\u3008'), + ('\u300a', '\u300a'), ('\u300c', '\u300c'), + ('\u300e', '\u300e'), ('\u3010', '\u3010'), + ('\u3014', '\u3014'), ('\u3016', '\u3016'), + ('\u3018', '\u3018'), ('\u301a', '\u301a'), + ('\u301d', '\u301d'), ('\ufd3e', '\ufd3e'), + ('\ufe17', '\ufe17'), ('\ufe35', '\ufe35'), + ('\ufe37', '\ufe37'), ('\ufe39', '\ufe39'), + ('\ufe3b', '\ufe3b'), ('\ufe3d', '\ufe3d'), + ('\ufe3f', '\ufe3f'), ('\ufe41', '\ufe41'), + ('\ufe43', '\ufe43'), ('\ufe47', '\ufe47'), + ('\ufe59', '\ufe59'), ('\ufe5b', '\ufe5b'), + ('\ufe5d', '\ufe5d'), ('\uff08', '\uff08'), + ('\uff3b', '\uff3b'), ('\uff5b', '\uff5b'), + ('\uff5f', '\uff5f'), ('\uff62', '\uff62') + ]; + pub fn Ps(c: char) -> bool { - return match c { - '\x28' - | '\x5b' - | '\x7b' - | '\u0f3a' - | '\u0f3c' - | '\u169b' - | '\u201a' - | '\u201e' - | '\u2045' - | '\u207d' - | '\u208d' - | '\u2329' - | '\u2768' - | '\u276a' - | '\u276c' - | '\u276e' - | '\u2770' - | '\u2772' - | '\u2774' - | '\u27c5' - | '\u27e6' - | '\u27e8' - | '\u27ea' - | '\u27ec' - | '\u27ee' - | '\u2983' - | '\u2985' - | '\u2987' - | '\u2989' - | '\u298b' - | '\u298d' - | '\u298f' - | '\u2991' - | '\u2993' - | '\u2995' - | '\u2997' - | '\u29d8' - | '\u29da' - | '\u29fc' - | '\u2e22' - | '\u2e24' - | '\u2e26' - | '\u2e28' - | '\u3008' - | '\u300a' - | '\u300c' - | '\u300e' - | '\u3010' - | '\u3014' - | '\u3016' - | '\u3018' - | '\u301a' - | '\u301d' - | '\ufd3e' - | '\ufe17' - | '\ufe35' - | '\ufe37' - | '\ufe39' - | '\ufe3b' - | '\ufe3d' - | '\ufe3f' - | '\ufe41' - | '\ufe43' - | '\ufe47' - | '\ufe59' - | '\ufe5b' - | '\ufe5d' - | '\uff08' - | '\uff3b' - | '\uff5b' - | '\uff5f' - | '\uff62' - => true, - _ => false - }; + bsearch_range_table(c, Ps_table) } + static Sc_table : &'static [(char,char)] = &[ + ('\x24', '\x24'), ('\xa2', '\xa5'), + ('\u058f', '\u058f'), ('\u060b', '\u060b'), + ('\u09f2', '\u09f3'), ('\u09fb', '\u09fb'), + ('\u0af1', '\u0af1'), ('\u0bf9', '\u0bf9'), + ('\u0e3f', '\u0e3f'), ('\u17db', '\u17db'), + ('\u20a0', '\u20ba'), ('\ua838', '\ua838'), + ('\ufdfc', '\ufdfc'), ('\ufe69', '\ufe69'), + ('\uff04', '\uff04'), ('\uffe0', '\uffe1'), + ('\uffe5', '\uffe6') + ]; + pub fn Sc(c: char) -> bool { - return match c { - '\x24' - | '\xa2' .. '\xa5' - | '\u060b' - | '\u09f2' .. '\u09f3' - | '\u09fb' - | '\u0af1' - | '\u0bf9' - | '\u0e3f' - | '\u17db' - | '\u20a0' .. '\u20b9' - | '\ua838' - | '\ufdfc' - | '\ufe69' - | '\uff04' - | '\uffe0' .. '\uffe1' - | '\uffe5' .. '\uffe6' - => true, - _ => false - }; + bsearch_range_table(c, Sc_table) } + static Sk_table : &'static [(char,char)] = &[ + ('\x5e', '\x5e'), ('\x60', '\x60'), + ('\xa8', '\xa8'), ('\xaf', '\xaf'), + ('\xb4', '\xb4'), ('\xb8', '\xb8'), + ('\u02c2', '\u02c5'), ('\u02d2', '\u02df'), + ('\u02e5', '\u02eb'), ('\u02ed', '\u02ed'), + ('\u02ef', '\u02ff'), ('\u0375', '\u0375'), + ('\u0384', '\u0385'), ('\u1fbd', '\u1fbd'), + ('\u1fbf', '\u1fc1'), ('\u1fcd', '\u1fcf'), + ('\u1fdd', '\u1fdf'), ('\u1fed', '\u1fef'), + ('\u1ffd', '\u1ffe'), ('\u309b', '\u309c'), + ('\ua700', '\ua716'), ('\ua720', '\ua721'), + ('\ua789', '\ua78a'), ('\ufbb2', '\ufbc1'), + ('\uff3e', '\uff3e'), ('\uff40', '\uff40'), + ('\uffe3', '\uffe3') + ]; + pub fn Sk(c: char) -> bool { - return match c { - '\x5e' - | '\x60' - | '\xa8' - | '\xaf' - | '\xb4' - | '\xb8' - | '\u02c2' .. '\u02c5' - | '\u02d2' .. '\u02df' - | '\u02e5' .. '\u02eb' - | '\u02ed' - | '\u02ef' .. '\u02ff' - | '\u0375' - | '\u0384' .. '\u0385' - | '\u1fbd' - | '\u1fbf' .. '\u1fc1' - | '\u1fcd' .. '\u1fcf' - | '\u1fdd' .. '\u1fdf' - | '\u1fed' .. '\u1fef' - | '\u1ffd' .. '\u1ffe' - | '\u309b' .. '\u309c' - | '\ua700' .. '\ua716' - | '\ua720' .. '\ua721' - | '\ua789' .. '\ua78a' - | '\ufbb2' .. '\ufbc1' - | '\uff3e' - | '\uff40' - | '\uffe3' - => true, - _ => false - }; + bsearch_range_table(c, Sk_table) } + static Sm_table : &'static [(char,char)] = &[ + ('\x2b', '\x2b'), ('\x3c', '\x3e'), + ('\x7c', '\x7c'), ('\x7e', '\x7e'), + ('\xac', '\xac'), ('\xb1', '\xb1'), + ('\xd7', '\xd7'), ('\xf7', '\xf7'), + ('\u03f6', '\u03f6'), ('\u0606', '\u0608'), + ('\u2044', '\u2044'), ('\u2052', '\u2052'), + ('\u207a', '\u207c'), ('\u208a', '\u208c'), + ('\u2118', '\u2118'), ('\u2140', '\u2144'), + ('\u214b', '\u214b'), ('\u2190', '\u2194'), + ('\u219a', '\u219b'), ('\u21a0', '\u21a0'), + ('\u21a3', '\u21a3'), ('\u21a6', '\u21a6'), + ('\u21ae', '\u21ae'), ('\u21ce', '\u21cf'), + ('\u21d2', '\u21d2'), ('\u21d4', '\u21d4'), + ('\u21f4', '\u22ff'), ('\u2308', '\u230b'), + ('\u2320', '\u2321'), ('\u237c', '\u237c'), + ('\u239b', '\u23b3'), ('\u23dc', '\u23e1'), + ('\u25b7', '\u25b7'), ('\u25c1', '\u25c1'), + ('\u25f8', '\u25ff'), ('\u266f', '\u266f'), + ('\u27c0', '\u27c4'), ('\u27c7', '\u27e5'), + ('\u27f0', '\u27ff'), ('\u2900', '\u2982'), + ('\u2999', '\u29d7'), ('\u29dc', '\u29fb'), + ('\u29fe', '\u2aff'), ('\u2b30', '\u2b44'), + ('\u2b47', '\u2b4c'), ('\ufb29', '\ufb29'), + ('\ufe62', '\ufe62'), ('\ufe64', '\ufe66'), + ('\uff0b', '\uff0b'), ('\uff1c', '\uff1e'), + ('\uff5c', '\uff5c'), ('\uff5e', '\uff5e'), + ('\uffe2', '\uffe2'), ('\uffe9', '\uffec'), + ('\U0001d6c1', '\U0001d6c1'), ('\U0001d6db', '\U0001d6db'), + ('\U0001d6fb', '\U0001d6fb'), ('\U0001d715', '\U0001d715'), + ('\U0001d735', '\U0001d735'), ('\U0001d74f', '\U0001d74f'), + ('\U0001d76f', '\U0001d76f'), ('\U0001d789', '\U0001d789'), + ('\U0001d7a9', '\U0001d7a9'), ('\U0001d7c3', '\U0001d7c3'), + ('\U0001eef0', '\U0001eef1') + ]; + pub fn Sm(c: char) -> bool { - return match c { - '\x2b' - | '\x3c' .. '\x3e' - | '\x7c' - | '\x7e' - | '\xac' - | '\xb1' - | '\xd7' - | '\xf7' - | '\u03f6' - | '\u0606' .. '\u0608' - | '\u2044' - | '\u2052' - | '\u207a' .. '\u207c' - | '\u208a' .. '\u208c' - | '\u2118' - | '\u2140' .. '\u2144' - | '\u214b' - | '\u2190' .. '\u2194' - | '\u219a' .. '\u219b' - | '\u21a0' - | '\u21a3' - | '\u21a6' - | '\u21ae' - | '\u21ce' .. '\u21cf' - | '\u21d2' - | '\u21d4' - | '\u21f4' .. '\u22ff' - | '\u2308' .. '\u230b' - | '\u2320' .. '\u2321' - | '\u237c' - | '\u239b' .. '\u23b3' - | '\u23dc' .. '\u23e1' - | '\u25b7' - | '\u25c1' - | '\u25f8' .. '\u25ff' - | '\u266f' - | '\u27c0' .. '\u27c4' - | '\u27c7' .. '\u27e5' - | '\u27f0' .. '\u27ff' - | '\u2900' .. '\u2982' - | '\u2999' .. '\u29d7' - | '\u29dc' .. '\u29fb' - | '\u29fe' .. '\u2aff' - | '\u2b30' .. '\u2b44' - | '\u2b47' .. '\u2b4c' - | '\ufb29' - | '\ufe62' - | '\ufe64' .. '\ufe66' - | '\uff0b' - | '\uff1c' .. '\uff1e' - | '\uff5c' - | '\uff5e' - | '\uffe2' - | '\uffe9' .. '\uffec' - | '\U0001d6c1' - | '\U0001d6db' - | '\U0001d6fb' - | '\U0001d715' - | '\U0001d735' - | '\U0001d74f' - | '\U0001d76f' - | '\U0001d789' - | '\U0001d7a9' - | '\U0001d7c3' - => true, - _ => false - }; + bsearch_range_table(c, Sm_table) } + static So_table : &'static [(char,char)] = &[ + ('\xa6', '\xa6'), ('\xa9', '\xa9'), + ('\xae', '\xae'), ('\xb0', '\xb0'), + ('\u0482', '\u0482'), ('\u060e', '\u060f'), + ('\u06de', '\u06de'), ('\u06e9', '\u06e9'), + ('\u06fd', '\u06fe'), ('\u07f6', '\u07f6'), + ('\u09fa', '\u09fa'), ('\u0b70', '\u0b70'), + ('\u0bf3', '\u0bf8'), ('\u0bfa', '\u0bfa'), + ('\u0c7f', '\u0c7f'), ('\u0d79', '\u0d79'), + ('\u0f01', '\u0f03'), ('\u0f13', '\u0f13'), + ('\u0f15', '\u0f17'), ('\u0f1a', '\u0f1f'), + ('\u0f34', '\u0f34'), ('\u0f36', '\u0f36'), + ('\u0f38', '\u0f38'), ('\u0fbe', '\u0fc5'), + ('\u0fc7', '\u0fcf'), ('\u0fd5', '\u0fd8'), + ('\u109e', '\u109f'), ('\u1390', '\u1399'), + ('\u1940', '\u1940'), ('\u19de', '\u19ff'), + ('\u1b61', '\u1b6a'), ('\u1b74', '\u1b7c'), + ('\u2100', '\u2101'), ('\u2103', '\u2106'), + ('\u2108', '\u2109'), ('\u2114', '\u2114'), + ('\u2116', '\u2117'), ('\u211e', '\u2123'), + ('\u2125', '\u2125'), ('\u2127', '\u2127'), + ('\u2129', '\u2129'), ('\u212e', '\u212e'), + ('\u213a', '\u213b'), ('\u214a', '\u214a'), + ('\u214c', '\u214d'), ('\u214f', '\u214f'), + ('\u2195', '\u2199'), ('\u219c', '\u219f'), + ('\u21a1', '\u21a2'), ('\u21a4', '\u21a5'), + ('\u21a7', '\u21ad'), ('\u21af', '\u21cd'), + ('\u21d0', '\u21d1'), ('\u21d3', '\u21d3'), + ('\u21d5', '\u21f3'), ('\u2300', '\u2307'), + ('\u230c', '\u231f'), ('\u2322', '\u2328'), + ('\u232b', '\u237b'), ('\u237d', '\u239a'), + ('\u23b4', '\u23db'), ('\u23e2', '\u244a'), + ('\u249c', '\u24e9'), ('\u2500', '\u25b6'), + ('\u25b8', '\u25c0'), ('\u25c2', '\u25f7'), + ('\u2600', '\u266e'), ('\u2670', '\u2767'), + ('\u2794', '\u27bf'), ('\u2800', '\u28ff'), + ('\u2b00', '\u2b2f'), ('\u2b45', '\u2b46'), + ('\u2b50', '\u2b59'), ('\u2ce5', '\u2cea'), + ('\u2e80', '\u2ffb'), ('\u3004', '\u3004'), + ('\u3012', '\u3013'), ('\u3020', '\u3020'), + ('\u3036', '\u3037'), ('\u303e', '\u303f'), + ('\u3190', '\u3191'), ('\u3196', '\u319f'), + ('\u31c0', '\u31e3'), ('\u3200', '\u321e'), + ('\u322a', '\u3247'), ('\u3250', '\u3250'), + ('\u3260', '\u327f'), ('\u328a', '\u32b0'), + ('\u32c0', '\u33ff'), ('\u4dc0', '\u4dff'), + ('\ua490', '\ua4c6'), ('\ua828', '\ua82b'), + ('\ua836', '\ua837'), ('\ua839', '\ua839'), + ('\uaa77', '\uaa79'), ('\ufdfd', '\ufdfd'), + ('\uffe4', '\uffe4'), ('\uffe8', '\uffe8'), + ('\uffed', '\uffee'), ('\ufffc', '\ufffd'), + ('\U00010137', '\U0001013f'), ('\U00010179', '\U00010189'), + ('\U00010190', '\U000101fc'), ('\U0001d000', '\U0001d164'), + ('\U0001d16a', '\U0001d16c'), ('\U0001d183', '\U0001d184'), + ('\U0001d18c', '\U0001d1a9'), ('\U0001d1ae', '\U0001d241'), + ('\U0001d245', '\U0001d356'), ('\U0001f000', '\U0001f0df'), + ('\U0001f110', '\U0001f773') + ]; + pub fn So(c: char) -> bool { - return match c { - '\xa6' .. '\xa7' - | '\xa9' - | '\xae' - | '\xb0' - | '\xb6' - | '\u0482' - | '\u060e' .. '\u060f' - | '\u06de' - | '\u06e9' - | '\u06fd' .. '\u06fe' - | '\u07f6' - | '\u09fa' - | '\u0b70' - | '\u0bf3' .. '\u0bf8' - | '\u0bfa' - | '\u0c7f' - | '\u0d79' - | '\u0f01' .. '\u0f03' - | '\u0f13' .. '\u0f17' - | '\u0f1a' .. '\u0f1f' - | '\u0f34' - | '\u0f36' - | '\u0f38' - | '\u0fbe' .. '\u0fc5' - | '\u0fc7' .. '\u0fcf' - | '\u0fd5' .. '\u0fd8' - | '\u109e' .. '\u109f' - | '\u1360' - | '\u1390' .. '\u1399' - | '\u1940' - | '\u19de' .. '\u19ff' - | '\u1b61' .. '\u1b6a' - | '\u1b74' .. '\u1b7c' - | '\u2100' .. '\u2101' - | '\u2103' .. '\u2106' - | '\u2108' .. '\u2109' - | '\u2114' - | '\u2116' .. '\u2117' - | '\u211e' .. '\u2123' - | '\u2125' - | '\u2127' - | '\u2129' - | '\u212e' - | '\u213a' .. '\u213b' - | '\u214a' - | '\u214c' .. '\u214d' - | '\u214f' - | '\u2195' .. '\u2199' - | '\u219c' .. '\u219f' - | '\u21a1' .. '\u21a2' - | '\u21a4' .. '\u21a5' - | '\u21a7' .. '\u21ad' - | '\u21af' .. '\u21cd' - | '\u21d0' .. '\u21d1' - | '\u21d3' - | '\u21d5' .. '\u21f3' - | '\u2300' .. '\u2307' - | '\u230c' .. '\u231f' - | '\u2322' .. '\u2328' - | '\u232b' .. '\u237b' - | '\u237d' .. '\u239a' - | '\u23b4' .. '\u23db' - | '\u23e2' .. '\u244a' - | '\u249c' .. '\u24e9' - | '\u2500' .. '\u25b6' - | '\u25b8' .. '\u25c0' - | '\u25c2' .. '\u25f7' - | '\u2600' .. '\u266e' - | '\u2670' .. '\u2767' - | '\u2794' .. '\u27bf' - | '\u2800' .. '\u28ff' - | '\u2b00' .. '\u2b2f' - | '\u2b45' .. '\u2b46' - | '\u2b50' .. '\u2b59' - | '\u2ce5' .. '\u2cea' - | '\u2e80' .. '\u2ffb' - | '\u3004' - | '\u3012' .. '\u3013' - | '\u3020' - | '\u3036' .. '\u3037' - | '\u303e' .. '\u303f' - | '\u3190' .. '\u3191' - | '\u3196' .. '\u319f' - | '\u31c0' .. '\u31e3' - | '\u3200' .. '\u321e' - | '\u322a' .. '\u3250' - | '\u3260' .. '\u327f' - | '\u328a' .. '\u32b0' - | '\u32c0' .. '\u33ff' - | '\u4dc0' .. '\u4dff' - | '\ua490' .. '\ua4c6' - | '\ua828' .. '\ua82b' - | '\ua836' .. '\ua837' - | '\ua839' - | '\uaa77' .. '\uaa79' - | '\ufdfd' - | '\uffe4' - | '\uffe8' - | '\uffed' .. '\uffee' - | '\ufffc' .. '\ufffd' - | '\U00010102' - | '\U00010137' .. '\U0001013f' - | '\U00010179' .. '\U00010189' - | '\U00010190' .. '\U000101fc' - | '\U0001d000' .. '\U0001d164' - | '\U0001d16a' .. '\U0001d16c' - | '\U0001d183' .. '\U0001d184' - | '\U0001d18c' .. '\U0001d1a9' - | '\U0001d1ae' .. '\U0001d241' - | '\U0001d245' .. '\U0001d356' - | '\U0001f000' .. '\U0001f0df' - | '\U0001f110' .. '\U0001f773' - => true, - _ => false - }; + bsearch_range_table(c, So_table) } + static Zl_table : &'static [(char,char)] = &[ + ('\u2028', '\u2028') + ]; + pub fn Zl(c: char) -> bool { - return match c { - '\u2028' => true, - _ => false - }; + bsearch_range_table(c, Zl_table) } + static Zp_table : &'static [(char,char)] = &[ + ('\u2029', '\u2029') + ]; + pub fn Zp(c: char) -> bool { - return match c { - '\u2029' => true, - _ => false - }; + bsearch_range_table(c, Zp_table) } + static Zs_table : &'static [(char,char)] = &[ + ('\x20', '\x20'), ('\xa0', '\xa0'), + ('\u1680', '\u1680'), ('\u180e', '\u180e'), + ('\u2000', '\u200a'), ('\u202f', '\u202f'), + ('\u205f', '\u205f'), ('\u3000', '\u3000') + ]; + pub fn Zs(c: char) -> bool { - return match c { - '\x20' - | '\xa0' - | '\u1680' - | '\u180e' - | '\u2000' .. '\u200a' - | '\u202f' - | '\u205f' - | '\u3000' - => true, - _ => false - }; + bsearch_range_table(c, Zs_table) } } -mod derived_property { - /// Check if a character has the alphabetic unicode property + +pub mod derived_property { + + + fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { + use cmp::{Equal, Less, Greater}; + use vec::bsearch; + use option::None; + (do bsearch(r) |&(lo,hi)| { + if lo <= c && c <= hi { Equal } + else if hi < c { Less } + else { Greater } + }) != None + } + + + static Alphabetic_table : &'static [(char,char)] = &[ + ('\x41', '\x5a'), ('\x61', '\x7a'), + ('\xaa', '\xaa'), ('\xb5', '\xb5'), + ('\xba', '\xba'), ('\xc0', '\xd6'), + ('\xd8', '\xf6'), ('\xf8', '\u01ba'), + ('\u01bb', '\u01bb'), ('\u01bc', '\u01bf'), + ('\u01c0', '\u01c3'), ('\u01c4', '\u0293'), + ('\u0294', '\u0294'), ('\u0295', '\u02af'), + ('\u02b0', '\u02c1'), ('\u02c6', '\u02d1'), + ('\u02e0', '\u02e4'), ('\u02ec', '\u02ec'), + ('\u02ee', '\u02ee'), ('\u0345', '\u0345'), + ('\u0370', '\u0373'), ('\u0374', '\u0374'), + ('\u0376', '\u0377'), ('\u037a', '\u037a'), + ('\u037b', '\u037d'), ('\u0386', '\u0386'), + ('\u0388', '\u038a'), ('\u038c', '\u038c'), + ('\u038e', '\u03a1'), ('\u03a3', '\u03f5'), + ('\u03f7', '\u0481'), ('\u048a', '\u0527'), + ('\u0531', '\u0556'), ('\u0559', '\u0559'), + ('\u0561', '\u0587'), ('\u05b0', '\u05bd'), + ('\u05bf', '\u05bf'), ('\u05c1', '\u05c2'), + ('\u05c4', '\u05c5'), ('\u05c7', '\u05c7'), + ('\u05d0', '\u05ea'), ('\u05f0', '\u05f2'), + ('\u0610', '\u061a'), ('\u0620', '\u063f'), + ('\u0640', '\u0640'), ('\u0641', '\u064a'), + ('\u064b', '\u0657'), ('\u0659', '\u065f'), + ('\u066e', '\u066f'), ('\u0670', '\u0670'), + ('\u0671', '\u06d3'), ('\u06d5', '\u06d5'), + ('\u06d6', '\u06dc'), ('\u06e1', '\u06e4'), + ('\u06e5', '\u06e6'), ('\u06e7', '\u06e8'), + ('\u06ed', '\u06ed'), ('\u06ee', '\u06ef'), + ('\u06fa', '\u06fc'), ('\u06ff', '\u06ff'), + ('\u0710', '\u0710'), ('\u0711', '\u0711'), + ('\u0712', '\u072f'), ('\u0730', '\u073f'), + ('\u074d', '\u07a5'), ('\u07a6', '\u07b0'), + ('\u07b1', '\u07b1'), ('\u07ca', '\u07ea'), + ('\u07f4', '\u07f5'), ('\u07fa', '\u07fa'), + ('\u0800', '\u0815'), ('\u0816', '\u0817'), + ('\u081a', '\u081a'), ('\u081b', '\u0823'), + ('\u0824', '\u0824'), ('\u0825', '\u0827'), + ('\u0828', '\u0828'), ('\u0829', '\u082c'), + ('\u0840', '\u0858'), ('\u08a0', '\u08a0'), + ('\u08a2', '\u08ac'), ('\u08e4', '\u08e9'), + ('\u08f0', '\u08fe'), ('\u0900', '\u0902'), + ('\u0903', '\u0903'), ('\u0904', '\u0939'), + ('\u093a', '\u093a'), ('\u093b', '\u093b'), + ('\u093d', '\u093d'), ('\u093e', '\u0940'), + ('\u0941', '\u0948'), ('\u0949', '\u094c'), + ('\u094e', '\u094f'), ('\u0950', '\u0950'), + ('\u0955', '\u0957'), ('\u0958', '\u0961'), + ('\u0962', '\u0963'), ('\u0971', '\u0971'), + ('\u0972', '\u0977'), ('\u0979', '\u097f'), + ('\u0981', '\u0981'), ('\u0982', '\u0983'), + ('\u0985', '\u098c'), ('\u098f', '\u0990'), + ('\u0993', '\u09a8'), ('\u09aa', '\u09b0'), + ('\u09b2', '\u09b2'), ('\u09b6', '\u09b9'), + ('\u09bd', '\u09bd'), ('\u09be', '\u09c0'), + ('\u09c1', '\u09c4'), ('\u09c7', '\u09c8'), + ('\u09cb', '\u09cc'), ('\u09ce', '\u09ce'), + ('\u09d7', '\u09d7'), ('\u09dc', '\u09dd'), + ('\u09df', '\u09e1'), ('\u09e2', '\u09e3'), + ('\u09f0', '\u09f1'), ('\u0a01', '\u0a02'), + ('\u0a03', '\u0a03'), ('\u0a05', '\u0a0a'), + ('\u0a0f', '\u0a10'), ('\u0a13', '\u0a28'), + ('\u0a2a', '\u0a30'), ('\u0a32', '\u0a33'), + ('\u0a35', '\u0a36'), ('\u0a38', '\u0a39'), + ('\u0a3e', '\u0a40'), ('\u0a41', '\u0a42'), + ('\u0a47', '\u0a48'), ('\u0a4b', '\u0a4c'), + ('\u0a51', '\u0a51'), ('\u0a59', '\u0a5c'), + ('\u0a5e', '\u0a5e'), ('\u0a70', '\u0a71'), + ('\u0a72', '\u0a74'), ('\u0a75', '\u0a75'), + ('\u0a81', '\u0a82'), ('\u0a83', '\u0a83'), + ('\u0a85', '\u0a8d'), ('\u0a8f', '\u0a91'), + ('\u0a93', '\u0aa8'), ('\u0aaa', '\u0ab0'), + ('\u0ab2', '\u0ab3'), ('\u0ab5', '\u0ab9'), + ('\u0abd', '\u0abd'), ('\u0abe', '\u0ac0'), + ('\u0ac1', '\u0ac5'), ('\u0ac7', '\u0ac8'), + ('\u0ac9', '\u0ac9'), ('\u0acb', '\u0acc'), + ('\u0ad0', '\u0ad0'), ('\u0ae0', '\u0ae1'), + ('\u0ae2', '\u0ae3'), ('\u0b01', '\u0b01'), + ('\u0b02', '\u0b03'), ('\u0b05', '\u0b0c'), + ('\u0b0f', '\u0b10'), ('\u0b13', '\u0b28'), + ('\u0b2a', '\u0b30'), ('\u0b32', '\u0b33'), + ('\u0b35', '\u0b39'), ('\u0b3d', '\u0b3d'), + ('\u0b3e', '\u0b3e'), ('\u0b3f', '\u0b3f'), + ('\u0b40', '\u0b40'), ('\u0b41', '\u0b44'), + ('\u0b47', '\u0b48'), ('\u0b4b', '\u0b4c'), + ('\u0b56', '\u0b56'), ('\u0b57', '\u0b57'), + ('\u0b5c', '\u0b5d'), ('\u0b5f', '\u0b61'), + ('\u0b62', '\u0b63'), ('\u0b71', '\u0b71'), + ('\u0b82', '\u0b82'), ('\u0b83', '\u0b83'), + ('\u0b85', '\u0b8a'), ('\u0b8e', '\u0b90'), + ('\u0b92', '\u0b95'), ('\u0b99', '\u0b9a'), + ('\u0b9c', '\u0b9c'), ('\u0b9e', '\u0b9f'), + ('\u0ba3', '\u0ba4'), ('\u0ba8', '\u0baa'), + ('\u0bae', '\u0bb9'), ('\u0bbe', '\u0bbf'), + ('\u0bc0', '\u0bc0'), ('\u0bc1', '\u0bc2'), + ('\u0bc6', '\u0bc8'), ('\u0bca', '\u0bcc'), + ('\u0bd0', '\u0bd0'), ('\u0bd7', '\u0bd7'), + ('\u0c01', '\u0c03'), ('\u0c05', '\u0c0c'), + ('\u0c0e', '\u0c10'), ('\u0c12', '\u0c28'), + ('\u0c2a', '\u0c33'), ('\u0c35', '\u0c39'), + ('\u0c3d', '\u0c3d'), ('\u0c3e', '\u0c40'), + ('\u0c41', '\u0c44'), ('\u0c46', '\u0c48'), + ('\u0c4a', '\u0c4c'), ('\u0c55', '\u0c56'), + ('\u0c58', '\u0c59'), ('\u0c60', '\u0c61'), + ('\u0c62', '\u0c63'), ('\u0c82', '\u0c83'), + ('\u0c85', '\u0c8c'), ('\u0c8e', '\u0c90'), + ('\u0c92', '\u0ca8'), ('\u0caa', '\u0cb3'), + ('\u0cb5', '\u0cb9'), ('\u0cbd', '\u0cbd'), + ('\u0cbe', '\u0cbe'), ('\u0cbf', '\u0cbf'), + ('\u0cc0', '\u0cc4'), ('\u0cc6', '\u0cc6'), + ('\u0cc7', '\u0cc8'), ('\u0cca', '\u0ccb'), + ('\u0ccc', '\u0ccc'), ('\u0cd5', '\u0cd6'), + ('\u0cde', '\u0cde'), ('\u0ce0', '\u0ce1'), + ('\u0ce2', '\u0ce3'), ('\u0cf1', '\u0cf2'), + ('\u0d02', '\u0d03'), ('\u0d05', '\u0d0c'), + ('\u0d0e', '\u0d10'), ('\u0d12', '\u0d3a'), + ('\u0d3d', '\u0d3d'), ('\u0d3e', '\u0d40'), + ('\u0d41', '\u0d44'), ('\u0d46', '\u0d48'), + ('\u0d4a', '\u0d4c'), ('\u0d4e', '\u0d4e'), + ('\u0d57', '\u0d57'), ('\u0d60', '\u0d61'), + ('\u0d62', '\u0d63'), ('\u0d7a', '\u0d7f'), + ('\u0d82', '\u0d83'), ('\u0d85', '\u0d96'), + ('\u0d9a', '\u0db1'), ('\u0db3', '\u0dbb'), + ('\u0dbd', '\u0dbd'), ('\u0dc0', '\u0dc6'), + ('\u0dcf', '\u0dd1'), ('\u0dd2', '\u0dd4'), + ('\u0dd6', '\u0dd6'), ('\u0dd8', '\u0ddf'), + ('\u0df2', '\u0df3'), ('\u0e01', '\u0e30'), + ('\u0e31', '\u0e31'), ('\u0e32', '\u0e33'), + ('\u0e34', '\u0e3a'), ('\u0e40', '\u0e45'), + ('\u0e46', '\u0e46'), ('\u0e4d', '\u0e4d'), + ('\u0e81', '\u0e82'), ('\u0e84', '\u0e84'), + ('\u0e87', '\u0e88'), ('\u0e8a', '\u0e8a'), + ('\u0e8d', '\u0e8d'), ('\u0e94', '\u0e97'), + ('\u0e99', '\u0e9f'), ('\u0ea1', '\u0ea3'), + ('\u0ea5', '\u0ea5'), ('\u0ea7', '\u0ea7'), + ('\u0eaa', '\u0eab'), ('\u0ead', '\u0eb0'), + ('\u0eb1', '\u0eb1'), ('\u0eb2', '\u0eb3'), + ('\u0eb4', '\u0eb9'), ('\u0ebb', '\u0ebc'), + ('\u0ebd', '\u0ebd'), ('\u0ec0', '\u0ec4'), + ('\u0ec6', '\u0ec6'), ('\u0ecd', '\u0ecd'), + ('\u0edc', '\u0edf'), ('\u0f00', '\u0f00'), + ('\u0f40', '\u0f47'), ('\u0f49', '\u0f6c'), + ('\u0f71', '\u0f7e'), ('\u0f7f', '\u0f7f'), + ('\u0f80', '\u0f81'), ('\u0f88', '\u0f8c'), + ('\u0f8d', '\u0f97'), ('\u0f99', '\u0fbc'), + ('\u1000', '\u102a'), ('\u102b', '\u102c'), + ('\u102d', '\u1030'), ('\u1031', '\u1031'), + ('\u1032', '\u1036'), ('\u1038', '\u1038'), + ('\u103b', '\u103c'), ('\u103d', '\u103e'), + ('\u103f', '\u103f'), ('\u1050', '\u1055'), + ('\u1056', '\u1057'), ('\u1058', '\u1059'), + ('\u105a', '\u105d'), ('\u105e', '\u1060'), + ('\u1061', '\u1061'), ('\u1062', '\u1062'), + ('\u1065', '\u1066'), ('\u1067', '\u1068'), + ('\u106e', '\u1070'), ('\u1071', '\u1074'), + ('\u1075', '\u1081'), ('\u1082', '\u1082'), + ('\u1083', '\u1084'), ('\u1085', '\u1086'), + ('\u108e', '\u108e'), ('\u109c', '\u109c'), + ('\u109d', '\u109d'), ('\u10a0', '\u10c5'), + ('\u10c7', '\u10c7'), ('\u10cd', '\u10cd'), + ('\u10d0', '\u10fa'), ('\u10fc', '\u10fc'), + ('\u10fd', '\u1248'), ('\u124a', '\u124d'), + ('\u1250', '\u1256'), ('\u1258', '\u1258'), + ('\u125a', '\u125d'), ('\u1260', '\u1288'), + ('\u128a', '\u128d'), ('\u1290', '\u12b0'), + ('\u12b2', '\u12b5'), ('\u12b8', '\u12be'), + ('\u12c0', '\u12c0'), ('\u12c2', '\u12c5'), + ('\u12c8', '\u12d6'), ('\u12d8', '\u1310'), + ('\u1312', '\u1315'), ('\u1318', '\u135a'), + ('\u135f', '\u135f'), ('\u1380', '\u138f'), + ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), + ('\u166f', '\u167f'), ('\u1681', '\u169a'), + ('\u16a0', '\u16ea'), ('\u16ee', '\u16f0'), + ('\u1700', '\u170c'), ('\u170e', '\u1711'), + ('\u1712', '\u1713'), ('\u1720', '\u1731'), + ('\u1732', '\u1733'), ('\u1740', '\u1751'), + ('\u1752', '\u1753'), ('\u1760', '\u176c'), + ('\u176e', '\u1770'), ('\u1772', '\u1773'), + ('\u1780', '\u17b3'), ('\u17b6', '\u17b6'), + ('\u17b7', '\u17bd'), ('\u17be', '\u17c5'), + ('\u17c6', '\u17c6'), ('\u17c7', '\u17c8'), + ('\u17d7', '\u17d7'), ('\u17dc', '\u17dc'), + ('\u1820', '\u1842'), ('\u1843', '\u1843'), + ('\u1844', '\u1877'), ('\u1880', '\u18a8'), + ('\u18a9', '\u18a9'), ('\u18aa', '\u18aa'), + ('\u18b0', '\u18f5'), ('\u1900', '\u191c'), + ('\u1920', '\u1922'), ('\u1923', '\u1926'), + ('\u1927', '\u1928'), ('\u1929', '\u192b'), + ('\u1930', '\u1931'), ('\u1932', '\u1932'), + ('\u1933', '\u1938'), ('\u1950', '\u196d'), + ('\u1970', '\u1974'), ('\u1980', '\u19ab'), + ('\u19b0', '\u19c0'), ('\u19c1', '\u19c7'), + ('\u19c8', '\u19c9'), ('\u1a00', '\u1a16'), + ('\u1a17', '\u1a18'), ('\u1a19', '\u1a1b'), + ('\u1a20', '\u1a54'), ('\u1a55', '\u1a55'), + ('\u1a56', '\u1a56'), ('\u1a57', '\u1a57'), + ('\u1a58', '\u1a5e'), ('\u1a61', '\u1a61'), + ('\u1a62', '\u1a62'), ('\u1a63', '\u1a64'), + ('\u1a65', '\u1a6c'), ('\u1a6d', '\u1a72'), + ('\u1a73', '\u1a74'), ('\u1aa7', '\u1aa7'), + ('\u1b00', '\u1b03'), ('\u1b04', '\u1b04'), + ('\u1b05', '\u1b33'), ('\u1b35', '\u1b35'), + ('\u1b36', '\u1b3a'), ('\u1b3b', '\u1b3b'), + ('\u1b3c', '\u1b3c'), ('\u1b3d', '\u1b41'), + ('\u1b42', '\u1b42'), ('\u1b43', '\u1b43'), + ('\u1b45', '\u1b4b'), ('\u1b80', '\u1b81'), + ('\u1b82', '\u1b82'), ('\u1b83', '\u1ba0'), + ('\u1ba1', '\u1ba1'), ('\u1ba2', '\u1ba5'), + ('\u1ba6', '\u1ba7'), ('\u1ba8', '\u1ba9'), + ('\u1bac', '\u1bad'), ('\u1bae', '\u1baf'), + ('\u1bba', '\u1be5'), ('\u1be7', '\u1be7'), + ('\u1be8', '\u1be9'), ('\u1bea', '\u1bec'), + ('\u1bed', '\u1bed'), ('\u1bee', '\u1bee'), + ('\u1bef', '\u1bf1'), ('\u1c00', '\u1c23'), + ('\u1c24', '\u1c2b'), ('\u1c2c', '\u1c33'), + ('\u1c34', '\u1c35'), ('\u1c4d', '\u1c4f'), + ('\u1c5a', '\u1c77'), ('\u1c78', '\u1c7d'), + ('\u1ce9', '\u1cec'), ('\u1cee', '\u1cf1'), + ('\u1cf2', '\u1cf3'), ('\u1cf5', '\u1cf6'), + ('\u1d00', '\u1d2b'), ('\u1d2c', '\u1d6a'), + ('\u1d6b', '\u1d77'), ('\u1d78', '\u1d78'), + ('\u1d79', '\u1d9a'), ('\u1d9b', '\u1dbf'), + ('\u1e00', '\u1f15'), ('\u1f18', '\u1f1d'), + ('\u1f20', '\u1f45'), ('\u1f48', '\u1f4d'), + ('\u1f50', '\u1f57'), ('\u1f59', '\u1f59'), + ('\u1f5b', '\u1f5b'), ('\u1f5d', '\u1f5d'), + ('\u1f5f', '\u1f7d'), ('\u1f80', '\u1fb4'), + ('\u1fb6', '\u1fbc'), ('\u1fbe', '\u1fbe'), + ('\u1fc2', '\u1fc4'), ('\u1fc6', '\u1fcc'), + ('\u1fd0', '\u1fd3'), ('\u1fd6', '\u1fdb'), + ('\u1fe0', '\u1fec'), ('\u1ff2', '\u1ff4'), + ('\u1ff6', '\u1ffc'), ('\u2071', '\u2071'), + ('\u207f', '\u207f'), ('\u2090', '\u209c'), + ('\u2102', '\u2102'), ('\u2107', '\u2107'), + ('\u210a', '\u2113'), ('\u2115', '\u2115'), + ('\u2119', '\u211d'), ('\u2124', '\u2124'), + ('\u2126', '\u2126'), ('\u2128', '\u2128'), + ('\u212a', '\u212d'), ('\u212f', '\u2134'), + ('\u2135', '\u2138'), ('\u2139', '\u2139'), + ('\u213c', '\u213f'), ('\u2145', '\u2149'), + ('\u214e', '\u214e'), ('\u2160', '\u2182'), + ('\u2183', '\u2184'), ('\u2185', '\u2188'), + ('\u24b6', '\u24e9'), ('\u2c00', '\u2c2e'), + ('\u2c30', '\u2c5e'), ('\u2c60', '\u2c7b'), + ('\u2c7c', '\u2c7d'), ('\u2c7e', '\u2ce4'), + ('\u2ceb', '\u2cee'), ('\u2cf2', '\u2cf3'), + ('\u2d00', '\u2d25'), ('\u2d27', '\u2d27'), + ('\u2d2d', '\u2d2d'), ('\u2d30', '\u2d67'), + ('\u2d6f', '\u2d6f'), ('\u2d80', '\u2d96'), + ('\u2da0', '\u2da6'), ('\u2da8', '\u2dae'), + ('\u2db0', '\u2db6'), ('\u2db8', '\u2dbe'), + ('\u2dc0', '\u2dc6'), ('\u2dc8', '\u2dce'), + ('\u2dd0', '\u2dd6'), ('\u2dd8', '\u2dde'), + ('\u2de0', '\u2dff'), ('\u2e2f', '\u2e2f'), + ('\u3005', '\u3005'), ('\u3006', '\u3006'), + ('\u3007', '\u3007'), ('\u3021', '\u3029'), + ('\u3031', '\u3035'), ('\u3038', '\u303a'), + ('\u303b', '\u303b'), ('\u303c', '\u303c'), + ('\u3041', '\u3096'), ('\u309d', '\u309e'), + ('\u309f', '\u309f'), ('\u30a1', '\u30fa'), + ('\u30fc', '\u30fe'), ('\u30ff', '\u30ff'), + ('\u3105', '\u312d'), ('\u3131', '\u318e'), + ('\u31a0', '\u31ba'), ('\u31f0', '\u31ff'), + ('\u3400', '\u4db5'), ('\u4e00', '\u9fcc'), + ('\ua000', '\ua014'), ('\ua015', '\ua015'), + ('\ua016', '\ua48c'), ('\ua4d0', '\ua4f7'), + ('\ua4f8', '\ua4fd'), ('\ua500', '\ua60b'), + ('\ua60c', '\ua60c'), ('\ua610', '\ua61f'), + ('\ua62a', '\ua62b'), ('\ua640', '\ua66d'), + ('\ua66e', '\ua66e'), ('\ua674', '\ua67b'), + ('\ua67f', '\ua67f'), ('\ua680', '\ua697'), + ('\ua69f', '\ua69f'), ('\ua6a0', '\ua6e5'), + ('\ua6e6', '\ua6ef'), ('\ua717', '\ua71f'), + ('\ua722', '\ua76f'), ('\ua770', '\ua770'), + ('\ua771', '\ua787'), ('\ua788', '\ua788'), + ('\ua78b', '\ua78e'), ('\ua790', '\ua793'), + ('\ua7a0', '\ua7aa'), ('\ua7f8', '\ua7f9'), + ('\ua7fa', '\ua7fa'), ('\ua7fb', '\ua801'), + ('\ua803', '\ua805'), ('\ua807', '\ua80a'), + ('\ua80c', '\ua822'), ('\ua823', '\ua824'), + ('\ua825', '\ua826'), ('\ua827', '\ua827'), + ('\ua840', '\ua873'), ('\ua880', '\ua881'), + ('\ua882', '\ua8b3'), ('\ua8b4', '\ua8c3'), + ('\ua8f2', '\ua8f7'), ('\ua8fb', '\ua8fb'), + ('\ua90a', '\ua925'), ('\ua926', '\ua92a'), + ('\ua930', '\ua946'), ('\ua947', '\ua951'), + ('\ua952', '\ua952'), ('\ua960', '\ua97c'), + ('\ua980', '\ua982'), ('\ua983', '\ua983'), + ('\ua984', '\ua9b2'), ('\ua9b4', '\ua9b5'), + ('\ua9b6', '\ua9b9'), ('\ua9ba', '\ua9bb'), + ('\ua9bc', '\ua9bc'), ('\ua9bd', '\ua9bf'), + ('\ua9cf', '\ua9cf'), ('\uaa00', '\uaa28'), + ('\uaa29', '\uaa2e'), ('\uaa2f', '\uaa30'), + ('\uaa31', '\uaa32'), ('\uaa33', '\uaa34'), + ('\uaa35', '\uaa36'), ('\uaa40', '\uaa42'), + ('\uaa43', '\uaa43'), ('\uaa44', '\uaa4b'), + ('\uaa4c', '\uaa4c'), ('\uaa4d', '\uaa4d'), + ('\uaa60', '\uaa6f'), ('\uaa70', '\uaa70'), + ('\uaa71', '\uaa76'), ('\uaa7a', '\uaa7a'), + ('\uaa80', '\uaaaf'), ('\uaab0', '\uaab0'), + ('\uaab1', '\uaab1'), ('\uaab2', '\uaab4'), + ('\uaab5', '\uaab6'), ('\uaab7', '\uaab8'), + ('\uaab9', '\uaabd'), ('\uaabe', '\uaabe'), + ('\uaac0', '\uaac0'), ('\uaac2', '\uaac2'), + ('\uaadb', '\uaadc'), ('\uaadd', '\uaadd'), + ('\uaae0', '\uaaea'), ('\uaaeb', '\uaaeb'), + ('\uaaec', '\uaaed'), ('\uaaee', '\uaaef'), + ('\uaaf2', '\uaaf2'), ('\uaaf3', '\uaaf4'), + ('\uaaf5', '\uaaf5'), ('\uab01', '\uab06'), + ('\uab09', '\uab0e'), ('\uab11', '\uab16'), + ('\uab20', '\uab26'), ('\uab28', '\uab2e'), + ('\uabc0', '\uabe2'), ('\uabe3', '\uabe4'), + ('\uabe5', '\uabe5'), ('\uabe6', '\uabe7'), + ('\uabe8', '\uabe8'), ('\uabe9', '\uabea'), + ('\uac00', '\ud7a3'), ('\ud7b0', '\ud7c6'), + ('\ud7cb', '\ud7fb'), ('\uf900', '\ufa6d'), + ('\ufa70', '\ufad9'), ('\ufb00', '\ufb06'), + ('\ufb13', '\ufb17'), ('\ufb1d', '\ufb1d'), + ('\ufb1e', '\ufb1e'), ('\ufb1f', '\ufb28'), + ('\ufb2a', '\ufb36'), ('\ufb38', '\ufb3c'), + ('\ufb3e', '\ufb3e'), ('\ufb40', '\ufb41'), + ('\ufb43', '\ufb44'), ('\ufb46', '\ufbb1'), + ('\ufbd3', '\ufd3d'), ('\ufd50', '\ufd8f'), + ('\ufd92', '\ufdc7'), ('\ufdf0', '\ufdfb'), + ('\ufe70', '\ufe74'), ('\ufe76', '\ufefc'), + ('\uff21', '\uff3a'), ('\uff41', '\uff5a'), + ('\uff66', '\uff6f'), ('\uff70', '\uff70'), + ('\uff71', '\uff9d'), ('\uff9e', '\uff9f'), + ('\uffa0', '\uffbe'), ('\uffc2', '\uffc7'), + ('\uffca', '\uffcf'), ('\uffd2', '\uffd7'), + ('\uffda', '\uffdc'), ('\U00010000', '\U0001000b'), + ('\U0001000d', '\U00010026'), ('\U00010028', '\U0001003a'), + ('\U0001003c', '\U0001003d'), ('\U0001003f', '\U0001004d'), + ('\U00010050', '\U0001005d'), ('\U00010080', '\U000100fa'), + ('\U00010140', '\U00010174'), ('\U00010280', '\U0001029c'), + ('\U000102a0', '\U000102d0'), ('\U00010300', '\U0001031e'), + ('\U00010330', '\U00010340'), ('\U00010341', '\U00010341'), + ('\U00010342', '\U00010349'), ('\U0001034a', '\U0001034a'), + ('\U00010380', '\U0001039d'), ('\U000103a0', '\U000103c3'), + ('\U000103c8', '\U000103cf'), ('\U000103d1', '\U000103d5'), + ('\U00010400', '\U0001044f'), ('\U00010450', '\U0001049d'), + ('\U00010800', '\U00010805'), ('\U00010808', '\U00010808'), + ('\U0001080a', '\U00010835'), ('\U00010837', '\U00010838'), + ('\U0001083c', '\U0001083c'), ('\U0001083f', '\U00010855'), + ('\U00010900', '\U00010915'), ('\U00010920', '\U00010939'), + ('\U00010980', '\U000109b7'), ('\U000109be', '\U000109bf'), + ('\U00010a00', '\U00010a00'), ('\U00010a01', '\U00010a03'), + ('\U00010a05', '\U00010a06'), ('\U00010a0c', '\U00010a0f'), + ('\U00010a10', '\U00010a13'), ('\U00010a15', '\U00010a17'), + ('\U00010a19', '\U00010a33'), ('\U00010a60', '\U00010a7c'), + ('\U00010b00', '\U00010b35'), ('\U00010b40', '\U00010b55'), + ('\U00010b60', '\U00010b72'), ('\U00010c00', '\U00010c48'), + ('\U00011000', '\U00011000'), ('\U00011001', '\U00011001'), + ('\U00011002', '\U00011002'), ('\U00011003', '\U00011037'), + ('\U00011038', '\U00011045'), ('\U00011082', '\U00011082'), + ('\U00011083', '\U000110af'), ('\U000110b0', '\U000110b2'), + ('\U000110b3', '\U000110b6'), ('\U000110b7', '\U000110b8'), + ('\U000110d0', '\U000110e8'), ('\U00011100', '\U00011102'), + ('\U00011103', '\U00011126'), ('\U00011127', '\U0001112b'), + ('\U0001112c', '\U0001112c'), ('\U0001112d', '\U00011132'), + ('\U00011180', '\U00011181'), ('\U00011182', '\U00011182'), + ('\U00011183', '\U000111b2'), ('\U000111b3', '\U000111b5'), + ('\U000111b6', '\U000111be'), ('\U000111bf', '\U000111bf'), + ('\U000111c1', '\U000111c4'), ('\U00011680', '\U000116aa'), + ('\U000116ab', '\U000116ab'), ('\U000116ac', '\U000116ac'), + ('\U000116ad', '\U000116ad'), ('\U000116ae', '\U000116af'), + ('\U000116b0', '\U000116b5'), ('\U00012000', '\U0001236e'), + ('\U00012400', '\U00012462'), ('\U00013000', '\U0001342e'), + ('\U00016800', '\U00016a38'), ('\U00016f00', '\U00016f44'), + ('\U00016f50', '\U00016f50'), ('\U00016f51', '\U00016f7e'), + ('\U00016f93', '\U00016f9f'), ('\U0001b000', '\U0001b001'), + ('\U0001d400', '\U0001d454'), ('\U0001d456', '\U0001d49c'), + ('\U0001d49e', '\U0001d49f'), ('\U0001d4a2', '\U0001d4a2'), + ('\U0001d4a5', '\U0001d4a6'), ('\U0001d4a9', '\U0001d4ac'), + ('\U0001d4ae', '\U0001d4b9'), ('\U0001d4bb', '\U0001d4bb'), + ('\U0001d4bd', '\U0001d4c3'), ('\U0001d4c5', '\U0001d505'), + ('\U0001d507', '\U0001d50a'), ('\U0001d50d', '\U0001d514'), + ('\U0001d516', '\U0001d51c'), ('\U0001d51e', '\U0001d539'), + ('\U0001d53b', '\U0001d53e'), ('\U0001d540', '\U0001d544'), + ('\U0001d546', '\U0001d546'), ('\U0001d54a', '\U0001d550'), + ('\U0001d552', '\U0001d6a5'), ('\U0001d6a8', '\U0001d6c0'), + ('\U0001d6c2', '\U0001d6da'), ('\U0001d6dc', '\U0001d6fa'), + ('\U0001d6fc', '\U0001d714'), ('\U0001d716', '\U0001d734'), + ('\U0001d736', '\U0001d74e'), ('\U0001d750', '\U0001d76e'), + ('\U0001d770', '\U0001d788'), ('\U0001d78a', '\U0001d7a8'), + ('\U0001d7aa', '\U0001d7c2'), ('\U0001d7c4', '\U0001d7cb'), + ('\U0001ee00', '\U0001ee03'), ('\U0001ee05', '\U0001ee1f'), + ('\U0001ee21', '\U0001ee22'), ('\U0001ee24', '\U0001ee24'), + ('\U0001ee27', '\U0001ee27'), ('\U0001ee29', '\U0001ee32'), + ('\U0001ee34', '\U0001ee37'), ('\U0001ee39', '\U0001ee39'), + ('\U0001ee3b', '\U0001ee3b'), ('\U0001ee42', '\U0001ee42'), + ('\U0001ee47', '\U0001ee47'), ('\U0001ee49', '\U0001ee49'), + ('\U0001ee4b', '\U0001ee4b'), ('\U0001ee4d', '\U0001ee4f'), + ('\U0001ee51', '\U0001ee52'), ('\U0001ee54', '\U0001ee54'), + ('\U0001ee57', '\U0001ee57'), ('\U0001ee59', '\U0001ee59'), + ('\U0001ee5b', '\U0001ee5b'), ('\U0001ee5d', '\U0001ee5d'), + ('\U0001ee5f', '\U0001ee5f'), ('\U0001ee61', '\U0001ee62'), + ('\U0001ee64', '\U0001ee64'), ('\U0001ee67', '\U0001ee6a'), + ('\U0001ee6c', '\U0001ee72'), ('\U0001ee74', '\U0001ee77'), + ('\U0001ee79', '\U0001ee7c'), ('\U0001ee7e', '\U0001ee7e'), + ('\U0001ee80', '\U0001ee89'), ('\U0001ee8b', '\U0001ee9b'), + ('\U0001eea1', '\U0001eea3'), ('\U0001eea5', '\U0001eea9'), + ('\U0001eeab', '\U0001eebb'), ('\U00020000', '\U0002a6d6'), + ('\U0002a700', '\U0002b734'), ('\U0002b740', '\U0002b81d'), + ('\U0002f800', '\U0002fa1d') + ]; + pub fn Alphabetic(c: char) -> bool { - return match c { - '\x41' .. '\x5a' - | '\x61' .. '\x7a' - | '\xaa' - | '\xb5' - | '\xba' - | '\xc0' .. '\xd6' - | '\xd8' .. '\xf6' - | '\xf8' .. '\u01ba' - | '\u01bb' - | '\u01bc' .. '\u01bf' - | '\u01c0' .. '\u01c3' - | '\u01c4' .. '\u0293' - | '\u0294' - | '\u0295' .. '\u02af' - | '\u02b0' .. '\u02c1' - | '\u02c6' .. '\u02d1' - | '\u02e0' .. '\u02e4' - | '\u02ec' - | '\u02ee' - | '\u0345' - | '\u0370' .. '\u0373' - | '\u0374' - | '\u0376' .. '\u0377' - | '\u037a' - | '\u037b' .. '\u037d' - | '\u0386' - | '\u0388' .. '\u038a' - | '\u038c' - | '\u038e' .. '\u03a1' - | '\u03a3' .. '\u03f5' - | '\u03f7' .. '\u0481' - | '\u048a' .. '\u0527' - | '\u0531' .. '\u0556' - | '\u0559' - | '\u0561' .. '\u0587' - | '\u05b0' .. '\u05bd' - | '\u05bf' - | '\u05c1' .. '\u05c2' - | '\u05c4' .. '\u05c5' - | '\u05c7' - | '\u05d0' .. '\u05ea' - | '\u05f0' .. '\u05f2' - | '\u0610' .. '\u061a' - | '\u0620' .. '\u063f' - | '\u0640' - | '\u0641' .. '\u064a' - | '\u064b' .. '\u0657' - | '\u0659' .. '\u065f' - | '\u066e' .. '\u066f' - | '\u0670' - | '\u0671' .. '\u06d3' - | '\u06d5' - | '\u06d6' .. '\u06dc' - | '\u06e1' .. '\u06e4' - | '\u06e5' .. '\u06e6' - | '\u06e7' .. '\u06e8' - | '\u06ed' - | '\u06ee' .. '\u06ef' - | '\u06fa' .. '\u06fc' - | '\u06ff' - | '\u0710' - | '\u0711' - | '\u0712' .. '\u072f' - | '\u0730' .. '\u073f' - | '\u074d' .. '\u07a5' - | '\u07a6' .. '\u07b0' - | '\u07b1' - | '\u07ca' .. '\u07ea' - | '\u07f4' .. '\u07f5' - | '\u07fa' - | '\u0800' .. '\u0815' - | '\u0816' .. '\u0817' - | '\u081a' - | '\u081b' .. '\u0823' - | '\u0824' - | '\u0825' .. '\u0827' - | '\u0828' - | '\u0829' .. '\u082c' - | '\u0840' .. '\u0858' - | '\u0900' .. '\u0902' - | '\u0903' - | '\u0904' .. '\u0939' - | '\u093a' - | '\u093b' - | '\u093d' - | '\u093e' .. '\u0940' - | '\u0941' .. '\u0948' - | '\u0949' .. '\u094c' - | '\u094e' .. '\u094f' - | '\u0950' - | '\u0955' .. '\u0957' - | '\u0958' .. '\u0961' - | '\u0962' .. '\u0963' - | '\u0971' - | '\u0972' .. '\u0977' - | '\u0979' .. '\u097f' - | '\u0981' - | '\u0982' .. '\u0983' - | '\u0985' .. '\u098c' - | '\u098f' .. '\u0990' - | '\u0993' .. '\u09a8' - | '\u09aa' .. '\u09b0' - | '\u09b2' - | '\u09b6' .. '\u09b9' - | '\u09bd' - | '\u09be' .. '\u09c0' - | '\u09c1' .. '\u09c4' - | '\u09c7' .. '\u09c8' - | '\u09cb' .. '\u09cc' - | '\u09ce' - | '\u09d7' - | '\u09dc' .. '\u09dd' - | '\u09df' .. '\u09e1' - | '\u09e2' .. '\u09e3' - | '\u09f0' .. '\u09f1' - | '\u0a01' .. '\u0a02' - | '\u0a03' - | '\u0a05' .. '\u0a0a' - | '\u0a0f' .. '\u0a10' - | '\u0a13' .. '\u0a28' - | '\u0a2a' .. '\u0a30' - | '\u0a32' .. '\u0a33' - | '\u0a35' .. '\u0a36' - | '\u0a38' .. '\u0a39' - | '\u0a3e' .. '\u0a40' - | '\u0a41' .. '\u0a42' - | '\u0a47' .. '\u0a48' - | '\u0a4b' .. '\u0a4c' - | '\u0a51' - | '\u0a59' .. '\u0a5c' - | '\u0a5e' - | '\u0a70' .. '\u0a71' - | '\u0a72' .. '\u0a74' - | '\u0a75' - | '\u0a81' .. '\u0a82' - | '\u0a83' - | '\u0a85' .. '\u0a8d' - | '\u0a8f' .. '\u0a91' - | '\u0a93' .. '\u0aa8' - | '\u0aaa' .. '\u0ab0' - | '\u0ab2' .. '\u0ab3' - | '\u0ab5' .. '\u0ab9' - | '\u0abd' - | '\u0abe' .. '\u0ac0' - | '\u0ac1' .. '\u0ac5' - | '\u0ac7' .. '\u0ac8' - | '\u0ac9' - | '\u0acb' .. '\u0acc' - | '\u0ad0' - | '\u0ae0' .. '\u0ae1' - | '\u0ae2' .. '\u0ae3' - | '\u0b01' - | '\u0b02' .. '\u0b03' - | '\u0b05' .. '\u0b0c' - | '\u0b0f' .. '\u0b10' - | '\u0b13' .. '\u0b28' - | '\u0b2a' .. '\u0b30' - | '\u0b32' .. '\u0b33' - | '\u0b35' .. '\u0b39' - | '\u0b3d' - | '\u0b3e' - | '\u0b3f' - | '\u0b40' - | '\u0b41' .. '\u0b44' - | '\u0b47' .. '\u0b48' - | '\u0b4b' .. '\u0b4c' - | '\u0b56' - | '\u0b57' - | '\u0b5c' .. '\u0b5d' - | '\u0b5f' .. '\u0b61' - | '\u0b62' .. '\u0b63' - | '\u0b71' - | '\u0b82' - | '\u0b83' - | '\u0b85' .. '\u0b8a' - | '\u0b8e' .. '\u0b90' - | '\u0b92' .. '\u0b95' - | '\u0b99' .. '\u0b9a' - | '\u0b9c' - | '\u0b9e' .. '\u0b9f' - | '\u0ba3' .. '\u0ba4' - | '\u0ba8' .. '\u0baa' - | '\u0bae' .. '\u0bb9' - | '\u0bbe' .. '\u0bbf' - | '\u0bc0' - | '\u0bc1' .. '\u0bc2' - | '\u0bc6' .. '\u0bc8' - | '\u0bca' .. '\u0bcc' - | '\u0bd0' - | '\u0bd7' - | '\u0c01' .. '\u0c03' - | '\u0c05' .. '\u0c0c' - | '\u0c0e' .. '\u0c10' - | '\u0c12' .. '\u0c28' - | '\u0c2a' .. '\u0c33' - | '\u0c35' .. '\u0c39' - | '\u0c3d' - | '\u0c3e' .. '\u0c40' - | '\u0c41' .. '\u0c44' - | '\u0c46' .. '\u0c48' - | '\u0c4a' .. '\u0c4c' - | '\u0c55' .. '\u0c56' - | '\u0c58' .. '\u0c59' - | '\u0c60' .. '\u0c61' - | '\u0c62' .. '\u0c63' - | '\u0c82' .. '\u0c83' - | '\u0c85' .. '\u0c8c' - | '\u0c8e' .. '\u0c90' - | '\u0c92' .. '\u0ca8' - | '\u0caa' .. '\u0cb3' - | '\u0cb5' .. '\u0cb9' - | '\u0cbd' - | '\u0cbe' - | '\u0cbf' - | '\u0cc0' .. '\u0cc4' - | '\u0cc6' - | '\u0cc7' .. '\u0cc8' - | '\u0cca' .. '\u0ccb' - | '\u0ccc' - | '\u0cd5' .. '\u0cd6' - | '\u0cde' - | '\u0ce0' .. '\u0ce1' - | '\u0ce2' .. '\u0ce3' - | '\u0cf1' .. '\u0cf2' - | '\u0d02' .. '\u0d03' - | '\u0d05' .. '\u0d0c' - | '\u0d0e' .. '\u0d10' - | '\u0d12' .. '\u0d3a' - | '\u0d3d' - | '\u0d3e' .. '\u0d40' - | '\u0d41' .. '\u0d44' - | '\u0d46' .. '\u0d48' - | '\u0d4a' .. '\u0d4c' - | '\u0d4e' - | '\u0d57' - | '\u0d60' .. '\u0d61' - | '\u0d62' .. '\u0d63' - | '\u0d7a' .. '\u0d7f' - | '\u0d82' .. '\u0d83' - | '\u0d85' .. '\u0d96' - | '\u0d9a' .. '\u0db1' - | '\u0db3' .. '\u0dbb' - | '\u0dbd' - | '\u0dc0' .. '\u0dc6' - | '\u0dcf' .. '\u0dd1' - | '\u0dd2' .. '\u0dd4' - | '\u0dd6' - | '\u0dd8' .. '\u0ddf' - | '\u0df2' .. '\u0df3' - | '\u0e01' .. '\u0e30' - | '\u0e31' - | '\u0e32' .. '\u0e33' - | '\u0e34' .. '\u0e3a' - | '\u0e40' .. '\u0e45' - | '\u0e46' - | '\u0e4d' - | '\u0e81' .. '\u0e82' - | '\u0e84' - | '\u0e87' .. '\u0e88' - | '\u0e8a' - | '\u0e8d' - | '\u0e94' .. '\u0e97' - | '\u0e99' .. '\u0e9f' - | '\u0ea1' .. '\u0ea3' - | '\u0ea5' - | '\u0ea7' - | '\u0eaa' .. '\u0eab' - | '\u0ead' .. '\u0eb0' - | '\u0eb1' - | '\u0eb2' .. '\u0eb3' - | '\u0eb4' .. '\u0eb9' - | '\u0ebb' .. '\u0ebc' - | '\u0ebd' - | '\u0ec0' .. '\u0ec4' - | '\u0ec6' - | '\u0ecd' - | '\u0edc' .. '\u0edd' - | '\u0f00' - | '\u0f40' .. '\u0f47' - | '\u0f49' .. '\u0f6c' - | '\u0f71' .. '\u0f7e' - | '\u0f7f' - | '\u0f80' .. '\u0f81' - | '\u0f88' .. '\u0f8c' - | '\u0f8d' .. '\u0f97' - | '\u0f99' .. '\u0fbc' - | '\u1000' .. '\u102a' - | '\u102b' .. '\u102c' - | '\u102d' .. '\u1030' - | '\u1031' - | '\u1032' .. '\u1036' - | '\u1038' - | '\u103b' .. '\u103c' - | '\u103d' .. '\u103e' - | '\u103f' - | '\u1050' .. '\u1055' - | '\u1056' .. '\u1057' - | '\u1058' .. '\u1059' - | '\u105a' .. '\u105d' - | '\u105e' .. '\u1060' - | '\u1061' - | '\u1062' - | '\u1065' .. '\u1066' - | '\u1067' .. '\u1068' - | '\u106e' .. '\u1070' - | '\u1071' .. '\u1074' - | '\u1075' .. '\u1081' - | '\u1082' - | '\u1083' .. '\u1084' - | '\u1085' .. '\u1086' - | '\u108e' - | '\u109c' - | '\u109d' - | '\u10a0' .. '\u10c5' - | '\u10d0' .. '\u10fa' - | '\u10fc' - | '\u1100' .. '\u1248' - | '\u124a' .. '\u124d' - | '\u1250' .. '\u1256' - | '\u1258' - | '\u125a' .. '\u125d' - | '\u1260' .. '\u1288' - | '\u128a' .. '\u128d' - | '\u1290' .. '\u12b0' - | '\u12b2' .. '\u12b5' - | '\u12b8' .. '\u12be' - | '\u12c0' - | '\u12c2' .. '\u12c5' - | '\u12c8' .. '\u12d6' - | '\u12d8' .. '\u1310' - | '\u1312' .. '\u1315' - | '\u1318' .. '\u135a' - | '\u135f' - | '\u1380' .. '\u138f' - | '\u13a0' .. '\u13f4' - | '\u1401' .. '\u166c' - | '\u166f' .. '\u167f' - | '\u1681' .. '\u169a' - | '\u16a0' .. '\u16ea' - | '\u16ee' .. '\u16f0' - | '\u1700' .. '\u170c' - | '\u170e' .. '\u1711' - | '\u1712' .. '\u1713' - | '\u1720' .. '\u1731' - | '\u1732' .. '\u1733' - | '\u1740' .. '\u1751' - | '\u1752' .. '\u1753' - | '\u1760' .. '\u176c' - | '\u176e' .. '\u1770' - | '\u1772' .. '\u1773' - | '\u1780' .. '\u17b3' - | '\u17b6' - | '\u17b7' .. '\u17bd' - | '\u17be' .. '\u17c5' - | '\u17c6' - | '\u17c7' .. '\u17c8' - | '\u17d7' - | '\u17dc' - | '\u1820' .. '\u1842' - | '\u1843' - | '\u1844' .. '\u1877' - | '\u1880' .. '\u18a8' - | '\u18a9' - | '\u18aa' - | '\u18b0' .. '\u18f5' - | '\u1900' .. '\u191c' - | '\u1920' .. '\u1922' - | '\u1923' .. '\u1926' - | '\u1927' .. '\u1928' - | '\u1929' .. '\u192b' - | '\u1930' .. '\u1931' - | '\u1932' - | '\u1933' .. '\u1938' - | '\u1950' .. '\u196d' - | '\u1970' .. '\u1974' - | '\u1980' .. '\u19ab' - | '\u19b0' .. '\u19c0' - | '\u19c1' .. '\u19c7' - | '\u19c8' .. '\u19c9' - | '\u1a00' .. '\u1a16' - | '\u1a17' .. '\u1a18' - | '\u1a19' .. '\u1a1b' - | '\u1a20' .. '\u1a54' - | '\u1a55' - | '\u1a56' - | '\u1a57' - | '\u1a58' .. '\u1a5e' - | '\u1a61' - | '\u1a62' - | '\u1a63' .. '\u1a64' - | '\u1a65' .. '\u1a6c' - | '\u1a6d' .. '\u1a72' - | '\u1a73' .. '\u1a74' - | '\u1aa7' - | '\u1b00' .. '\u1b03' - | '\u1b04' - | '\u1b05' .. '\u1b33' - | '\u1b35' - | '\u1b36' .. '\u1b3a' - | '\u1b3b' - | '\u1b3c' - | '\u1b3d' .. '\u1b41' - | '\u1b42' - | '\u1b43' - | '\u1b45' .. '\u1b4b' - | '\u1b80' .. '\u1b81' - | '\u1b82' - | '\u1b83' .. '\u1ba0' - | '\u1ba1' - | '\u1ba2' .. '\u1ba5' - | '\u1ba6' .. '\u1ba7' - | '\u1ba8' .. '\u1ba9' - | '\u1bae' .. '\u1baf' - | '\u1bc0' .. '\u1be5' - | '\u1be7' - | '\u1be8' .. '\u1be9' - | '\u1bea' .. '\u1bec' - | '\u1bed' - | '\u1bee' - | '\u1bef' .. '\u1bf1' - | '\u1c00' .. '\u1c23' - | '\u1c24' .. '\u1c2b' - | '\u1c2c' .. '\u1c33' - | '\u1c34' .. '\u1c35' - | '\u1c4d' .. '\u1c4f' - | '\u1c5a' .. '\u1c77' - | '\u1c78' .. '\u1c7d' - | '\u1ce9' .. '\u1cec' - | '\u1cee' .. '\u1cf1' - | '\u1cf2' - | '\u1d00' .. '\u1d2b' - | '\u1d2c' .. '\u1d61' - | '\u1d62' .. '\u1d77' - | '\u1d78' - | '\u1d79' .. '\u1d9a' - | '\u1d9b' .. '\u1dbf' - | '\u1e00' .. '\u1f15' - | '\u1f18' .. '\u1f1d' - | '\u1f20' .. '\u1f45' - | '\u1f48' .. '\u1f4d' - | '\u1f50' .. '\u1f57' - | '\u1f59' - | '\u1f5b' - | '\u1f5d' - | '\u1f5f' .. '\u1f7d' - | '\u1f80' .. '\u1fb4' - | '\u1fb6' .. '\u1fbc' - | '\u1fbe' - | '\u1fc2' .. '\u1fc4' - | '\u1fc6' .. '\u1fcc' - | '\u1fd0' .. '\u1fd3' - | '\u1fd6' .. '\u1fdb' - | '\u1fe0' .. '\u1fec' - | '\u1ff2' .. '\u1ff4' - | '\u1ff6' .. '\u1ffc' - | '\u2071' - | '\u207f' - | '\u2090' .. '\u209c' - | '\u2102' - | '\u2107' - | '\u210a' .. '\u2113' - | '\u2115' - | '\u2119' .. '\u211d' - | '\u2124' - | '\u2126' - | '\u2128' - | '\u212a' .. '\u212d' - | '\u212f' .. '\u2134' - | '\u2135' .. '\u2138' - | '\u2139' - | '\u213c' .. '\u213f' - | '\u2145' .. '\u2149' - | '\u214e' - | '\u2160' .. '\u2182' - | '\u2183' .. '\u2184' - | '\u2185' .. '\u2188' - | '\u24b6' .. '\u24e9' - | '\u2c00' .. '\u2c2e' - | '\u2c30' .. '\u2c5e' - | '\u2c60' .. '\u2c7c' - | '\u2c7d' - | '\u2c7e' .. '\u2ce4' - | '\u2ceb' .. '\u2cee' - | '\u2d00' .. '\u2d25' - | '\u2d30' .. '\u2d65' - | '\u2d6f' - | '\u2d80' .. '\u2d96' - | '\u2da0' .. '\u2da6' - | '\u2da8' .. '\u2dae' - | '\u2db0' .. '\u2db6' - | '\u2db8' .. '\u2dbe' - | '\u2dc0' .. '\u2dc6' - | '\u2dc8' .. '\u2dce' - | '\u2dd0' .. '\u2dd6' - | '\u2dd8' .. '\u2dde' - | '\u2de0' .. '\u2dff' - | '\u2e2f' - | '\u3005' - | '\u3006' - | '\u3007' - | '\u3021' .. '\u3029' - | '\u3031' .. '\u3035' - | '\u3038' .. '\u303a' - | '\u303b' - | '\u303c' - | '\u3041' .. '\u3096' - | '\u309d' .. '\u309e' - | '\u309f' - | '\u30a1' .. '\u30fa' - | '\u30fc' .. '\u30fe' - | '\u30ff' - | '\u3105' .. '\u312d' - | '\u3131' .. '\u318e' - | '\u31a0' .. '\u31ba' - | '\u31f0' .. '\u31ff' - | '\u3400' .. '\u4db5' - | '\u4e00' .. '\u9fcb' - | '\ua000' .. '\ua014' - | '\ua015' - | '\ua016' .. '\ua48c' - | '\ua4d0' .. '\ua4f7' - | '\ua4f8' .. '\ua4fd' - | '\ua500' .. '\ua60b' - | '\ua60c' - | '\ua610' .. '\ua61f' - | '\ua62a' .. '\ua62b' - | '\ua640' .. '\ua66d' - | '\ua66e' - | '\ua67f' - | '\ua680' .. '\ua697' - | '\ua6a0' .. '\ua6e5' - | '\ua6e6' .. '\ua6ef' - | '\ua717' .. '\ua71f' - | '\ua722' .. '\ua76f' - | '\ua770' - | '\ua771' .. '\ua787' - | '\ua788' - | '\ua78b' .. '\ua78e' - | '\ua790' .. '\ua791' - | '\ua7a0' .. '\ua7a9' - | '\ua7fa' - | '\ua7fb' .. '\ua801' - | '\ua803' .. '\ua805' - | '\ua807' .. '\ua80a' - | '\ua80c' .. '\ua822' - | '\ua823' .. '\ua824' - | '\ua825' .. '\ua826' - | '\ua827' - | '\ua840' .. '\ua873' - | '\ua880' .. '\ua881' - | '\ua882' .. '\ua8b3' - | '\ua8b4' .. '\ua8c3' - | '\ua8f2' .. '\ua8f7' - | '\ua8fb' - | '\ua90a' .. '\ua925' - | '\ua926' .. '\ua92a' - | '\ua930' .. '\ua946' - | '\ua947' .. '\ua951' - | '\ua952' - | '\ua960' .. '\ua97c' - | '\ua980' .. '\ua982' - | '\ua983' - | '\ua984' .. '\ua9b2' - | '\ua9b4' .. '\ua9b5' - | '\ua9b6' .. '\ua9b9' - | '\ua9ba' .. '\ua9bb' - | '\ua9bc' - | '\ua9bd' .. '\ua9bf' - | '\ua9cf' - | '\uaa00' .. '\uaa28' - | '\uaa29' .. '\uaa2e' - | '\uaa2f' .. '\uaa30' - | '\uaa31' .. '\uaa32' - | '\uaa33' .. '\uaa34' - | '\uaa35' .. '\uaa36' - | '\uaa40' .. '\uaa42' - | '\uaa43' - | '\uaa44' .. '\uaa4b' - | '\uaa4c' - | '\uaa4d' - | '\uaa60' .. '\uaa6f' - | '\uaa70' - | '\uaa71' .. '\uaa76' - | '\uaa7a' - | '\uaa80' .. '\uaaaf' - | '\uaab0' - | '\uaab1' - | '\uaab2' .. '\uaab4' - | '\uaab5' .. '\uaab6' - | '\uaab7' .. '\uaab8' - | '\uaab9' .. '\uaabd' - | '\uaabe' - | '\uaac0' - | '\uaac2' - | '\uaadb' .. '\uaadc' - | '\uaadd' - | '\uab01' .. '\uab06' - | '\uab09' .. '\uab0e' - | '\uab11' .. '\uab16' - | '\uab20' .. '\uab26' - | '\uab28' .. '\uab2e' - | '\uabc0' .. '\uabe2' - | '\uabe3' .. '\uabe4' - | '\uabe5' - | '\uabe6' .. '\uabe7' - | '\uabe8' - | '\uabe9' .. '\uabea' - | '\uac00' .. '\ud7a3' - | '\ud7b0' .. '\ud7c6' - | '\ud7cb' .. '\ud7fb' - | '\uf900' .. '\ufa2d' - | '\ufa30' .. '\ufa6d' - | '\ufa70' .. '\ufad9' - | '\ufb00' .. '\ufb06' - | '\ufb13' .. '\ufb17' - | '\ufb1d' - | '\ufb1e' - | '\ufb1f' .. '\ufb28' - | '\ufb2a' .. '\ufb36' - | '\ufb38' .. '\ufb3c' - | '\ufb3e' - | '\ufb40' .. '\ufb41' - | '\ufb43' .. '\ufb44' - | '\ufb46' .. '\ufbb1' - | '\ufbd3' .. '\ufd3d' - | '\ufd50' .. '\ufd8f' - | '\ufd92' .. '\ufdc7' - | '\ufdf0' .. '\ufdfb' - | '\ufe70' .. '\ufe74' - | '\ufe76' .. '\ufefc' - | '\uff21' .. '\uff3a' - | '\uff41' .. '\uff5a' - | '\uff66' .. '\uff6f' - | '\uff70' - | '\uff71' .. '\uff9d' - | '\uff9e' .. '\uff9f' - | '\uffa0' .. '\uffbe' - | '\uffc2' .. '\uffc7' - | '\uffca' .. '\uffcf' - | '\uffd2' .. '\uffd7' - | '\uffda' .. '\uffdc' - | '\U00010000' .. '\U0001000b' - | '\U0001000d' .. '\U00010026' - | '\U00010028' .. '\U0001003a' - | '\U0001003c' .. '\U0001003d' - | '\U0001003f' .. '\U0001004d' - | '\U00010050' .. '\U0001005d' - | '\U00010080' .. '\U000100fa' - | '\U00010140' .. '\U00010174' - | '\U00010280' .. '\U0001029c' - | '\U000102a0' .. '\U000102d0' - | '\U00010300' .. '\U0001031e' - | '\U00010330' .. '\U00010340' - | '\U00010341' - | '\U00010342' .. '\U00010349' - | '\U0001034a' - | '\U00010380' .. '\U0001039d' - | '\U000103a0' .. '\U000103c3' - | '\U000103c8' .. '\U000103cf' - | '\U000103d1' .. '\U000103d5' - | '\U00010400' .. '\U0001044f' - | '\U00010450' .. '\U0001049d' - | '\U00010800' .. '\U00010805' - | '\U00010808' - | '\U0001080a' .. '\U00010835' - | '\U00010837' .. '\U00010838' - | '\U0001083c' - | '\U0001083f' .. '\U00010855' - | '\U00010900' .. '\U00010915' - | '\U00010920' .. '\U00010939' - | '\U00010a00' - | '\U00010a01' .. '\U00010a03' - | '\U00010a05' .. '\U00010a06' - | '\U00010a0c' .. '\U00010a0f' - | '\U00010a10' .. '\U00010a13' - | '\U00010a15' .. '\U00010a17' - | '\U00010a19' .. '\U00010a33' - | '\U00010a60' .. '\U00010a7c' - | '\U00010b00' .. '\U00010b35' - | '\U00010b40' .. '\U00010b55' - | '\U00010b60' .. '\U00010b72' - | '\U00010c00' .. '\U00010c48' - | '\U00011000' - | '\U00011001' - | '\U00011002' - | '\U00011003' .. '\U00011037' - | '\U00011038' .. '\U00011045' - | '\U00011082' - | '\U00011083' .. '\U000110af' - | '\U000110b0' .. '\U000110b2' - | '\U000110b3' .. '\U000110b6' - | '\U000110b7' .. '\U000110b8' - | '\U00012000' .. '\U0001236e' - | '\U00012400' .. '\U00012462' - | '\U00013000' .. '\U0001342e' - | '\U00016800' .. '\U00016a38' - | '\U0001b000' .. '\U0001b001' - | '\U0001d400' .. '\U0001d454' - | '\U0001d456' .. '\U0001d49c' - | '\U0001d49e' .. '\U0001d49f' - | '\U0001d4a2' - | '\U0001d4a5' .. '\U0001d4a6' - | '\U0001d4a9' .. '\U0001d4ac' - | '\U0001d4ae' .. '\U0001d4b9' - | '\U0001d4bb' - | '\U0001d4bd' .. '\U0001d4c3' - | '\U0001d4c5' .. '\U0001d505' - | '\U0001d507' .. '\U0001d50a' - | '\U0001d50d' .. '\U0001d514' - | '\U0001d516' .. '\U0001d51c' - | '\U0001d51e' .. '\U0001d539' - | '\U0001d53b' .. '\U0001d53e' - | '\U0001d540' .. '\U0001d544' - | '\U0001d546' - | '\U0001d54a' .. '\U0001d550' - | '\U0001d552' .. '\U0001d6a5' - | '\U0001d6a8' .. '\U0001d6c0' - | '\U0001d6c2' .. '\U0001d6da' - | '\U0001d6dc' .. '\U0001d6fa' - | '\U0001d6fc' .. '\U0001d714' - | '\U0001d716' .. '\U0001d734' - | '\U0001d736' .. '\U0001d74e' - | '\U0001d750' .. '\U0001d76e' - | '\U0001d770' .. '\U0001d788' - | '\U0001d78a' .. '\U0001d7a8' - | '\U0001d7aa' .. '\U0001d7c2' - | '\U0001d7c4' .. '\U0001d7cb' - | '\U00020000' .. '\U0002a6d6' - | '\U0002a700' .. '\U0002b734' - | '\U0002b740' .. '\U0002b81d' - | '\U0002f800' .. '\U0002fa1d' - => true, - _ => false - }; + bsearch_range_table(c, Alphabetic_table) } + static XID_Continue_table : &'static [(char,char)] = &[ + ('\x30', '\x39'), ('\x41', '\x5a'), + ('\x5f', '\x5f'), ('\x61', '\x7a'), + ('\xaa', '\xaa'), ('\xb5', '\xb5'), + ('\xb7', '\xb7'), ('\xba', '\xba'), + ('\xc0', '\xd6'), ('\xd8', '\xf6'), + ('\xf8', '\u01ba'), ('\u01bb', '\u01bb'), + ('\u01bc', '\u01bf'), ('\u01c0', '\u01c3'), + ('\u01c4', '\u0293'), ('\u0294', '\u0294'), + ('\u0295', '\u02af'), ('\u02b0', '\u02c1'), + ('\u02c6', '\u02d1'), ('\u02e0', '\u02e4'), + ('\u02ec', '\u02ec'), ('\u02ee', '\u02ee'), + ('\u0300', '\u036f'), ('\u0370', '\u0373'), + ('\u0374', '\u0374'), ('\u0376', '\u0377'), + ('\u037b', '\u037d'), ('\u0386', '\u0386'), + ('\u0387', '\u0387'), ('\u0388', '\u038a'), + ('\u038c', '\u038c'), ('\u038e', '\u03a1'), + ('\u03a3', '\u03f5'), ('\u03f7', '\u0481'), + ('\u0483', '\u0487'), ('\u048a', '\u0527'), + ('\u0531', '\u0556'), ('\u0559', '\u0559'), + ('\u0561', '\u0587'), ('\u0591', '\u05bd'), + ('\u05bf', '\u05bf'), ('\u05c1', '\u05c2'), + ('\u05c4', '\u05c5'), ('\u05c7', '\u05c7'), + ('\u05d0', '\u05ea'), ('\u05f0', '\u05f2'), + ('\u0610', '\u061a'), ('\u0620', '\u063f'), + ('\u0640', '\u0640'), ('\u0641', '\u064a'), + ('\u064b', '\u065f'), ('\u0660', '\u0669'), + ('\u066e', '\u066f'), ('\u0670', '\u0670'), + ('\u0671', '\u06d3'), ('\u06d5', '\u06d5'), + ('\u06d6', '\u06dc'), ('\u06df', '\u06e4'), + ('\u06e5', '\u06e6'), ('\u06e7', '\u06e8'), + ('\u06ea', '\u06ed'), ('\u06ee', '\u06ef'), + ('\u06f0', '\u06f9'), ('\u06fa', '\u06fc'), + ('\u06ff', '\u06ff'), ('\u0710', '\u0710'), + ('\u0711', '\u0711'), ('\u0712', '\u072f'), + ('\u0730', '\u074a'), ('\u074d', '\u07a5'), + ('\u07a6', '\u07b0'), ('\u07b1', '\u07b1'), + ('\u07c0', '\u07c9'), ('\u07ca', '\u07ea'), + ('\u07eb', '\u07f3'), ('\u07f4', '\u07f5'), + ('\u07fa', '\u07fa'), ('\u0800', '\u0815'), + ('\u0816', '\u0819'), ('\u081a', '\u081a'), + ('\u081b', '\u0823'), ('\u0824', '\u0824'), + ('\u0825', '\u0827'), ('\u0828', '\u0828'), + ('\u0829', '\u082d'), ('\u0840', '\u0858'), + ('\u0859', '\u085b'), ('\u08a0', '\u08a0'), + ('\u08a2', '\u08ac'), ('\u08e4', '\u08fe'), + ('\u0900', '\u0902'), ('\u0903', '\u0903'), + ('\u0904', '\u0939'), ('\u093a', '\u093a'), + ('\u093b', '\u093b'), ('\u093c', '\u093c'), + ('\u093d', '\u093d'), ('\u093e', '\u0940'), + ('\u0941', '\u0948'), ('\u0949', '\u094c'), + ('\u094d', '\u094d'), ('\u094e', '\u094f'), + ('\u0950', '\u0950'), ('\u0951', '\u0957'), + ('\u0958', '\u0961'), ('\u0962', '\u0963'), + ('\u0966', '\u096f'), ('\u0971', '\u0971'), + ('\u0972', '\u0977'), ('\u0979', '\u097f'), + ('\u0981', '\u0981'), ('\u0982', '\u0983'), + ('\u0985', '\u098c'), ('\u098f', '\u0990'), + ('\u0993', '\u09a8'), ('\u09aa', '\u09b0'), + ('\u09b2', '\u09b2'), ('\u09b6', '\u09b9'), + ('\u09bc', '\u09bc'), ('\u09bd', '\u09bd'), + ('\u09be', '\u09c0'), ('\u09c1', '\u09c4'), + ('\u09c7', '\u09c8'), ('\u09cb', '\u09cc'), + ('\u09cd', '\u09cd'), ('\u09ce', '\u09ce'), + ('\u09d7', '\u09d7'), ('\u09dc', '\u09dd'), + ('\u09df', '\u09e1'), ('\u09e2', '\u09e3'), + ('\u09e6', '\u09ef'), ('\u09f0', '\u09f1'), + ('\u0a01', '\u0a02'), ('\u0a03', '\u0a03'), + ('\u0a05', '\u0a0a'), ('\u0a0f', '\u0a10'), + ('\u0a13', '\u0a28'), ('\u0a2a', '\u0a30'), + ('\u0a32', '\u0a33'), ('\u0a35', '\u0a36'), + ('\u0a38', '\u0a39'), ('\u0a3c', '\u0a3c'), + ('\u0a3e', '\u0a40'), ('\u0a41', '\u0a42'), + ('\u0a47', '\u0a48'), ('\u0a4b', '\u0a4d'), + ('\u0a51', '\u0a51'), ('\u0a59', '\u0a5c'), + ('\u0a5e', '\u0a5e'), ('\u0a66', '\u0a6f'), + ('\u0a70', '\u0a71'), ('\u0a72', '\u0a74'), + ('\u0a75', '\u0a75'), ('\u0a81', '\u0a82'), + ('\u0a83', '\u0a83'), ('\u0a85', '\u0a8d'), + ('\u0a8f', '\u0a91'), ('\u0a93', '\u0aa8'), + ('\u0aaa', '\u0ab0'), ('\u0ab2', '\u0ab3'), + ('\u0ab5', '\u0ab9'), ('\u0abc', '\u0abc'), + ('\u0abd', '\u0abd'), ('\u0abe', '\u0ac0'), + ('\u0ac1', '\u0ac5'), ('\u0ac7', '\u0ac8'), + ('\u0ac9', '\u0ac9'), ('\u0acb', '\u0acc'), + ('\u0acd', '\u0acd'), ('\u0ad0', '\u0ad0'), + ('\u0ae0', '\u0ae1'), ('\u0ae2', '\u0ae3'), + ('\u0ae6', '\u0aef'), ('\u0b01', '\u0b01'), + ('\u0b02', '\u0b03'), ('\u0b05', '\u0b0c'), + ('\u0b0f', '\u0b10'), ('\u0b13', '\u0b28'), + ('\u0b2a', '\u0b30'), ('\u0b32', '\u0b33'), + ('\u0b35', '\u0b39'), ('\u0b3c', '\u0b3c'), + ('\u0b3d', '\u0b3d'), ('\u0b3e', '\u0b3e'), + ('\u0b3f', '\u0b3f'), ('\u0b40', '\u0b40'), + ('\u0b41', '\u0b44'), ('\u0b47', '\u0b48'), + ('\u0b4b', '\u0b4c'), ('\u0b4d', '\u0b4d'), + ('\u0b56', '\u0b56'), ('\u0b57', '\u0b57'), + ('\u0b5c', '\u0b5d'), ('\u0b5f', '\u0b61'), + ('\u0b62', '\u0b63'), ('\u0b66', '\u0b6f'), + ('\u0b71', '\u0b71'), ('\u0b82', '\u0b82'), + ('\u0b83', '\u0b83'), ('\u0b85', '\u0b8a'), + ('\u0b8e', '\u0b90'), ('\u0b92', '\u0b95'), + ('\u0b99', '\u0b9a'), ('\u0b9c', '\u0b9c'), + ('\u0b9e', '\u0b9f'), ('\u0ba3', '\u0ba4'), + ('\u0ba8', '\u0baa'), ('\u0bae', '\u0bb9'), + ('\u0bbe', '\u0bbf'), ('\u0bc0', '\u0bc0'), + ('\u0bc1', '\u0bc2'), ('\u0bc6', '\u0bc8'), + ('\u0bca', '\u0bcc'), ('\u0bcd', '\u0bcd'), + ('\u0bd0', '\u0bd0'), ('\u0bd7', '\u0bd7'), + ('\u0be6', '\u0bef'), ('\u0c01', '\u0c03'), + ('\u0c05', '\u0c0c'), ('\u0c0e', '\u0c10'), + ('\u0c12', '\u0c28'), ('\u0c2a', '\u0c33'), + ('\u0c35', '\u0c39'), ('\u0c3d', '\u0c3d'), + ('\u0c3e', '\u0c40'), ('\u0c41', '\u0c44'), + ('\u0c46', '\u0c48'), ('\u0c4a', '\u0c4d'), + ('\u0c55', '\u0c56'), ('\u0c58', '\u0c59'), + ('\u0c60', '\u0c61'), ('\u0c62', '\u0c63'), + ('\u0c66', '\u0c6f'), ('\u0c82', '\u0c83'), + ('\u0c85', '\u0c8c'), ('\u0c8e', '\u0c90'), + ('\u0c92', '\u0ca8'), ('\u0caa', '\u0cb3'), + ('\u0cb5', '\u0cb9'), ('\u0cbc', '\u0cbc'), + ('\u0cbd', '\u0cbd'), ('\u0cbe', '\u0cbe'), + ('\u0cbf', '\u0cbf'), ('\u0cc0', '\u0cc4'), + ('\u0cc6', '\u0cc6'), ('\u0cc7', '\u0cc8'), + ('\u0cca', '\u0ccb'), ('\u0ccc', '\u0ccd'), + ('\u0cd5', '\u0cd6'), ('\u0cde', '\u0cde'), + ('\u0ce0', '\u0ce1'), ('\u0ce2', '\u0ce3'), + ('\u0ce6', '\u0cef'), ('\u0cf1', '\u0cf2'), + ('\u0d02', '\u0d03'), ('\u0d05', '\u0d0c'), + ('\u0d0e', '\u0d10'), ('\u0d12', '\u0d3a'), + ('\u0d3d', '\u0d3d'), ('\u0d3e', '\u0d40'), + ('\u0d41', '\u0d44'), ('\u0d46', '\u0d48'), + ('\u0d4a', '\u0d4c'), ('\u0d4d', '\u0d4d'), + ('\u0d4e', '\u0d4e'), ('\u0d57', '\u0d57'), + ('\u0d60', '\u0d61'), ('\u0d62', '\u0d63'), + ('\u0d66', '\u0d6f'), ('\u0d7a', '\u0d7f'), + ('\u0d82', '\u0d83'), ('\u0d85', '\u0d96'), + ('\u0d9a', '\u0db1'), ('\u0db3', '\u0dbb'), + ('\u0dbd', '\u0dbd'), ('\u0dc0', '\u0dc6'), + ('\u0dca', '\u0dca'), ('\u0dcf', '\u0dd1'), + ('\u0dd2', '\u0dd4'), ('\u0dd6', '\u0dd6'), + ('\u0dd8', '\u0ddf'), ('\u0df2', '\u0df3'), + ('\u0e01', '\u0e30'), ('\u0e31', '\u0e31'), + ('\u0e32', '\u0e33'), ('\u0e34', '\u0e3a'), + ('\u0e40', '\u0e45'), ('\u0e46', '\u0e46'), + ('\u0e47', '\u0e4e'), ('\u0e50', '\u0e59'), + ('\u0e81', '\u0e82'), ('\u0e84', '\u0e84'), + ('\u0e87', '\u0e88'), ('\u0e8a', '\u0e8a'), + ('\u0e8d', '\u0e8d'), ('\u0e94', '\u0e97'), + ('\u0e99', '\u0e9f'), ('\u0ea1', '\u0ea3'), + ('\u0ea5', '\u0ea5'), ('\u0ea7', '\u0ea7'), + ('\u0eaa', '\u0eab'), ('\u0ead', '\u0eb0'), + ('\u0eb1', '\u0eb1'), ('\u0eb2', '\u0eb3'), + ('\u0eb4', '\u0eb9'), ('\u0ebb', '\u0ebc'), + ('\u0ebd', '\u0ebd'), ('\u0ec0', '\u0ec4'), + ('\u0ec6', '\u0ec6'), ('\u0ec8', '\u0ecd'), + ('\u0ed0', '\u0ed9'), ('\u0edc', '\u0edf'), + ('\u0f00', '\u0f00'), ('\u0f18', '\u0f19'), + ('\u0f20', '\u0f29'), ('\u0f35', '\u0f35'), + ('\u0f37', '\u0f37'), ('\u0f39', '\u0f39'), + ('\u0f3e', '\u0f3f'), ('\u0f40', '\u0f47'), + ('\u0f49', '\u0f6c'), ('\u0f71', '\u0f7e'), + ('\u0f7f', '\u0f7f'), ('\u0f80', '\u0f84'), + ('\u0f86', '\u0f87'), ('\u0f88', '\u0f8c'), + ('\u0f8d', '\u0f97'), ('\u0f99', '\u0fbc'), + ('\u0fc6', '\u0fc6'), ('\u1000', '\u102a'), + ('\u102b', '\u102c'), ('\u102d', '\u1030'), + ('\u1031', '\u1031'), ('\u1032', '\u1037'), + ('\u1038', '\u1038'), ('\u1039', '\u103a'), + ('\u103b', '\u103c'), ('\u103d', '\u103e'), + ('\u103f', '\u103f'), ('\u1040', '\u1049'), + ('\u1050', '\u1055'), ('\u1056', '\u1057'), + ('\u1058', '\u1059'), ('\u105a', '\u105d'), + ('\u105e', '\u1060'), ('\u1061', '\u1061'), + ('\u1062', '\u1064'), ('\u1065', '\u1066'), + ('\u1067', '\u106d'), ('\u106e', '\u1070'), + ('\u1071', '\u1074'), ('\u1075', '\u1081'), + ('\u1082', '\u1082'), ('\u1083', '\u1084'), + ('\u1085', '\u1086'), ('\u1087', '\u108c'), + ('\u108d', '\u108d'), ('\u108e', '\u108e'), + ('\u108f', '\u108f'), ('\u1090', '\u1099'), + ('\u109a', '\u109c'), ('\u109d', '\u109d'), + ('\u10a0', '\u10c5'), ('\u10c7', '\u10c7'), + ('\u10cd', '\u10cd'), ('\u10d0', '\u10fa'), + ('\u10fc', '\u10fc'), ('\u10fd', '\u1248'), + ('\u124a', '\u124d'), ('\u1250', '\u1256'), + ('\u1258', '\u1258'), ('\u125a', '\u125d'), + ('\u1260', '\u1288'), ('\u128a', '\u128d'), + ('\u1290', '\u12b0'), ('\u12b2', '\u12b5'), + ('\u12b8', '\u12be'), ('\u12c0', '\u12c0'), + ('\u12c2', '\u12c5'), ('\u12c8', '\u12d6'), + ('\u12d8', '\u1310'), ('\u1312', '\u1315'), + ('\u1318', '\u135a'), ('\u135d', '\u135f'), + ('\u1369', '\u1371'), ('\u1380', '\u138f'), + ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), + ('\u166f', '\u167f'), ('\u1681', '\u169a'), + ('\u16a0', '\u16ea'), ('\u16ee', '\u16f0'), + ('\u1700', '\u170c'), ('\u170e', '\u1711'), + ('\u1712', '\u1714'), ('\u1720', '\u1731'), + ('\u1732', '\u1734'), ('\u1740', '\u1751'), + ('\u1752', '\u1753'), ('\u1760', '\u176c'), + ('\u176e', '\u1770'), ('\u1772', '\u1773'), + ('\u1780', '\u17b3'), ('\u17b4', '\u17b5'), + ('\u17b6', '\u17b6'), ('\u17b7', '\u17bd'), + ('\u17be', '\u17c5'), ('\u17c6', '\u17c6'), + ('\u17c7', '\u17c8'), ('\u17c9', '\u17d3'), + ('\u17d7', '\u17d7'), ('\u17dc', '\u17dc'), + ('\u17dd', '\u17dd'), ('\u17e0', '\u17e9'), + ('\u180b', '\u180d'), ('\u1810', '\u1819'), + ('\u1820', '\u1842'), ('\u1843', '\u1843'), + ('\u1844', '\u1877'), ('\u1880', '\u18a8'), + ('\u18a9', '\u18a9'), ('\u18aa', '\u18aa'), + ('\u18b0', '\u18f5'), ('\u1900', '\u191c'), + ('\u1920', '\u1922'), ('\u1923', '\u1926'), + ('\u1927', '\u1928'), ('\u1929', '\u192b'), + ('\u1930', '\u1931'), ('\u1932', '\u1932'), + ('\u1933', '\u1938'), ('\u1939', '\u193b'), + ('\u1946', '\u194f'), ('\u1950', '\u196d'), + ('\u1970', '\u1974'), ('\u1980', '\u19ab'), + ('\u19b0', '\u19c0'), ('\u19c1', '\u19c7'), + ('\u19c8', '\u19c9'), ('\u19d0', '\u19d9'), + ('\u19da', '\u19da'), ('\u1a00', '\u1a16'), + ('\u1a17', '\u1a18'), ('\u1a19', '\u1a1b'), + ('\u1a20', '\u1a54'), ('\u1a55', '\u1a55'), + ('\u1a56', '\u1a56'), ('\u1a57', '\u1a57'), + ('\u1a58', '\u1a5e'), ('\u1a60', '\u1a60'), + ('\u1a61', '\u1a61'), ('\u1a62', '\u1a62'), + ('\u1a63', '\u1a64'), ('\u1a65', '\u1a6c'), + ('\u1a6d', '\u1a72'), ('\u1a73', '\u1a7c'), + ('\u1a7f', '\u1a7f'), ('\u1a80', '\u1a89'), + ('\u1a90', '\u1a99'), ('\u1aa7', '\u1aa7'), + ('\u1b00', '\u1b03'), ('\u1b04', '\u1b04'), + ('\u1b05', '\u1b33'), ('\u1b34', '\u1b34'), + ('\u1b35', '\u1b35'), ('\u1b36', '\u1b3a'), + ('\u1b3b', '\u1b3b'), ('\u1b3c', '\u1b3c'), + ('\u1b3d', '\u1b41'), ('\u1b42', '\u1b42'), + ('\u1b43', '\u1b44'), ('\u1b45', '\u1b4b'), + ('\u1b50', '\u1b59'), ('\u1b6b', '\u1b73'), + ('\u1b80', '\u1b81'), ('\u1b82', '\u1b82'), + ('\u1b83', '\u1ba0'), ('\u1ba1', '\u1ba1'), + ('\u1ba2', '\u1ba5'), ('\u1ba6', '\u1ba7'), + ('\u1ba8', '\u1ba9'), ('\u1baa', '\u1baa'), + ('\u1bab', '\u1bab'), ('\u1bac', '\u1bad'), + ('\u1bae', '\u1baf'), ('\u1bb0', '\u1bb9'), + ('\u1bba', '\u1be5'), ('\u1be6', '\u1be6'), + ('\u1be7', '\u1be7'), ('\u1be8', '\u1be9'), + ('\u1bea', '\u1bec'), ('\u1bed', '\u1bed'), + ('\u1bee', '\u1bee'), ('\u1bef', '\u1bf1'), + ('\u1bf2', '\u1bf3'), ('\u1c00', '\u1c23'), + ('\u1c24', '\u1c2b'), ('\u1c2c', '\u1c33'), + ('\u1c34', '\u1c35'), ('\u1c36', '\u1c37'), + ('\u1c40', '\u1c49'), ('\u1c4d', '\u1c4f'), + ('\u1c50', '\u1c59'), ('\u1c5a', '\u1c77'), + ('\u1c78', '\u1c7d'), ('\u1cd0', '\u1cd2'), + ('\u1cd4', '\u1ce0'), ('\u1ce1', '\u1ce1'), + ('\u1ce2', '\u1ce8'), ('\u1ce9', '\u1cec'), + ('\u1ced', '\u1ced'), ('\u1cee', '\u1cf1'), + ('\u1cf2', '\u1cf3'), ('\u1cf4', '\u1cf4'), + ('\u1cf5', '\u1cf6'), ('\u1d00', '\u1d2b'), + ('\u1d2c', '\u1d6a'), ('\u1d6b', '\u1d77'), + ('\u1d78', '\u1d78'), ('\u1d79', '\u1d9a'), + ('\u1d9b', '\u1dbf'), ('\u1dc0', '\u1de6'), + ('\u1dfc', '\u1dff'), ('\u1e00', '\u1f15'), + ('\u1f18', '\u1f1d'), ('\u1f20', '\u1f45'), + ('\u1f48', '\u1f4d'), ('\u1f50', '\u1f57'), + ('\u1f59', '\u1f59'), ('\u1f5b', '\u1f5b'), + ('\u1f5d', '\u1f5d'), ('\u1f5f', '\u1f7d'), + ('\u1f80', '\u1fb4'), ('\u1fb6', '\u1fbc'), + ('\u1fbe', '\u1fbe'), ('\u1fc2', '\u1fc4'), + ('\u1fc6', '\u1fcc'), ('\u1fd0', '\u1fd3'), + ('\u1fd6', '\u1fdb'), ('\u1fe0', '\u1fec'), + ('\u1ff2', '\u1ff4'), ('\u1ff6', '\u1ffc'), + ('\u203f', '\u2040'), ('\u2054', '\u2054'), + ('\u2071', '\u2071'), ('\u207f', '\u207f'), + ('\u2090', '\u209c'), ('\u20d0', '\u20dc'), + ('\u20e1', '\u20e1'), ('\u20e5', '\u20f0'), + ('\u2102', '\u2102'), ('\u2107', '\u2107'), + ('\u210a', '\u2113'), ('\u2115', '\u2115'), + ('\u2118', '\u2118'), ('\u2119', '\u211d'), + ('\u2124', '\u2124'), ('\u2126', '\u2126'), + ('\u2128', '\u2128'), ('\u212a', '\u212d'), + ('\u212e', '\u212e'), ('\u212f', '\u2134'), + ('\u2135', '\u2138'), ('\u2139', '\u2139'), + ('\u213c', '\u213f'), ('\u2145', '\u2149'), + ('\u214e', '\u214e'), ('\u2160', '\u2182'), + ('\u2183', '\u2184'), ('\u2185', '\u2188'), + ('\u2c00', '\u2c2e'), ('\u2c30', '\u2c5e'), + ('\u2c60', '\u2c7b'), ('\u2c7c', '\u2c7d'), + ('\u2c7e', '\u2ce4'), ('\u2ceb', '\u2cee'), + ('\u2cef', '\u2cf1'), ('\u2cf2', '\u2cf3'), + ('\u2d00', '\u2d25'), ('\u2d27', '\u2d27'), + ('\u2d2d', '\u2d2d'), ('\u2d30', '\u2d67'), + ('\u2d6f', '\u2d6f'), ('\u2d7f', '\u2d7f'), + ('\u2d80', '\u2d96'), ('\u2da0', '\u2da6'), + ('\u2da8', '\u2dae'), ('\u2db0', '\u2db6'), + ('\u2db8', '\u2dbe'), ('\u2dc0', '\u2dc6'), + ('\u2dc8', '\u2dce'), ('\u2dd0', '\u2dd6'), + ('\u2dd8', '\u2dde'), ('\u2de0', '\u2dff'), + ('\u3005', '\u3005'), ('\u3006', '\u3006'), + ('\u3007', '\u3007'), ('\u3021', '\u3029'), + ('\u302a', '\u302d'), ('\u302e', '\u302f'), + ('\u3031', '\u3035'), ('\u3038', '\u303a'), + ('\u303b', '\u303b'), ('\u303c', '\u303c'), + ('\u3041', '\u3096'), ('\u3099', '\u309a'), + ('\u309d', '\u309e'), ('\u309f', '\u309f'), + ('\u30a1', '\u30fa'), ('\u30fc', '\u30fe'), + ('\u30ff', '\u30ff'), ('\u3105', '\u312d'), + ('\u3131', '\u318e'), ('\u31a0', '\u31ba'), + ('\u31f0', '\u31ff'), ('\u3400', '\u4db5'), + ('\u4e00', '\u9fcc'), ('\ua000', '\ua014'), + ('\ua015', '\ua015'), ('\ua016', '\ua48c'), + ('\ua4d0', '\ua4f7'), ('\ua4f8', '\ua4fd'), + ('\ua500', '\ua60b'), ('\ua60c', '\ua60c'), + ('\ua610', '\ua61f'), ('\ua620', '\ua629'), + ('\ua62a', '\ua62b'), ('\ua640', '\ua66d'), + ('\ua66e', '\ua66e'), ('\ua66f', '\ua66f'), + ('\ua674', '\ua67d'), ('\ua67f', '\ua67f'), + ('\ua680', '\ua697'), ('\ua69f', '\ua69f'), + ('\ua6a0', '\ua6e5'), ('\ua6e6', '\ua6ef'), + ('\ua6f0', '\ua6f1'), ('\ua717', '\ua71f'), + ('\ua722', '\ua76f'), ('\ua770', '\ua770'), + ('\ua771', '\ua787'), ('\ua788', '\ua788'), + ('\ua78b', '\ua78e'), ('\ua790', '\ua793'), + ('\ua7a0', '\ua7aa'), ('\ua7f8', '\ua7f9'), + ('\ua7fa', '\ua7fa'), ('\ua7fb', '\ua801'), + ('\ua802', '\ua802'), ('\ua803', '\ua805'), + ('\ua806', '\ua806'), ('\ua807', '\ua80a'), + ('\ua80b', '\ua80b'), ('\ua80c', '\ua822'), + ('\ua823', '\ua824'), ('\ua825', '\ua826'), + ('\ua827', '\ua827'), ('\ua840', '\ua873'), + ('\ua880', '\ua881'), ('\ua882', '\ua8b3'), + ('\ua8b4', '\ua8c3'), ('\ua8c4', '\ua8c4'), + ('\ua8d0', '\ua8d9'), ('\ua8e0', '\ua8f1'), + ('\ua8f2', '\ua8f7'), ('\ua8fb', '\ua8fb'), + ('\ua900', '\ua909'), ('\ua90a', '\ua925'), + ('\ua926', '\ua92d'), ('\ua930', '\ua946'), + ('\ua947', '\ua951'), ('\ua952', '\ua953'), + ('\ua960', '\ua97c'), ('\ua980', '\ua982'), + ('\ua983', '\ua983'), ('\ua984', '\ua9b2'), + ('\ua9b3', '\ua9b3'), ('\ua9b4', '\ua9b5'), + ('\ua9b6', '\ua9b9'), ('\ua9ba', '\ua9bb'), + ('\ua9bc', '\ua9bc'), ('\ua9bd', '\ua9c0'), + ('\ua9cf', '\ua9cf'), ('\ua9d0', '\ua9d9'), + ('\uaa00', '\uaa28'), ('\uaa29', '\uaa2e'), + ('\uaa2f', '\uaa30'), ('\uaa31', '\uaa32'), + ('\uaa33', '\uaa34'), ('\uaa35', '\uaa36'), + ('\uaa40', '\uaa42'), ('\uaa43', '\uaa43'), + ('\uaa44', '\uaa4b'), ('\uaa4c', '\uaa4c'), + ('\uaa4d', '\uaa4d'), ('\uaa50', '\uaa59'), + ('\uaa60', '\uaa6f'), ('\uaa70', '\uaa70'), + ('\uaa71', '\uaa76'), ('\uaa7a', '\uaa7a'), + ('\uaa7b', '\uaa7b'), ('\uaa80', '\uaaaf'), + ('\uaab0', '\uaab0'), ('\uaab1', '\uaab1'), + ('\uaab2', '\uaab4'), ('\uaab5', '\uaab6'), + ('\uaab7', '\uaab8'), ('\uaab9', '\uaabd'), + ('\uaabe', '\uaabf'), ('\uaac0', '\uaac0'), + ('\uaac1', '\uaac1'), ('\uaac2', '\uaac2'), + ('\uaadb', '\uaadc'), ('\uaadd', '\uaadd'), + ('\uaae0', '\uaaea'), ('\uaaeb', '\uaaeb'), + ('\uaaec', '\uaaed'), ('\uaaee', '\uaaef'), + ('\uaaf2', '\uaaf2'), ('\uaaf3', '\uaaf4'), + ('\uaaf5', '\uaaf5'), ('\uaaf6', '\uaaf6'), + ('\uab01', '\uab06'), ('\uab09', '\uab0e'), + ('\uab11', '\uab16'), ('\uab20', '\uab26'), + ('\uab28', '\uab2e'), ('\uabc0', '\uabe2'), + ('\uabe3', '\uabe4'), ('\uabe5', '\uabe5'), + ('\uabe6', '\uabe7'), ('\uabe8', '\uabe8'), + ('\uabe9', '\uabea'), ('\uabec', '\uabec'), + ('\uabed', '\uabed'), ('\uabf0', '\uabf9'), + ('\uac00', '\ud7a3'), ('\ud7b0', '\ud7c6'), + ('\ud7cb', '\ud7fb'), ('\uf900', '\ufa6d'), + ('\ufa70', '\ufad9'), ('\ufb00', '\ufb06'), + ('\ufb13', '\ufb17'), ('\ufb1d', '\ufb1d'), + ('\ufb1e', '\ufb1e'), ('\ufb1f', '\ufb28'), + ('\ufb2a', '\ufb36'), ('\ufb38', '\ufb3c'), + ('\ufb3e', '\ufb3e'), ('\ufb40', '\ufb41'), + ('\ufb43', '\ufb44'), ('\ufb46', '\ufbb1'), + ('\ufbd3', '\ufc5d'), ('\ufc64', '\ufd3d'), + ('\ufd50', '\ufd8f'), ('\ufd92', '\ufdc7'), + ('\ufdf0', '\ufdf9'), ('\ufe00', '\ufe0f'), + ('\ufe20', '\ufe26'), ('\ufe33', '\ufe34'), + ('\ufe4d', '\ufe4f'), ('\ufe71', '\ufe71'), + ('\ufe73', '\ufe73'), ('\ufe77', '\ufe77'), + ('\ufe79', '\ufe79'), ('\ufe7b', '\ufe7b'), + ('\ufe7d', '\ufe7d'), ('\ufe7f', '\ufefc'), + ('\uff10', '\uff19'), ('\uff21', '\uff3a'), + ('\uff3f', '\uff3f'), ('\uff41', '\uff5a'), + ('\uff66', '\uff6f'), ('\uff70', '\uff70'), + ('\uff71', '\uff9d'), ('\uff9e', '\uff9f'), + ('\uffa0', '\uffbe'), ('\uffc2', '\uffc7'), + ('\uffca', '\uffcf'), ('\uffd2', '\uffd7'), + ('\uffda', '\uffdc'), ('\U00010000', '\U0001000b'), + ('\U0001000d', '\U00010026'), ('\U00010028', '\U0001003a'), + ('\U0001003c', '\U0001003d'), ('\U0001003f', '\U0001004d'), + ('\U00010050', '\U0001005d'), ('\U00010080', '\U000100fa'), + ('\U00010140', '\U00010174'), ('\U000101fd', '\U000101fd'), + ('\U00010280', '\U0001029c'), ('\U000102a0', '\U000102d0'), + ('\U00010300', '\U0001031e'), ('\U00010330', '\U00010340'), + ('\U00010341', '\U00010341'), ('\U00010342', '\U00010349'), + ('\U0001034a', '\U0001034a'), ('\U00010380', '\U0001039d'), + ('\U000103a0', '\U000103c3'), ('\U000103c8', '\U000103cf'), + ('\U000103d1', '\U000103d5'), ('\U00010400', '\U0001044f'), + ('\U00010450', '\U0001049d'), ('\U000104a0', '\U000104a9'), + ('\U00010800', '\U00010805'), ('\U00010808', '\U00010808'), + ('\U0001080a', '\U00010835'), ('\U00010837', '\U00010838'), + ('\U0001083c', '\U0001083c'), ('\U0001083f', '\U00010855'), + ('\U00010900', '\U00010915'), ('\U00010920', '\U00010939'), + ('\U00010980', '\U000109b7'), ('\U000109be', '\U000109bf'), + ('\U00010a00', '\U00010a00'), ('\U00010a01', '\U00010a03'), + ('\U00010a05', '\U00010a06'), ('\U00010a0c', '\U00010a0f'), + ('\U00010a10', '\U00010a13'), ('\U00010a15', '\U00010a17'), + ('\U00010a19', '\U00010a33'), ('\U00010a38', '\U00010a3a'), + ('\U00010a3f', '\U00010a3f'), ('\U00010a60', '\U00010a7c'), + ('\U00010b00', '\U00010b35'), ('\U00010b40', '\U00010b55'), + ('\U00010b60', '\U00010b72'), ('\U00010c00', '\U00010c48'), + ('\U00011000', '\U00011000'), ('\U00011001', '\U00011001'), + ('\U00011002', '\U00011002'), ('\U00011003', '\U00011037'), + ('\U00011038', '\U00011046'), ('\U00011066', '\U0001106f'), + ('\U00011080', '\U00011081'), ('\U00011082', '\U00011082'), + ('\U00011083', '\U000110af'), ('\U000110b0', '\U000110b2'), + ('\U000110b3', '\U000110b6'), ('\U000110b7', '\U000110b8'), + ('\U000110b9', '\U000110ba'), ('\U000110d0', '\U000110e8'), + ('\U000110f0', '\U000110f9'), ('\U00011100', '\U00011102'), + ('\U00011103', '\U00011126'), ('\U00011127', '\U0001112b'), + ('\U0001112c', '\U0001112c'), ('\U0001112d', '\U00011134'), + ('\U00011136', '\U0001113f'), ('\U00011180', '\U00011181'), + ('\U00011182', '\U00011182'), ('\U00011183', '\U000111b2'), + ('\U000111b3', '\U000111b5'), ('\U000111b6', '\U000111be'), + ('\U000111bf', '\U000111c0'), ('\U000111c1', '\U000111c4'), + ('\U000111d0', '\U000111d9'), ('\U00011680', '\U000116aa'), + ('\U000116ab', '\U000116ab'), ('\U000116ac', '\U000116ac'), + ('\U000116ad', '\U000116ad'), ('\U000116ae', '\U000116af'), + ('\U000116b0', '\U000116b5'), ('\U000116b6', '\U000116b6'), + ('\U000116b7', '\U000116b7'), ('\U000116c0', '\U000116c9'), + ('\U00012000', '\U0001236e'), ('\U00012400', '\U00012462'), + ('\U00013000', '\U0001342e'), ('\U00016800', '\U00016a38'), + ('\U00016f00', '\U00016f44'), ('\U00016f50', '\U00016f50'), + ('\U00016f51', '\U00016f7e'), ('\U00016f8f', '\U00016f92'), + ('\U00016f93', '\U00016f9f'), ('\U0001b000', '\U0001b001'), + ('\U0001d165', '\U0001d166'), ('\U0001d167', '\U0001d169'), + ('\U0001d16d', '\U0001d172'), ('\U0001d17b', '\U0001d182'), + ('\U0001d185', '\U0001d18b'), ('\U0001d1aa', '\U0001d1ad'), + ('\U0001d242', '\U0001d244'), ('\U0001d400', '\U0001d454'), + ('\U0001d456', '\U0001d49c'), ('\U0001d49e', '\U0001d49f'), + ('\U0001d4a2', '\U0001d4a2'), ('\U0001d4a5', '\U0001d4a6'), + ('\U0001d4a9', '\U0001d4ac'), ('\U0001d4ae', '\U0001d4b9'), + ('\U0001d4bb', '\U0001d4bb'), ('\U0001d4bd', '\U0001d4c3'), + ('\U0001d4c5', '\U0001d505'), ('\U0001d507', '\U0001d50a'), + ('\U0001d50d', '\U0001d514'), ('\U0001d516', '\U0001d51c'), + ('\U0001d51e', '\U0001d539'), ('\U0001d53b', '\U0001d53e'), + ('\U0001d540', '\U0001d544'), ('\U0001d546', '\U0001d546'), + ('\U0001d54a', '\U0001d550'), ('\U0001d552', '\U0001d6a5'), + ('\U0001d6a8', '\U0001d6c0'), ('\U0001d6c2', '\U0001d6da'), + ('\U0001d6dc', '\U0001d6fa'), ('\U0001d6fc', '\U0001d714'), + ('\U0001d716', '\U0001d734'), ('\U0001d736', '\U0001d74e'), + ('\U0001d750', '\U0001d76e'), ('\U0001d770', '\U0001d788'), + ('\U0001d78a', '\U0001d7a8'), ('\U0001d7aa', '\U0001d7c2'), + ('\U0001d7c4', '\U0001d7cb'), ('\U0001d7ce', '\U0001d7ff'), + ('\U0001ee00', '\U0001ee03'), ('\U0001ee05', '\U0001ee1f'), + ('\U0001ee21', '\U0001ee22'), ('\U0001ee24', '\U0001ee24'), + ('\U0001ee27', '\U0001ee27'), ('\U0001ee29', '\U0001ee32'), + ('\U0001ee34', '\U0001ee37'), ('\U0001ee39', '\U0001ee39'), + ('\U0001ee3b', '\U0001ee3b'), ('\U0001ee42', '\U0001ee42'), + ('\U0001ee47', '\U0001ee47'), ('\U0001ee49', '\U0001ee49'), + ('\U0001ee4b', '\U0001ee4b'), ('\U0001ee4d', '\U0001ee4f'), + ('\U0001ee51', '\U0001ee52'), ('\U0001ee54', '\U0001ee54'), + ('\U0001ee57', '\U0001ee57'), ('\U0001ee59', '\U0001ee59'), + ('\U0001ee5b', '\U0001ee5b'), ('\U0001ee5d', '\U0001ee5d'), + ('\U0001ee5f', '\U0001ee5f'), ('\U0001ee61', '\U0001ee62'), + ('\U0001ee64', '\U0001ee64'), ('\U0001ee67', '\U0001ee6a'), + ('\U0001ee6c', '\U0001ee72'), ('\U0001ee74', '\U0001ee77'), + ('\U0001ee79', '\U0001ee7c'), ('\U0001ee7e', '\U0001ee7e'), + ('\U0001ee80', '\U0001ee89'), ('\U0001ee8b', '\U0001ee9b'), + ('\U0001eea1', '\U0001eea3'), ('\U0001eea5', '\U0001eea9'), + ('\U0001eeab', '\U0001eebb'), ('\U00020000', '\U0002a6d6'), + ('\U0002a700', '\U0002b734'), ('\U0002b740', '\U0002b81d'), + ('\U0002f800', '\U0002fa1d'), ('\U000e0100', '\U000e01ef') + ]; + pub fn XID_Continue(c: char) -> bool { - return match c { - '\x30' .. '\x39' - | '\x41' .. '\x5a' - | '\x5f' - | '\x61' .. '\x7a' - | '\xaa' - | '\xb5' - | '\xb7' - | '\xba' - | '\xc0' .. '\xd6' - | '\xd8' .. '\xf6' - | '\xf8' .. '\u01ba' - | '\u01bb' - | '\u01bc' .. '\u01bf' - | '\u01c0' .. '\u01c3' - | '\u01c4' .. '\u0293' - | '\u0294' - | '\u0295' .. '\u02af' - | '\u02b0' .. '\u02c1' - | '\u02c6' .. '\u02d1' - | '\u02e0' .. '\u02e4' - | '\u02ec' - | '\u02ee' - | '\u0300' .. '\u036f' - | '\u0370' .. '\u0373' - | '\u0374' - | '\u0376' .. '\u0377' - | '\u037b' .. '\u037d' - | '\u0386' - | '\u0387' - | '\u0388' .. '\u038a' - | '\u038c' - | '\u038e' .. '\u03a1' - | '\u03a3' .. '\u03f5' - | '\u03f7' .. '\u0481' - | '\u0483' .. '\u0487' - | '\u048a' .. '\u0527' - | '\u0531' .. '\u0556' - | '\u0559' - | '\u0561' .. '\u0587' - | '\u0591' .. '\u05bd' - | '\u05bf' - | '\u05c1' .. '\u05c2' - | '\u05c4' .. '\u05c5' - | '\u05c7' - | '\u05d0' .. '\u05ea' - | '\u05f0' .. '\u05f2' - | '\u0610' .. '\u061a' - | '\u0620' .. '\u063f' - | '\u0640' - | '\u0641' .. '\u064a' - | '\u064b' .. '\u065f' - | '\u0660' .. '\u0669' - | '\u066e' .. '\u066f' - | '\u0670' - | '\u0671' .. '\u06d3' - | '\u06d5' - | '\u06d6' .. '\u06dc' - | '\u06df' .. '\u06e4' - | '\u06e5' .. '\u06e6' - | '\u06e7' .. '\u06e8' - | '\u06ea' .. '\u06ed' - | '\u06ee' .. '\u06ef' - | '\u06f0' .. '\u06f9' - | '\u06fa' .. '\u06fc' - | '\u06ff' - | '\u0710' - | '\u0711' - | '\u0712' .. '\u072f' - | '\u0730' .. '\u074a' - | '\u074d' .. '\u07a5' - | '\u07a6' .. '\u07b0' - | '\u07b1' - | '\u07c0' .. '\u07c9' - | '\u07ca' .. '\u07ea' - | '\u07eb' .. '\u07f3' - | '\u07f4' .. '\u07f5' - | '\u07fa' - | '\u0800' .. '\u0815' - | '\u0816' .. '\u0819' - | '\u081a' - | '\u081b' .. '\u0823' - | '\u0824' - | '\u0825' .. '\u0827' - | '\u0828' - | '\u0829' .. '\u082d' - | '\u0840' .. '\u0858' - | '\u0859' .. '\u085b' - | '\u0900' .. '\u0902' - | '\u0903' - | '\u0904' .. '\u0939' - | '\u093a' - | '\u093b' - | '\u093c' - | '\u093d' - | '\u093e' .. '\u0940' - | '\u0941' .. '\u0948' - | '\u0949' .. '\u094c' - | '\u094d' - | '\u094e' .. '\u094f' - | '\u0950' - | '\u0951' .. '\u0957' - | '\u0958' .. '\u0961' - | '\u0962' .. '\u0963' - | '\u0966' .. '\u096f' - | '\u0971' - | '\u0972' .. '\u0977' - | '\u0979' .. '\u097f' - | '\u0981' - | '\u0982' .. '\u0983' - | '\u0985' .. '\u098c' - | '\u098f' .. '\u0990' - | '\u0993' .. '\u09a8' - | '\u09aa' .. '\u09b0' - | '\u09b2' - | '\u09b6' .. '\u09b9' - | '\u09bc' - | '\u09bd' - | '\u09be' .. '\u09c0' - | '\u09c1' .. '\u09c4' - | '\u09c7' .. '\u09c8' - | '\u09cb' .. '\u09cc' - | '\u09cd' - | '\u09ce' - | '\u09d7' - | '\u09dc' .. '\u09dd' - | '\u09df' .. '\u09e1' - | '\u09e2' .. '\u09e3' - | '\u09e6' .. '\u09ef' - | '\u09f0' .. '\u09f1' - | '\u0a01' .. '\u0a02' - | '\u0a03' - | '\u0a05' .. '\u0a0a' - | '\u0a0f' .. '\u0a10' - | '\u0a13' .. '\u0a28' - | '\u0a2a' .. '\u0a30' - | '\u0a32' .. '\u0a33' - | '\u0a35' .. '\u0a36' - | '\u0a38' .. '\u0a39' - | '\u0a3c' - | '\u0a3e' .. '\u0a40' - | '\u0a41' .. '\u0a42' - | '\u0a47' .. '\u0a48' - | '\u0a4b' .. '\u0a4d' - | '\u0a51' - | '\u0a59' .. '\u0a5c' - | '\u0a5e' - | '\u0a66' .. '\u0a6f' - | '\u0a70' .. '\u0a71' - | '\u0a72' .. '\u0a74' - | '\u0a75' - | '\u0a81' .. '\u0a82' - | '\u0a83' - | '\u0a85' .. '\u0a8d' - | '\u0a8f' .. '\u0a91' - | '\u0a93' .. '\u0aa8' - | '\u0aaa' .. '\u0ab0' - | '\u0ab2' .. '\u0ab3' - | '\u0ab5' .. '\u0ab9' - | '\u0abc' - | '\u0abd' - | '\u0abe' .. '\u0ac0' - | '\u0ac1' .. '\u0ac5' - | '\u0ac7' .. '\u0ac8' - | '\u0ac9' - | '\u0acb' .. '\u0acc' - | '\u0acd' - | '\u0ad0' - | '\u0ae0' .. '\u0ae1' - | '\u0ae2' .. '\u0ae3' - | '\u0ae6' .. '\u0aef' - | '\u0b01' - | '\u0b02' .. '\u0b03' - | '\u0b05' .. '\u0b0c' - | '\u0b0f' .. '\u0b10' - | '\u0b13' .. '\u0b28' - | '\u0b2a' .. '\u0b30' - | '\u0b32' .. '\u0b33' - | '\u0b35' .. '\u0b39' - | '\u0b3c' - | '\u0b3d' - | '\u0b3e' - | '\u0b3f' - | '\u0b40' - | '\u0b41' .. '\u0b44' - | '\u0b47' .. '\u0b48' - | '\u0b4b' .. '\u0b4c' - | '\u0b4d' - | '\u0b56' - | '\u0b57' - | '\u0b5c' .. '\u0b5d' - | '\u0b5f' .. '\u0b61' - | '\u0b62' .. '\u0b63' - | '\u0b66' .. '\u0b6f' - | '\u0b71' - | '\u0b82' - | '\u0b83' - | '\u0b85' .. '\u0b8a' - | '\u0b8e' .. '\u0b90' - | '\u0b92' .. '\u0b95' - | '\u0b99' .. '\u0b9a' - | '\u0b9c' - | '\u0b9e' .. '\u0b9f' - | '\u0ba3' .. '\u0ba4' - | '\u0ba8' .. '\u0baa' - | '\u0bae' .. '\u0bb9' - | '\u0bbe' .. '\u0bbf' - | '\u0bc0' - | '\u0bc1' .. '\u0bc2' - | '\u0bc6' .. '\u0bc8' - | '\u0bca' .. '\u0bcc' - | '\u0bcd' - | '\u0bd0' - | '\u0bd7' - | '\u0be6' .. '\u0bef' - | '\u0c01' .. '\u0c03' - | '\u0c05' .. '\u0c0c' - | '\u0c0e' .. '\u0c10' - | '\u0c12' .. '\u0c28' - | '\u0c2a' .. '\u0c33' - | '\u0c35' .. '\u0c39' - | '\u0c3d' - | '\u0c3e' .. '\u0c40' - | '\u0c41' .. '\u0c44' - | '\u0c46' .. '\u0c48' - | '\u0c4a' .. '\u0c4d' - | '\u0c55' .. '\u0c56' - | '\u0c58' .. '\u0c59' - | '\u0c60' .. '\u0c61' - | '\u0c62' .. '\u0c63' - | '\u0c66' .. '\u0c6f' - | '\u0c82' .. '\u0c83' - | '\u0c85' .. '\u0c8c' - | '\u0c8e' .. '\u0c90' - | '\u0c92' .. '\u0ca8' - | '\u0caa' .. '\u0cb3' - | '\u0cb5' .. '\u0cb9' - | '\u0cbc' - | '\u0cbd' - | '\u0cbe' - | '\u0cbf' - | '\u0cc0' .. '\u0cc4' - | '\u0cc6' - | '\u0cc7' .. '\u0cc8' - | '\u0cca' .. '\u0ccb' - | '\u0ccc' .. '\u0ccd' - | '\u0cd5' .. '\u0cd6' - | '\u0cde' - | '\u0ce0' .. '\u0ce1' - | '\u0ce2' .. '\u0ce3' - | '\u0ce6' .. '\u0cef' - | '\u0cf1' .. '\u0cf2' - | '\u0d02' .. '\u0d03' - | '\u0d05' .. '\u0d0c' - | '\u0d0e' .. '\u0d10' - | '\u0d12' .. '\u0d3a' - | '\u0d3d' - | '\u0d3e' .. '\u0d40' - | '\u0d41' .. '\u0d44' - | '\u0d46' .. '\u0d48' - | '\u0d4a' .. '\u0d4c' - | '\u0d4d' - | '\u0d4e' - | '\u0d57' - | '\u0d60' .. '\u0d61' - | '\u0d62' .. '\u0d63' - | '\u0d66' .. '\u0d6f' - | '\u0d7a' .. '\u0d7f' - | '\u0d82' .. '\u0d83' - | '\u0d85' .. '\u0d96' - | '\u0d9a' .. '\u0db1' - | '\u0db3' .. '\u0dbb' - | '\u0dbd' - | '\u0dc0' .. '\u0dc6' - | '\u0dca' - | '\u0dcf' .. '\u0dd1' - | '\u0dd2' .. '\u0dd4' - | '\u0dd6' - | '\u0dd8' .. '\u0ddf' - | '\u0df2' .. '\u0df3' - | '\u0e01' .. '\u0e30' - | '\u0e31' - | '\u0e32' .. '\u0e33' - | '\u0e34' .. '\u0e3a' - | '\u0e40' .. '\u0e45' - | '\u0e46' - | '\u0e47' .. '\u0e4e' - | '\u0e50' .. '\u0e59' - | '\u0e81' .. '\u0e82' - | '\u0e84' - | '\u0e87' .. '\u0e88' - | '\u0e8a' - | '\u0e8d' - | '\u0e94' .. '\u0e97' - | '\u0e99' .. '\u0e9f' - | '\u0ea1' .. '\u0ea3' - | '\u0ea5' - | '\u0ea7' - | '\u0eaa' .. '\u0eab' - | '\u0ead' .. '\u0eb0' - | '\u0eb1' - | '\u0eb2' .. '\u0eb3' - | '\u0eb4' .. '\u0eb9' - | '\u0ebb' .. '\u0ebc' - | '\u0ebd' - | '\u0ec0' .. '\u0ec4' - | '\u0ec6' - | '\u0ec8' .. '\u0ecd' - | '\u0ed0' .. '\u0ed9' - | '\u0edc' .. '\u0edd' - | '\u0f00' - | '\u0f18' .. '\u0f19' - | '\u0f20' .. '\u0f29' - | '\u0f35' - | '\u0f37' - | '\u0f39' - | '\u0f3e' .. '\u0f3f' - | '\u0f40' .. '\u0f47' - | '\u0f49' .. '\u0f6c' - | '\u0f71' .. '\u0f7e' - | '\u0f7f' - | '\u0f80' .. '\u0f84' - | '\u0f86' .. '\u0f87' - | '\u0f88' .. '\u0f8c' - | '\u0f8d' .. '\u0f97' - | '\u0f99' .. '\u0fbc' - | '\u0fc6' - | '\u1000' .. '\u102a' - | '\u102b' .. '\u102c' - | '\u102d' .. '\u1030' - | '\u1031' - | '\u1032' .. '\u1037' - | '\u1038' - | '\u1039' .. '\u103a' - | '\u103b' .. '\u103c' - | '\u103d' .. '\u103e' - | '\u103f' - | '\u1040' .. '\u1049' - | '\u1050' .. '\u1055' - | '\u1056' .. '\u1057' - | '\u1058' .. '\u1059' - | '\u105a' .. '\u105d' - | '\u105e' .. '\u1060' - | '\u1061' - | '\u1062' .. '\u1064' - | '\u1065' .. '\u1066' - | '\u1067' .. '\u106d' - | '\u106e' .. '\u1070' - | '\u1071' .. '\u1074' - | '\u1075' .. '\u1081' - | '\u1082' - | '\u1083' .. '\u1084' - | '\u1085' .. '\u1086' - | '\u1087' .. '\u108c' - | '\u108d' - | '\u108e' - | '\u108f' - | '\u1090' .. '\u1099' - | '\u109a' .. '\u109c' - | '\u109d' - | '\u10a0' .. '\u10c5' - | '\u10d0' .. '\u10fa' - | '\u10fc' - | '\u1100' .. '\u1248' - | '\u124a' .. '\u124d' - | '\u1250' .. '\u1256' - | '\u1258' - | '\u125a' .. '\u125d' - | '\u1260' .. '\u1288' - | '\u128a' .. '\u128d' - | '\u1290' .. '\u12b0' - | '\u12b2' .. '\u12b5' - | '\u12b8' .. '\u12be' - | '\u12c0' - | '\u12c2' .. '\u12c5' - | '\u12c8' .. '\u12d6' - | '\u12d8' .. '\u1310' - | '\u1312' .. '\u1315' - | '\u1318' .. '\u135a' - | '\u135d' .. '\u135f' - | '\u1369' .. '\u1371' - | '\u1380' .. '\u138f' - | '\u13a0' .. '\u13f4' - | '\u1401' .. '\u166c' - | '\u166f' .. '\u167f' - | '\u1681' .. '\u169a' - | '\u16a0' .. '\u16ea' - | '\u16ee' .. '\u16f0' - | '\u1700' .. '\u170c' - | '\u170e' .. '\u1711' - | '\u1712' .. '\u1714' - | '\u1720' .. '\u1731' - | '\u1732' .. '\u1734' - | '\u1740' .. '\u1751' - | '\u1752' .. '\u1753' - | '\u1760' .. '\u176c' - | '\u176e' .. '\u1770' - | '\u1772' .. '\u1773' - | '\u1780' .. '\u17b3' - | '\u17b6' - | '\u17b7' .. '\u17bd' - | '\u17be' .. '\u17c5' - | '\u17c6' - | '\u17c7' .. '\u17c8' - | '\u17c9' .. '\u17d3' - | '\u17d7' - | '\u17dc' - | '\u17dd' - | '\u17e0' .. '\u17e9' - | '\u180b' .. '\u180d' - | '\u1810' .. '\u1819' - | '\u1820' .. '\u1842' - | '\u1843' - | '\u1844' .. '\u1877' - | '\u1880' .. '\u18a8' - | '\u18a9' - | '\u18aa' - | '\u18b0' .. '\u18f5' - | '\u1900' .. '\u191c' - | '\u1920' .. '\u1922' - | '\u1923' .. '\u1926' - | '\u1927' .. '\u1928' - | '\u1929' .. '\u192b' - | '\u1930' .. '\u1931' - | '\u1932' - | '\u1933' .. '\u1938' - | '\u1939' .. '\u193b' - | '\u1946' .. '\u194f' - | '\u1950' .. '\u196d' - | '\u1970' .. '\u1974' - | '\u1980' .. '\u19ab' - | '\u19b0' .. '\u19c0' - | '\u19c1' .. '\u19c7' - | '\u19c8' .. '\u19c9' - | '\u19d0' .. '\u19d9' - | '\u19da' - | '\u1a00' .. '\u1a16' - | '\u1a17' .. '\u1a18' - | '\u1a19' .. '\u1a1b' - | '\u1a20' .. '\u1a54' - | '\u1a55' - | '\u1a56' - | '\u1a57' - | '\u1a58' .. '\u1a5e' - | '\u1a60' - | '\u1a61' - | '\u1a62' - | '\u1a63' .. '\u1a64' - | '\u1a65' .. '\u1a6c' - | '\u1a6d' .. '\u1a72' - | '\u1a73' .. '\u1a7c' - | '\u1a7f' - | '\u1a80' .. '\u1a89' - | '\u1a90' .. '\u1a99' - | '\u1aa7' - | '\u1b00' .. '\u1b03' - | '\u1b04' - | '\u1b05' .. '\u1b33' - | '\u1b34' - | '\u1b35' - | '\u1b36' .. '\u1b3a' - | '\u1b3b' - | '\u1b3c' - | '\u1b3d' .. '\u1b41' - | '\u1b42' - | '\u1b43' .. '\u1b44' - | '\u1b45' .. '\u1b4b' - | '\u1b50' .. '\u1b59' - | '\u1b6b' .. '\u1b73' - | '\u1b80' .. '\u1b81' - | '\u1b82' - | '\u1b83' .. '\u1ba0' - | '\u1ba1' - | '\u1ba2' .. '\u1ba5' - | '\u1ba6' .. '\u1ba7' - | '\u1ba8' .. '\u1ba9' - | '\u1baa' - | '\u1bae' .. '\u1baf' - | '\u1bb0' .. '\u1bb9' - | '\u1bc0' .. '\u1be5' - | '\u1be6' - | '\u1be7' - | '\u1be8' .. '\u1be9' - | '\u1bea' .. '\u1bec' - | '\u1bed' - | '\u1bee' - | '\u1bef' .. '\u1bf1' - | '\u1bf2' .. '\u1bf3' - | '\u1c00' .. '\u1c23' - | '\u1c24' .. '\u1c2b' - | '\u1c2c' .. '\u1c33' - | '\u1c34' .. '\u1c35' - | '\u1c36' .. '\u1c37' - | '\u1c40' .. '\u1c49' - | '\u1c4d' .. '\u1c4f' - | '\u1c50' .. '\u1c59' - | '\u1c5a' .. '\u1c77' - | '\u1c78' .. '\u1c7d' - | '\u1cd0' .. '\u1cd2' - | '\u1cd4' .. '\u1ce0' - | '\u1ce1' - | '\u1ce2' .. '\u1ce8' - | '\u1ce9' .. '\u1cec' - | '\u1ced' - | '\u1cee' .. '\u1cf1' - | '\u1cf2' - | '\u1d00' .. '\u1d2b' - | '\u1d2c' .. '\u1d61' - | '\u1d62' .. '\u1d77' - | '\u1d78' - | '\u1d79' .. '\u1d9a' - | '\u1d9b' .. '\u1dbf' - | '\u1dc0' .. '\u1de6' - | '\u1dfc' .. '\u1dff' - | '\u1e00' .. '\u1f15' - | '\u1f18' .. '\u1f1d' - | '\u1f20' .. '\u1f45' - | '\u1f48' .. '\u1f4d' - | '\u1f50' .. '\u1f57' - | '\u1f59' - | '\u1f5b' - | '\u1f5d' - | '\u1f5f' .. '\u1f7d' - | '\u1f80' .. '\u1fb4' - | '\u1fb6' .. '\u1fbc' - | '\u1fbe' - | '\u1fc2' .. '\u1fc4' - | '\u1fc6' .. '\u1fcc' - | '\u1fd0' .. '\u1fd3' - | '\u1fd6' .. '\u1fdb' - | '\u1fe0' .. '\u1fec' - | '\u1ff2' .. '\u1ff4' - | '\u1ff6' .. '\u1ffc' - | '\u203f' .. '\u2040' - | '\u2054' - | '\u2071' - | '\u207f' - | '\u2090' .. '\u209c' - | '\u20d0' .. '\u20dc' - | '\u20e1' - | '\u20e5' .. '\u20f0' - | '\u2102' - | '\u2107' - | '\u210a' .. '\u2113' - | '\u2115' - | '\u2118' - | '\u2119' .. '\u211d' - | '\u2124' - | '\u2126' - | '\u2128' - | '\u212a' .. '\u212d' - | '\u212e' - | '\u212f' .. '\u2134' - | '\u2135' .. '\u2138' - | '\u2139' - | '\u213c' .. '\u213f' - | '\u2145' .. '\u2149' - | '\u214e' - | '\u2160' .. '\u2182' - | '\u2183' .. '\u2184' - | '\u2185' .. '\u2188' - | '\u2c00' .. '\u2c2e' - | '\u2c30' .. '\u2c5e' - | '\u2c60' .. '\u2c7c' - | '\u2c7d' - | '\u2c7e' .. '\u2ce4' - | '\u2ceb' .. '\u2cee' - | '\u2cef' .. '\u2cf1' - | '\u2d00' .. '\u2d25' - | '\u2d30' .. '\u2d65' - | '\u2d6f' - | '\u2d7f' - | '\u2d80' .. '\u2d96' - | '\u2da0' .. '\u2da6' - | '\u2da8' .. '\u2dae' - | '\u2db0' .. '\u2db6' - | '\u2db8' .. '\u2dbe' - | '\u2dc0' .. '\u2dc6' - | '\u2dc8' .. '\u2dce' - | '\u2dd0' .. '\u2dd6' - | '\u2dd8' .. '\u2dde' - | '\u2de0' .. '\u2dff' - | '\u3005' - | '\u3006' - | '\u3007' - | '\u3021' .. '\u3029' - | '\u302a' .. '\u302f' - | '\u3031' .. '\u3035' - | '\u3038' .. '\u303a' - | '\u303b' - | '\u303c' - | '\u3041' .. '\u3096' - | '\u3099' .. '\u309a' - | '\u309d' .. '\u309e' - | '\u309f' - | '\u30a1' .. '\u30fa' - | '\u30fc' .. '\u30fe' - | '\u30ff' - | '\u3105' .. '\u312d' - | '\u3131' .. '\u318e' - | '\u31a0' .. '\u31ba' - | '\u31f0' .. '\u31ff' - | '\u3400' .. '\u4db5' - | '\u4e00' .. '\u9fcb' - | '\ua000' .. '\ua014' - | '\ua015' - | '\ua016' .. '\ua48c' - | '\ua4d0' .. '\ua4f7' - | '\ua4f8' .. '\ua4fd' - | '\ua500' .. '\ua60b' - | '\ua60c' - | '\ua610' .. '\ua61f' - | '\ua620' .. '\ua629' - | '\ua62a' .. '\ua62b' - | '\ua640' .. '\ua66d' - | '\ua66e' - | '\ua66f' - | '\ua67c' .. '\ua67d' - | '\ua67f' - | '\ua680' .. '\ua697' - | '\ua6a0' .. '\ua6e5' - | '\ua6e6' .. '\ua6ef' - | '\ua6f0' .. '\ua6f1' - | '\ua717' .. '\ua71f' - | '\ua722' .. '\ua76f' - | '\ua770' - | '\ua771' .. '\ua787' - | '\ua788' - | '\ua78b' .. '\ua78e' - | '\ua790' .. '\ua791' - | '\ua7a0' .. '\ua7a9' - | '\ua7fa' - | '\ua7fb' .. '\ua801' - | '\ua802' - | '\ua803' .. '\ua805' - | '\ua806' - | '\ua807' .. '\ua80a' - | '\ua80b' - | '\ua80c' .. '\ua822' - | '\ua823' .. '\ua824' - | '\ua825' .. '\ua826' - | '\ua827' - | '\ua840' .. '\ua873' - | '\ua880' .. '\ua881' - | '\ua882' .. '\ua8b3' - | '\ua8b4' .. '\ua8c3' - | '\ua8c4' - | '\ua8d0' .. '\ua8d9' - | '\ua8e0' .. '\ua8f1' - | '\ua8f2' .. '\ua8f7' - | '\ua8fb' - | '\ua900' .. '\ua909' - | '\ua90a' .. '\ua925' - | '\ua926' .. '\ua92d' - | '\ua930' .. '\ua946' - | '\ua947' .. '\ua951' - | '\ua952' .. '\ua953' - | '\ua960' .. '\ua97c' - | '\ua980' .. '\ua982' - | '\ua983' - | '\ua984' .. '\ua9b2' - | '\ua9b3' - | '\ua9b4' .. '\ua9b5' - | '\ua9b6' .. '\ua9b9' - | '\ua9ba' .. '\ua9bb' - | '\ua9bc' - | '\ua9bd' .. '\ua9c0' - | '\ua9cf' - | '\ua9d0' .. '\ua9d9' - | '\uaa00' .. '\uaa28' - | '\uaa29' .. '\uaa2e' - | '\uaa2f' .. '\uaa30' - | '\uaa31' .. '\uaa32' - | '\uaa33' .. '\uaa34' - | '\uaa35' .. '\uaa36' - | '\uaa40' .. '\uaa42' - | '\uaa43' - | '\uaa44' .. '\uaa4b' - | '\uaa4c' - | '\uaa4d' - | '\uaa50' .. '\uaa59' - | '\uaa60' .. '\uaa6f' - | '\uaa70' - | '\uaa71' .. '\uaa76' - | '\uaa7a' - | '\uaa7b' - | '\uaa80' .. '\uaaaf' - | '\uaab0' - | '\uaab1' - | '\uaab2' .. '\uaab4' - | '\uaab5' .. '\uaab6' - | '\uaab7' .. '\uaab8' - | '\uaab9' .. '\uaabd' - | '\uaabe' .. '\uaabf' - | '\uaac0' - | '\uaac1' - | '\uaac2' - | '\uaadb' .. '\uaadc' - | '\uaadd' - | '\uab01' .. '\uab06' - | '\uab09' .. '\uab0e' - | '\uab11' .. '\uab16' - | '\uab20' .. '\uab26' - | '\uab28' .. '\uab2e' - | '\uabc0' .. '\uabe2' - | '\uabe3' .. '\uabe4' - | '\uabe5' - | '\uabe6' .. '\uabe7' - | '\uabe8' - | '\uabe9' .. '\uabea' - | '\uabec' - | '\uabed' - | '\uabf0' .. '\uabf9' - | '\uac00' .. '\ud7a3' - | '\ud7b0' .. '\ud7c6' - | '\ud7cb' .. '\ud7fb' - | '\uf900' .. '\ufa2d' - | '\ufa30' .. '\ufa6d' - | '\ufa70' .. '\ufad9' - | '\ufb00' .. '\ufb06' - | '\ufb13' .. '\ufb17' - | '\ufb1d' - | '\ufb1e' - | '\ufb1f' .. '\ufb28' - | '\ufb2a' .. '\ufb36' - | '\ufb38' .. '\ufb3c' - | '\ufb3e' - | '\ufb40' .. '\ufb41' - | '\ufb43' .. '\ufb44' - | '\ufb46' .. '\ufbb1' - | '\ufbd3' .. '\ufc5d' - | '\ufc64' .. '\ufd3d' - | '\ufd50' .. '\ufd8f' - | '\ufd92' .. '\ufdc7' - | '\ufdf0' .. '\ufdf9' - | '\ufe00' .. '\ufe0f' - | '\ufe20' .. '\ufe26' - | '\ufe33' .. '\ufe34' - | '\ufe4d' .. '\ufe4f' - | '\ufe71' - | '\ufe73' - | '\ufe77' - | '\ufe79' - | '\ufe7b' - | '\ufe7d' - | '\ufe7f' .. '\ufefc' - | '\uff10' .. '\uff19' - | '\uff21' .. '\uff3a' - | '\uff3f' - | '\uff41' .. '\uff5a' - | '\uff66' .. '\uff6f' - | '\uff70' - | '\uff71' .. '\uff9d' - | '\uff9e' .. '\uff9f' - | '\uffa0' .. '\uffbe' - | '\uffc2' .. '\uffc7' - | '\uffca' .. '\uffcf' - | '\uffd2' .. '\uffd7' - | '\uffda' .. '\uffdc' - | '\U00010000' .. '\U0001000b' - | '\U0001000d' .. '\U00010026' - | '\U00010028' .. '\U0001003a' - | '\U0001003c' .. '\U0001003d' - | '\U0001003f' .. '\U0001004d' - | '\U00010050' .. '\U0001005d' - | '\U00010080' .. '\U000100fa' - | '\U00010140' .. '\U00010174' - | '\U000101fd' - | '\U00010280' .. '\U0001029c' - | '\U000102a0' .. '\U000102d0' - | '\U00010300' .. '\U0001031e' - | '\U00010330' .. '\U00010340' - | '\U00010341' - | '\U00010342' .. '\U00010349' - | '\U0001034a' - | '\U00010380' .. '\U0001039d' - | '\U000103a0' .. '\U000103c3' - | '\U000103c8' .. '\U000103cf' - | '\U000103d1' .. '\U000103d5' - | '\U00010400' .. '\U0001044f' - | '\U00010450' .. '\U0001049d' - | '\U000104a0' .. '\U000104a9' - | '\U00010800' .. '\U00010805' - | '\U00010808' - | '\U0001080a' .. '\U00010835' - | '\U00010837' .. '\U00010838' - | '\U0001083c' - | '\U0001083f' .. '\U00010855' - | '\U00010900' .. '\U00010915' - | '\U00010920' .. '\U00010939' - | '\U00010a00' - | '\U00010a01' .. '\U00010a03' - | '\U00010a05' .. '\U00010a06' - | '\U00010a0c' .. '\U00010a0f' - | '\U00010a10' .. '\U00010a13' - | '\U00010a15' .. '\U00010a17' - | '\U00010a19' .. '\U00010a33' - | '\U00010a38' .. '\U00010a3a' - | '\U00010a3f' - | '\U00010a60' .. '\U00010a7c' - | '\U00010b00' .. '\U00010b35' - | '\U00010b40' .. '\U00010b55' - | '\U00010b60' .. '\U00010b72' - | '\U00010c00' .. '\U00010c48' - | '\U00011000' - | '\U00011001' - | '\U00011002' - | '\U00011003' .. '\U00011037' - | '\U00011038' .. '\U00011046' - | '\U00011066' .. '\U0001106f' - | '\U00011080' .. '\U00011081' - | '\U00011082' - | '\U00011083' .. '\U000110af' - | '\U000110b0' .. '\U000110b2' - | '\U000110b3' .. '\U000110b6' - | '\U000110b7' .. '\U000110b8' - | '\U000110b9' .. '\U000110ba' - | '\U00012000' .. '\U0001236e' - | '\U00012400' .. '\U00012462' - | '\U00013000' .. '\U0001342e' - | '\U00016800' .. '\U00016a38' - | '\U0001b000' .. '\U0001b001' - | '\U0001d165' .. '\U0001d166' - | '\U0001d167' .. '\U0001d169' - | '\U0001d16d' .. '\U0001d172' - | '\U0001d17b' .. '\U0001d182' - | '\U0001d185' .. '\U0001d18b' - | '\U0001d1aa' .. '\U0001d1ad' - | '\U0001d242' .. '\U0001d244' - | '\U0001d400' .. '\U0001d454' - | '\U0001d456' .. '\U0001d49c' - | '\U0001d49e' .. '\U0001d49f' - | '\U0001d4a2' - | '\U0001d4a5' .. '\U0001d4a6' - | '\U0001d4a9' .. '\U0001d4ac' - | '\U0001d4ae' .. '\U0001d4b9' - | '\U0001d4bb' - | '\U0001d4bd' .. '\U0001d4c3' - | '\U0001d4c5' .. '\U0001d505' - | '\U0001d507' .. '\U0001d50a' - | '\U0001d50d' .. '\U0001d514' - | '\U0001d516' .. '\U0001d51c' - | '\U0001d51e' .. '\U0001d539' - | '\U0001d53b' .. '\U0001d53e' - | '\U0001d540' .. '\U0001d544' - | '\U0001d546' - | '\U0001d54a' .. '\U0001d550' - | '\U0001d552' .. '\U0001d6a5' - | '\U0001d6a8' .. '\U0001d6c0' - | '\U0001d6c2' .. '\U0001d6da' - | '\U0001d6dc' .. '\U0001d6fa' - | '\U0001d6fc' .. '\U0001d714' - | '\U0001d716' .. '\U0001d734' - | '\U0001d736' .. '\U0001d74e' - | '\U0001d750' .. '\U0001d76e' - | '\U0001d770' .. '\U0001d788' - | '\U0001d78a' .. '\U0001d7a8' - | '\U0001d7aa' .. '\U0001d7c2' - | '\U0001d7c4' .. '\U0001d7cb' - | '\U0001d7ce' .. '\U0001d7ff' - | '\U00020000' .. '\U0002a6d6' - | '\U0002a700' .. '\U0002b734' - | '\U0002b740' .. '\U0002b81d' - | '\U0002f800' .. '\U0002fa1d' - | '\U000e0100' .. '\U000e01ef' - => true, - _ => false - }; + bsearch_range_table(c, XID_Continue_table) } + static XID_Start_table : &'static [(char,char)] = &[ + ('\x41', '\x5a'), ('\x61', '\x7a'), + ('\xaa', '\xaa'), ('\xb5', '\xb5'), + ('\xba', '\xba'), ('\xc0', '\xd6'), + ('\xd8', '\xf6'), ('\xf8', '\u01ba'), + ('\u01bb', '\u01bb'), ('\u01bc', '\u01bf'), + ('\u01c0', '\u01c3'), ('\u01c4', '\u0293'), + ('\u0294', '\u0294'), ('\u0295', '\u02af'), + ('\u02b0', '\u02c1'), ('\u02c6', '\u02d1'), + ('\u02e0', '\u02e4'), ('\u02ec', '\u02ec'), + ('\u02ee', '\u02ee'), ('\u0370', '\u0373'), + ('\u0374', '\u0374'), ('\u0376', '\u0377'), + ('\u037b', '\u037d'), ('\u0386', '\u0386'), + ('\u0388', '\u038a'), ('\u038c', '\u038c'), + ('\u038e', '\u03a1'), ('\u03a3', '\u03f5'), + ('\u03f7', '\u0481'), ('\u048a', '\u0527'), + ('\u0531', '\u0556'), ('\u0559', '\u0559'), + ('\u0561', '\u0587'), ('\u05d0', '\u05ea'), + ('\u05f0', '\u05f2'), ('\u0620', '\u063f'), + ('\u0640', '\u0640'), ('\u0641', '\u064a'), + ('\u066e', '\u066f'), ('\u0671', '\u06d3'), + ('\u06d5', '\u06d5'), ('\u06e5', '\u06e6'), + ('\u06ee', '\u06ef'), ('\u06fa', '\u06fc'), + ('\u06ff', '\u06ff'), ('\u0710', '\u0710'), + ('\u0712', '\u072f'), ('\u074d', '\u07a5'), + ('\u07b1', '\u07b1'), ('\u07ca', '\u07ea'), + ('\u07f4', '\u07f5'), ('\u07fa', '\u07fa'), + ('\u0800', '\u0815'), ('\u081a', '\u081a'), + ('\u0824', '\u0824'), ('\u0828', '\u0828'), + ('\u0840', '\u0858'), ('\u08a0', '\u08a0'), + ('\u08a2', '\u08ac'), ('\u0904', '\u0939'), + ('\u093d', '\u093d'), ('\u0950', '\u0950'), + ('\u0958', '\u0961'), ('\u0971', '\u0971'), + ('\u0972', '\u0977'), ('\u0979', '\u097f'), + ('\u0985', '\u098c'), ('\u098f', '\u0990'), + ('\u0993', '\u09a8'), ('\u09aa', '\u09b0'), + ('\u09b2', '\u09b2'), ('\u09b6', '\u09b9'), + ('\u09bd', '\u09bd'), ('\u09ce', '\u09ce'), + ('\u09dc', '\u09dd'), ('\u09df', '\u09e1'), + ('\u09f0', '\u09f1'), ('\u0a05', '\u0a0a'), + ('\u0a0f', '\u0a10'), ('\u0a13', '\u0a28'), + ('\u0a2a', '\u0a30'), ('\u0a32', '\u0a33'), + ('\u0a35', '\u0a36'), ('\u0a38', '\u0a39'), + ('\u0a59', '\u0a5c'), ('\u0a5e', '\u0a5e'), + ('\u0a72', '\u0a74'), ('\u0a85', '\u0a8d'), + ('\u0a8f', '\u0a91'), ('\u0a93', '\u0aa8'), + ('\u0aaa', '\u0ab0'), ('\u0ab2', '\u0ab3'), + ('\u0ab5', '\u0ab9'), ('\u0abd', '\u0abd'), + ('\u0ad0', '\u0ad0'), ('\u0ae0', '\u0ae1'), + ('\u0b05', '\u0b0c'), ('\u0b0f', '\u0b10'), + ('\u0b13', '\u0b28'), ('\u0b2a', '\u0b30'), + ('\u0b32', '\u0b33'), ('\u0b35', '\u0b39'), + ('\u0b3d', '\u0b3d'), ('\u0b5c', '\u0b5d'), + ('\u0b5f', '\u0b61'), ('\u0b71', '\u0b71'), + ('\u0b83', '\u0b83'), ('\u0b85', '\u0b8a'), + ('\u0b8e', '\u0b90'), ('\u0b92', '\u0b95'), + ('\u0b99', '\u0b9a'), ('\u0b9c', '\u0b9c'), + ('\u0b9e', '\u0b9f'), ('\u0ba3', '\u0ba4'), + ('\u0ba8', '\u0baa'), ('\u0bae', '\u0bb9'), + ('\u0bd0', '\u0bd0'), ('\u0c05', '\u0c0c'), + ('\u0c0e', '\u0c10'), ('\u0c12', '\u0c28'), + ('\u0c2a', '\u0c33'), ('\u0c35', '\u0c39'), + ('\u0c3d', '\u0c3d'), ('\u0c58', '\u0c59'), + ('\u0c60', '\u0c61'), ('\u0c85', '\u0c8c'), + ('\u0c8e', '\u0c90'), ('\u0c92', '\u0ca8'), + ('\u0caa', '\u0cb3'), ('\u0cb5', '\u0cb9'), + ('\u0cbd', '\u0cbd'), ('\u0cde', '\u0cde'), + ('\u0ce0', '\u0ce1'), ('\u0cf1', '\u0cf2'), + ('\u0d05', '\u0d0c'), ('\u0d0e', '\u0d10'), + ('\u0d12', '\u0d3a'), ('\u0d3d', '\u0d3d'), + ('\u0d4e', '\u0d4e'), ('\u0d60', '\u0d61'), + ('\u0d7a', '\u0d7f'), ('\u0d85', '\u0d96'), + ('\u0d9a', '\u0db1'), ('\u0db3', '\u0dbb'), + ('\u0dbd', '\u0dbd'), ('\u0dc0', '\u0dc6'), + ('\u0e01', '\u0e30'), ('\u0e32', '\u0e32'), + ('\u0e40', '\u0e45'), ('\u0e46', '\u0e46'), + ('\u0e81', '\u0e82'), ('\u0e84', '\u0e84'), + ('\u0e87', '\u0e88'), ('\u0e8a', '\u0e8a'), + ('\u0e8d', '\u0e8d'), ('\u0e94', '\u0e97'), + ('\u0e99', '\u0e9f'), ('\u0ea1', '\u0ea3'), + ('\u0ea5', '\u0ea5'), ('\u0ea7', '\u0ea7'), + ('\u0eaa', '\u0eab'), ('\u0ead', '\u0eb0'), + ('\u0eb2', '\u0eb2'), ('\u0ebd', '\u0ebd'), + ('\u0ec0', '\u0ec4'), ('\u0ec6', '\u0ec6'), + ('\u0edc', '\u0edf'), ('\u0f00', '\u0f00'), + ('\u0f40', '\u0f47'), ('\u0f49', '\u0f6c'), + ('\u0f88', '\u0f8c'), ('\u1000', '\u102a'), + ('\u103f', '\u103f'), ('\u1050', '\u1055'), + ('\u105a', '\u105d'), ('\u1061', '\u1061'), + ('\u1065', '\u1066'), ('\u106e', '\u1070'), + ('\u1075', '\u1081'), ('\u108e', '\u108e'), + ('\u10a0', '\u10c5'), ('\u10c7', '\u10c7'), + ('\u10cd', '\u10cd'), ('\u10d0', '\u10fa'), + ('\u10fc', '\u10fc'), ('\u10fd', '\u1248'), + ('\u124a', '\u124d'), ('\u1250', '\u1256'), + ('\u1258', '\u1258'), ('\u125a', '\u125d'), + ('\u1260', '\u1288'), ('\u128a', '\u128d'), + ('\u1290', '\u12b0'), ('\u12b2', '\u12b5'), + ('\u12b8', '\u12be'), ('\u12c0', '\u12c0'), + ('\u12c2', '\u12c5'), ('\u12c8', '\u12d6'), + ('\u12d8', '\u1310'), ('\u1312', '\u1315'), + ('\u1318', '\u135a'), ('\u1380', '\u138f'), + ('\u13a0', '\u13f4'), ('\u1401', '\u166c'), + ('\u166f', '\u167f'), ('\u1681', '\u169a'), + ('\u16a0', '\u16ea'), ('\u16ee', '\u16f0'), + ('\u1700', '\u170c'), ('\u170e', '\u1711'), + ('\u1720', '\u1731'), ('\u1740', '\u1751'), + ('\u1760', '\u176c'), ('\u176e', '\u1770'), + ('\u1780', '\u17b3'), ('\u17d7', '\u17d7'), + ('\u17dc', '\u17dc'), ('\u1820', '\u1842'), + ('\u1843', '\u1843'), ('\u1844', '\u1877'), + ('\u1880', '\u18a8'), ('\u18aa', '\u18aa'), + ('\u18b0', '\u18f5'), ('\u1900', '\u191c'), + ('\u1950', '\u196d'), ('\u1970', '\u1974'), + ('\u1980', '\u19ab'), ('\u19c1', '\u19c7'), + ('\u1a00', '\u1a16'), ('\u1a20', '\u1a54'), + ('\u1aa7', '\u1aa7'), ('\u1b05', '\u1b33'), + ('\u1b45', '\u1b4b'), ('\u1b83', '\u1ba0'), + ('\u1bae', '\u1baf'), ('\u1bba', '\u1be5'), + ('\u1c00', '\u1c23'), ('\u1c4d', '\u1c4f'), + ('\u1c5a', '\u1c77'), ('\u1c78', '\u1c7d'), + ('\u1ce9', '\u1cec'), ('\u1cee', '\u1cf1'), + ('\u1cf5', '\u1cf6'), ('\u1d00', '\u1d2b'), + ('\u1d2c', '\u1d6a'), ('\u1d6b', '\u1d77'), + ('\u1d78', '\u1d78'), ('\u1d79', '\u1d9a'), + ('\u1d9b', '\u1dbf'), ('\u1e00', '\u1f15'), + ('\u1f18', '\u1f1d'), ('\u1f20', '\u1f45'), + ('\u1f48', '\u1f4d'), ('\u1f50', '\u1f57'), + ('\u1f59', '\u1f59'), ('\u1f5b', '\u1f5b'), + ('\u1f5d', '\u1f5d'), ('\u1f5f', '\u1f7d'), + ('\u1f80', '\u1fb4'), ('\u1fb6', '\u1fbc'), + ('\u1fbe', '\u1fbe'), ('\u1fc2', '\u1fc4'), + ('\u1fc6', '\u1fcc'), ('\u1fd0', '\u1fd3'), + ('\u1fd6', '\u1fdb'), ('\u1fe0', '\u1fec'), + ('\u1ff2', '\u1ff4'), ('\u1ff6', '\u1ffc'), + ('\u2071', '\u2071'), ('\u207f', '\u207f'), + ('\u2090', '\u209c'), ('\u2102', '\u2102'), + ('\u2107', '\u2107'), ('\u210a', '\u2113'), + ('\u2115', '\u2115'), ('\u2118', '\u2118'), + ('\u2119', '\u211d'), ('\u2124', '\u2124'), + ('\u2126', '\u2126'), ('\u2128', '\u2128'), + ('\u212a', '\u212d'), ('\u212e', '\u212e'), + ('\u212f', '\u2134'), ('\u2135', '\u2138'), + ('\u2139', '\u2139'), ('\u213c', '\u213f'), + ('\u2145', '\u2149'), ('\u214e', '\u214e'), + ('\u2160', '\u2182'), ('\u2183', '\u2184'), + ('\u2185', '\u2188'), ('\u2c00', '\u2c2e'), + ('\u2c30', '\u2c5e'), ('\u2c60', '\u2c7b'), + ('\u2c7c', '\u2c7d'), ('\u2c7e', '\u2ce4'), + ('\u2ceb', '\u2cee'), ('\u2cf2', '\u2cf3'), + ('\u2d00', '\u2d25'), ('\u2d27', '\u2d27'), + ('\u2d2d', '\u2d2d'), ('\u2d30', '\u2d67'), + ('\u2d6f', '\u2d6f'), ('\u2d80', '\u2d96'), + ('\u2da0', '\u2da6'), ('\u2da8', '\u2dae'), + ('\u2db0', '\u2db6'), ('\u2db8', '\u2dbe'), + ('\u2dc0', '\u2dc6'), ('\u2dc8', '\u2dce'), + ('\u2dd0', '\u2dd6'), ('\u2dd8', '\u2dde'), + ('\u3005', '\u3005'), ('\u3006', '\u3006'), + ('\u3007', '\u3007'), ('\u3021', '\u3029'), + ('\u3031', '\u3035'), ('\u3038', '\u303a'), + ('\u303b', '\u303b'), ('\u303c', '\u303c'), + ('\u3041', '\u3096'), ('\u309d', '\u309e'), + ('\u309f', '\u309f'), ('\u30a1', '\u30fa'), + ('\u30fc', '\u30fe'), ('\u30ff', '\u30ff'), + ('\u3105', '\u312d'), ('\u3131', '\u318e'), + ('\u31a0', '\u31ba'), ('\u31f0', '\u31ff'), + ('\u3400', '\u4db5'), ('\u4e00', '\u9fcc'), + ('\ua000', '\ua014'), ('\ua015', '\ua015'), + ('\ua016', '\ua48c'), ('\ua4d0', '\ua4f7'), + ('\ua4f8', '\ua4fd'), ('\ua500', '\ua60b'), + ('\ua60c', '\ua60c'), ('\ua610', '\ua61f'), + ('\ua62a', '\ua62b'), ('\ua640', '\ua66d'), + ('\ua66e', '\ua66e'), ('\ua67f', '\ua67f'), + ('\ua680', '\ua697'), ('\ua6a0', '\ua6e5'), + ('\ua6e6', '\ua6ef'), ('\ua717', '\ua71f'), + ('\ua722', '\ua76f'), ('\ua770', '\ua770'), + ('\ua771', '\ua787'), ('\ua788', '\ua788'), + ('\ua78b', '\ua78e'), ('\ua790', '\ua793'), + ('\ua7a0', '\ua7aa'), ('\ua7f8', '\ua7f9'), + ('\ua7fa', '\ua7fa'), ('\ua7fb', '\ua801'), + ('\ua803', '\ua805'), ('\ua807', '\ua80a'), + ('\ua80c', '\ua822'), ('\ua840', '\ua873'), + ('\ua882', '\ua8b3'), ('\ua8f2', '\ua8f7'), + ('\ua8fb', '\ua8fb'), ('\ua90a', '\ua925'), + ('\ua930', '\ua946'), ('\ua960', '\ua97c'), + ('\ua984', '\ua9b2'), ('\ua9cf', '\ua9cf'), + ('\uaa00', '\uaa28'), ('\uaa40', '\uaa42'), + ('\uaa44', '\uaa4b'), ('\uaa60', '\uaa6f'), + ('\uaa70', '\uaa70'), ('\uaa71', '\uaa76'), + ('\uaa7a', '\uaa7a'), ('\uaa80', '\uaaaf'), + ('\uaab1', '\uaab1'), ('\uaab5', '\uaab6'), + ('\uaab9', '\uaabd'), ('\uaac0', '\uaac0'), + ('\uaac2', '\uaac2'), ('\uaadb', '\uaadc'), + ('\uaadd', '\uaadd'), ('\uaae0', '\uaaea'), + ('\uaaf2', '\uaaf2'), ('\uaaf3', '\uaaf4'), + ('\uab01', '\uab06'), ('\uab09', '\uab0e'), + ('\uab11', '\uab16'), ('\uab20', '\uab26'), + ('\uab28', '\uab2e'), ('\uabc0', '\uabe2'), + ('\uac00', '\ud7a3'), ('\ud7b0', '\ud7c6'), + ('\ud7cb', '\ud7fb'), ('\uf900', '\ufa6d'), + ('\ufa70', '\ufad9'), ('\ufb00', '\ufb06'), + ('\ufb13', '\ufb17'), ('\ufb1d', '\ufb1d'), + ('\ufb1f', '\ufb28'), ('\ufb2a', '\ufb36'), + ('\ufb38', '\ufb3c'), ('\ufb3e', '\ufb3e'), + ('\ufb40', '\ufb41'), ('\ufb43', '\ufb44'), + ('\ufb46', '\ufbb1'), ('\ufbd3', '\ufc5d'), + ('\ufc64', '\ufd3d'), ('\ufd50', '\ufd8f'), + ('\ufd92', '\ufdc7'), ('\ufdf0', '\ufdf9'), + ('\ufe71', '\ufe71'), ('\ufe73', '\ufe73'), + ('\ufe77', '\ufe77'), ('\ufe79', '\ufe79'), + ('\ufe7b', '\ufe7b'), ('\ufe7d', '\ufe7d'), + ('\ufe7f', '\ufefc'), ('\uff21', '\uff3a'), + ('\uff41', '\uff5a'), ('\uff66', '\uff6f'), + ('\uff70', '\uff70'), ('\uff71', '\uff9d'), + ('\uffa0', '\uffbe'), ('\uffc2', '\uffc7'), + ('\uffca', '\uffcf'), ('\uffd2', '\uffd7'), + ('\uffda', '\uffdc'), ('\U00010000', '\U0001000b'), + ('\U0001000d', '\U00010026'), ('\U00010028', '\U0001003a'), + ('\U0001003c', '\U0001003d'), ('\U0001003f', '\U0001004d'), + ('\U00010050', '\U0001005d'), ('\U00010080', '\U000100fa'), + ('\U00010140', '\U00010174'), ('\U00010280', '\U0001029c'), + ('\U000102a0', '\U000102d0'), ('\U00010300', '\U0001031e'), + ('\U00010330', '\U00010340'), ('\U00010341', '\U00010341'), + ('\U00010342', '\U00010349'), ('\U0001034a', '\U0001034a'), + ('\U00010380', '\U0001039d'), ('\U000103a0', '\U000103c3'), + ('\U000103c8', '\U000103cf'), ('\U000103d1', '\U000103d5'), + ('\U00010400', '\U0001044f'), ('\U00010450', '\U0001049d'), + ('\U00010800', '\U00010805'), ('\U00010808', '\U00010808'), + ('\U0001080a', '\U00010835'), ('\U00010837', '\U00010838'), + ('\U0001083c', '\U0001083c'), ('\U0001083f', '\U00010855'), + ('\U00010900', '\U00010915'), ('\U00010920', '\U00010939'), + ('\U00010980', '\U000109b7'), ('\U000109be', '\U000109bf'), + ('\U00010a00', '\U00010a00'), ('\U00010a10', '\U00010a13'), + ('\U00010a15', '\U00010a17'), ('\U00010a19', '\U00010a33'), + ('\U00010a60', '\U00010a7c'), ('\U00010b00', '\U00010b35'), + ('\U00010b40', '\U00010b55'), ('\U00010b60', '\U00010b72'), + ('\U00010c00', '\U00010c48'), ('\U00011003', '\U00011037'), + ('\U00011083', '\U000110af'), ('\U000110d0', '\U000110e8'), + ('\U00011103', '\U00011126'), ('\U00011183', '\U000111b2'), + ('\U000111c1', '\U000111c4'), ('\U00011680', '\U000116aa'), + ('\U00012000', '\U0001236e'), ('\U00012400', '\U00012462'), + ('\U00013000', '\U0001342e'), ('\U00016800', '\U00016a38'), + ('\U00016f00', '\U00016f44'), ('\U00016f50', '\U00016f50'), + ('\U00016f93', '\U00016f9f'), ('\U0001b000', '\U0001b001'), + ('\U0001d400', '\U0001d454'), ('\U0001d456', '\U0001d49c'), + ('\U0001d49e', '\U0001d49f'), ('\U0001d4a2', '\U0001d4a2'), + ('\U0001d4a5', '\U0001d4a6'), ('\U0001d4a9', '\U0001d4ac'), + ('\U0001d4ae', '\U0001d4b9'), ('\U0001d4bb', '\U0001d4bb'), + ('\U0001d4bd', '\U0001d4c3'), ('\U0001d4c5', '\U0001d505'), + ('\U0001d507', '\U0001d50a'), ('\U0001d50d', '\U0001d514'), + ('\U0001d516', '\U0001d51c'), ('\U0001d51e', '\U0001d539'), + ('\U0001d53b', '\U0001d53e'), ('\U0001d540', '\U0001d544'), + ('\U0001d546', '\U0001d546'), ('\U0001d54a', '\U0001d550'), + ('\U0001d552', '\U0001d6a5'), ('\U0001d6a8', '\U0001d6c0'), + ('\U0001d6c2', '\U0001d6da'), ('\U0001d6dc', '\U0001d6fa'), + ('\U0001d6fc', '\U0001d714'), ('\U0001d716', '\U0001d734'), + ('\U0001d736', '\U0001d74e'), ('\U0001d750', '\U0001d76e'), + ('\U0001d770', '\U0001d788'), ('\U0001d78a', '\U0001d7a8'), + ('\U0001d7aa', '\U0001d7c2'), ('\U0001d7c4', '\U0001d7cb'), + ('\U0001ee00', '\U0001ee03'), ('\U0001ee05', '\U0001ee1f'), + ('\U0001ee21', '\U0001ee22'), ('\U0001ee24', '\U0001ee24'), + ('\U0001ee27', '\U0001ee27'), ('\U0001ee29', '\U0001ee32'), + ('\U0001ee34', '\U0001ee37'), ('\U0001ee39', '\U0001ee39'), + ('\U0001ee3b', '\U0001ee3b'), ('\U0001ee42', '\U0001ee42'), + ('\U0001ee47', '\U0001ee47'), ('\U0001ee49', '\U0001ee49'), + ('\U0001ee4b', '\U0001ee4b'), ('\U0001ee4d', '\U0001ee4f'), + ('\U0001ee51', '\U0001ee52'), ('\U0001ee54', '\U0001ee54'), + ('\U0001ee57', '\U0001ee57'), ('\U0001ee59', '\U0001ee59'), + ('\U0001ee5b', '\U0001ee5b'), ('\U0001ee5d', '\U0001ee5d'), + ('\U0001ee5f', '\U0001ee5f'), ('\U0001ee61', '\U0001ee62'), + ('\U0001ee64', '\U0001ee64'), ('\U0001ee67', '\U0001ee6a'), + ('\U0001ee6c', '\U0001ee72'), ('\U0001ee74', '\U0001ee77'), + ('\U0001ee79', '\U0001ee7c'), ('\U0001ee7e', '\U0001ee7e'), + ('\U0001ee80', '\U0001ee89'), ('\U0001ee8b', '\U0001ee9b'), + ('\U0001eea1', '\U0001eea3'), ('\U0001eea5', '\U0001eea9'), + ('\U0001eeab', '\U0001eebb'), ('\U00020000', '\U0002a6d6'), + ('\U0002a700', '\U0002b734'), ('\U0002b740', '\U0002b81d'), + ('\U0002f800', '\U0002fa1d') + ]; + pub fn XID_Start(c: char) -> bool { - return match c { - '\x41' .. '\x5a' - | '\x61' .. '\x7a' - | '\xaa' - | '\xb5' - | '\xba' - | '\xc0' .. '\xd6' - | '\xd8' .. '\xf6' - | '\xf8' .. '\u01ba' - | '\u01bb' - | '\u01bc' .. '\u01bf' - | '\u01c0' .. '\u01c3' - | '\u01c4' .. '\u0293' - | '\u0294' - | '\u0295' .. '\u02af' - | '\u02b0' .. '\u02c1' - | '\u02c6' .. '\u02d1' - | '\u02e0' .. '\u02e4' - | '\u02ec' - | '\u02ee' - | '\u0370' .. '\u0373' - | '\u0374' - | '\u0376' .. '\u0377' - | '\u037b' .. '\u037d' - | '\u0386' - | '\u0388' .. '\u038a' - | '\u038c' - | '\u038e' .. '\u03a1' - | '\u03a3' .. '\u03f5' - | '\u03f7' .. '\u0481' - | '\u048a' .. '\u0527' - | '\u0531' .. '\u0556' - | '\u0559' - | '\u0561' .. '\u0587' - | '\u05d0' .. '\u05ea' - | '\u05f0' .. '\u05f2' - | '\u0620' .. '\u063f' - | '\u0640' - | '\u0641' .. '\u064a' - | '\u066e' .. '\u066f' - | '\u0671' .. '\u06d3' - | '\u06d5' - | '\u06e5' .. '\u06e6' - | '\u06ee' .. '\u06ef' - | '\u06fa' .. '\u06fc' - | '\u06ff' - | '\u0710' - | '\u0712' .. '\u072f' - | '\u074d' .. '\u07a5' - | '\u07b1' - | '\u07ca' .. '\u07ea' - | '\u07f4' .. '\u07f5' - | '\u07fa' - | '\u0800' .. '\u0815' - | '\u081a' - | '\u0824' - | '\u0828' - | '\u0840' .. '\u0858' - | '\u0904' .. '\u0939' - | '\u093d' - | '\u0950' - | '\u0958' .. '\u0961' - | '\u0971' - | '\u0972' .. '\u0977' - | '\u0979' .. '\u097f' - | '\u0985' .. '\u098c' - | '\u098f' .. '\u0990' - | '\u0993' .. '\u09a8' - | '\u09aa' .. '\u09b0' - | '\u09b2' - | '\u09b6' .. '\u09b9' - | '\u09bd' - | '\u09ce' - | '\u09dc' .. '\u09dd' - | '\u09df' .. '\u09e1' - | '\u09f0' .. '\u09f1' - | '\u0a05' .. '\u0a0a' - | '\u0a0f' .. '\u0a10' - | '\u0a13' .. '\u0a28' - | '\u0a2a' .. '\u0a30' - | '\u0a32' .. '\u0a33' - | '\u0a35' .. '\u0a36' - | '\u0a38' .. '\u0a39' - | '\u0a59' .. '\u0a5c' - | '\u0a5e' - | '\u0a72' .. '\u0a74' - | '\u0a85' .. '\u0a8d' - | '\u0a8f' .. '\u0a91' - | '\u0a93' .. '\u0aa8' - | '\u0aaa' .. '\u0ab0' - | '\u0ab2' .. '\u0ab3' - | '\u0ab5' .. '\u0ab9' - | '\u0abd' - | '\u0ad0' - | '\u0ae0' .. '\u0ae1' - | '\u0b05' .. '\u0b0c' - | '\u0b0f' .. '\u0b10' - | '\u0b13' .. '\u0b28' - | '\u0b2a' .. '\u0b30' - | '\u0b32' .. '\u0b33' - | '\u0b35' .. '\u0b39' - | '\u0b3d' - | '\u0b5c' .. '\u0b5d' - | '\u0b5f' .. '\u0b61' - | '\u0b71' - | '\u0b83' - | '\u0b85' .. '\u0b8a' - | '\u0b8e' .. '\u0b90' - | '\u0b92' .. '\u0b95' - | '\u0b99' .. '\u0b9a' - | '\u0b9c' - | '\u0b9e' .. '\u0b9f' - | '\u0ba3' .. '\u0ba4' - | '\u0ba8' .. '\u0baa' - | '\u0bae' .. '\u0bb9' - | '\u0bd0' - | '\u0c05' .. '\u0c0c' - | '\u0c0e' .. '\u0c10' - | '\u0c12' .. '\u0c28' - | '\u0c2a' .. '\u0c33' - | '\u0c35' .. '\u0c39' - | '\u0c3d' - | '\u0c58' .. '\u0c59' - | '\u0c60' .. '\u0c61' - | '\u0c85' .. '\u0c8c' - | '\u0c8e' .. '\u0c90' - | '\u0c92' .. '\u0ca8' - | '\u0caa' .. '\u0cb3' - | '\u0cb5' .. '\u0cb9' - | '\u0cbd' - | '\u0cde' - | '\u0ce0' .. '\u0ce1' - | '\u0cf1' .. '\u0cf2' - | '\u0d05' .. '\u0d0c' - | '\u0d0e' .. '\u0d10' - | '\u0d12' .. '\u0d3a' - | '\u0d3d' - | '\u0d4e' - | '\u0d60' .. '\u0d61' - | '\u0d7a' .. '\u0d7f' - | '\u0d85' .. '\u0d96' - | '\u0d9a' .. '\u0db1' - | '\u0db3' .. '\u0dbb' - | '\u0dbd' - | '\u0dc0' .. '\u0dc6' - | '\u0e01' .. '\u0e30' - | '\u0e32' - | '\u0e40' .. '\u0e45' - | '\u0e46' - | '\u0e81' .. '\u0e82' - | '\u0e84' - | '\u0e87' .. '\u0e88' - | '\u0e8a' - | '\u0e8d' - | '\u0e94' .. '\u0e97' - | '\u0e99' .. '\u0e9f' - | '\u0ea1' .. '\u0ea3' - | '\u0ea5' - | '\u0ea7' - | '\u0eaa' .. '\u0eab' - | '\u0ead' .. '\u0eb0' - | '\u0eb2' - | '\u0ebd' - | '\u0ec0' .. '\u0ec4' - | '\u0ec6' - | '\u0edc' .. '\u0edd' - | '\u0f00' - | '\u0f40' .. '\u0f47' - | '\u0f49' .. '\u0f6c' - | '\u0f88' .. '\u0f8c' - | '\u1000' .. '\u102a' - | '\u103f' - | '\u1050' .. '\u1055' - | '\u105a' .. '\u105d' - | '\u1061' - | '\u1065' .. '\u1066' - | '\u106e' .. '\u1070' - | '\u1075' .. '\u1081' - | '\u108e' - | '\u10a0' .. '\u10c5' - | '\u10d0' .. '\u10fa' - | '\u10fc' - | '\u1100' .. '\u1248' - | '\u124a' .. '\u124d' - | '\u1250' .. '\u1256' - | '\u1258' - | '\u125a' .. '\u125d' - | '\u1260' .. '\u1288' - | '\u128a' .. '\u128d' - | '\u1290' .. '\u12b0' - | '\u12b2' .. '\u12b5' - | '\u12b8' .. '\u12be' - | '\u12c0' - | '\u12c2' .. '\u12c5' - | '\u12c8' .. '\u12d6' - | '\u12d8' .. '\u1310' - | '\u1312' .. '\u1315' - | '\u1318' .. '\u135a' - | '\u1380' .. '\u138f' - | '\u13a0' .. '\u13f4' - | '\u1401' .. '\u166c' - | '\u166f' .. '\u167f' - | '\u1681' .. '\u169a' - | '\u16a0' .. '\u16ea' - | '\u16ee' .. '\u16f0' - | '\u1700' .. '\u170c' - | '\u170e' .. '\u1711' - | '\u1720' .. '\u1731' - | '\u1740' .. '\u1751' - | '\u1760' .. '\u176c' - | '\u176e' .. '\u1770' - | '\u1780' .. '\u17b3' - | '\u17d7' - | '\u17dc' - | '\u1820' .. '\u1842' - | '\u1843' - | '\u1844' .. '\u1877' - | '\u1880' .. '\u18a8' - | '\u18aa' - | '\u18b0' .. '\u18f5' - | '\u1900' .. '\u191c' - | '\u1950' .. '\u196d' - | '\u1970' .. '\u1974' - | '\u1980' .. '\u19ab' - | '\u19c1' .. '\u19c7' - | '\u1a00' .. '\u1a16' - | '\u1a20' .. '\u1a54' - | '\u1aa7' - | '\u1b05' .. '\u1b33' - | '\u1b45' .. '\u1b4b' - | '\u1b83' .. '\u1ba0' - | '\u1bae' .. '\u1baf' - | '\u1bc0' .. '\u1be5' - | '\u1c00' .. '\u1c23' - | '\u1c4d' .. '\u1c4f' - | '\u1c5a' .. '\u1c77' - | '\u1c78' .. '\u1c7d' - | '\u1ce9' .. '\u1cec' - | '\u1cee' .. '\u1cf1' - | '\u1d00' .. '\u1d2b' - | '\u1d2c' .. '\u1d61' - | '\u1d62' .. '\u1d77' - | '\u1d78' - | '\u1d79' .. '\u1d9a' - | '\u1d9b' .. '\u1dbf' - | '\u1e00' .. '\u1f15' - | '\u1f18' .. '\u1f1d' - | '\u1f20' .. '\u1f45' - | '\u1f48' .. '\u1f4d' - | '\u1f50' .. '\u1f57' - | '\u1f59' - | '\u1f5b' - | '\u1f5d' - | '\u1f5f' .. '\u1f7d' - | '\u1f80' .. '\u1fb4' - | '\u1fb6' .. '\u1fbc' - | '\u1fbe' - | '\u1fc2' .. '\u1fc4' - | '\u1fc6' .. '\u1fcc' - | '\u1fd0' .. '\u1fd3' - | '\u1fd6' .. '\u1fdb' - | '\u1fe0' .. '\u1fec' - | '\u1ff2' .. '\u1ff4' - | '\u1ff6' .. '\u1ffc' - | '\u2071' - | '\u207f' - | '\u2090' .. '\u209c' - | '\u2102' - | '\u2107' - | '\u210a' .. '\u2113' - | '\u2115' - | '\u2118' - | '\u2119' .. '\u211d' - | '\u2124' - | '\u2126' - | '\u2128' - | '\u212a' .. '\u212d' - | '\u212e' - | '\u212f' .. '\u2134' - | '\u2135' .. '\u2138' - | '\u2139' - | '\u213c' .. '\u213f' - | '\u2145' .. '\u2149' - | '\u214e' - | '\u2160' .. '\u2182' - | '\u2183' .. '\u2184' - | '\u2185' .. '\u2188' - | '\u2c00' .. '\u2c2e' - | '\u2c30' .. '\u2c5e' - | '\u2c60' .. '\u2c7c' - | '\u2c7d' - | '\u2c7e' .. '\u2ce4' - | '\u2ceb' .. '\u2cee' - | '\u2d00' .. '\u2d25' - | '\u2d30' .. '\u2d65' - | '\u2d6f' - | '\u2d80' .. '\u2d96' - | '\u2da0' .. '\u2da6' - | '\u2da8' .. '\u2dae' - | '\u2db0' .. '\u2db6' - | '\u2db8' .. '\u2dbe' - | '\u2dc0' .. '\u2dc6' - | '\u2dc8' .. '\u2dce' - | '\u2dd0' .. '\u2dd6' - | '\u2dd8' .. '\u2dde' - | '\u3005' - | '\u3006' - | '\u3007' - | '\u3021' .. '\u3029' - | '\u3031' .. '\u3035' - | '\u3038' .. '\u303a' - | '\u303b' - | '\u303c' - | '\u3041' .. '\u3096' - | '\u309d' .. '\u309e' - | '\u309f' - | '\u30a1' .. '\u30fa' - | '\u30fc' .. '\u30fe' - | '\u30ff' - | '\u3105' .. '\u312d' - | '\u3131' .. '\u318e' - | '\u31a0' .. '\u31ba' - | '\u31f0' .. '\u31ff' - | '\u3400' .. '\u4db5' - | '\u4e00' .. '\u9fcb' - | '\ua000' .. '\ua014' - | '\ua015' - | '\ua016' .. '\ua48c' - | '\ua4d0' .. '\ua4f7' - | '\ua4f8' .. '\ua4fd' - | '\ua500' .. '\ua60b' - | '\ua60c' - | '\ua610' .. '\ua61f' - | '\ua62a' .. '\ua62b' - | '\ua640' .. '\ua66d' - | '\ua66e' - | '\ua67f' - | '\ua680' .. '\ua697' - | '\ua6a0' .. '\ua6e5' - | '\ua6e6' .. '\ua6ef' - | '\ua717' .. '\ua71f' - | '\ua722' .. '\ua76f' - | '\ua770' - | '\ua771' .. '\ua787' - | '\ua788' - | '\ua78b' .. '\ua78e' - | '\ua790' .. '\ua791' - | '\ua7a0' .. '\ua7a9' - | '\ua7fa' - | '\ua7fb' .. '\ua801' - | '\ua803' .. '\ua805' - | '\ua807' .. '\ua80a' - | '\ua80c' .. '\ua822' - | '\ua840' .. '\ua873' - | '\ua882' .. '\ua8b3' - | '\ua8f2' .. '\ua8f7' - | '\ua8fb' - | '\ua90a' .. '\ua925' - | '\ua930' .. '\ua946' - | '\ua960' .. '\ua97c' - | '\ua984' .. '\ua9b2' - | '\ua9cf' - | '\uaa00' .. '\uaa28' - | '\uaa40' .. '\uaa42' - | '\uaa44' .. '\uaa4b' - | '\uaa60' .. '\uaa6f' - | '\uaa70' - | '\uaa71' .. '\uaa76' - | '\uaa7a' - | '\uaa80' .. '\uaaaf' - | '\uaab1' - | '\uaab5' .. '\uaab6' - | '\uaab9' .. '\uaabd' - | '\uaac0' - | '\uaac2' - | '\uaadb' .. '\uaadc' - | '\uaadd' - | '\uab01' .. '\uab06' - | '\uab09' .. '\uab0e' - | '\uab11' .. '\uab16' - | '\uab20' .. '\uab26' - | '\uab28' .. '\uab2e' - | '\uabc0' .. '\uabe2' - | '\uac00' .. '\ud7a3' - | '\ud7b0' .. '\ud7c6' - | '\ud7cb' .. '\ud7fb' - | '\uf900' .. '\ufa2d' - | '\ufa30' .. '\ufa6d' - | '\ufa70' .. '\ufad9' - | '\ufb00' .. '\ufb06' - | '\ufb13' .. '\ufb17' - | '\ufb1d' - | '\ufb1f' .. '\ufb28' - | '\ufb2a' .. '\ufb36' - | '\ufb38' .. '\ufb3c' - | '\ufb3e' - | '\ufb40' .. '\ufb41' - | '\ufb43' .. '\ufb44' - | '\ufb46' .. '\ufbb1' - | '\ufbd3' .. '\ufc5d' - | '\ufc64' .. '\ufd3d' - | '\ufd50' .. '\ufd8f' - | '\ufd92' .. '\ufdc7' - | '\ufdf0' .. '\ufdf9' - | '\ufe71' - | '\ufe73' - | '\ufe77' - | '\ufe79' - | '\ufe7b' - | '\ufe7d' - | '\ufe7f' .. '\ufefc' - | '\uff21' .. '\uff3a' - | '\uff41' .. '\uff5a' - | '\uff66' .. '\uff6f' - | '\uff70' - | '\uff71' .. '\uff9d' - | '\uffa0' .. '\uffbe' - | '\uffc2' .. '\uffc7' - | '\uffca' .. '\uffcf' - | '\uffd2' .. '\uffd7' - | '\uffda' .. '\uffdc' - | '\U00010000' .. '\U0001000b' - | '\U0001000d' .. '\U00010026' - | '\U00010028' .. '\U0001003a' - | '\U0001003c' .. '\U0001003d' - | '\U0001003f' .. '\U0001004d' - | '\U00010050' .. '\U0001005d' - | '\U00010080' .. '\U000100fa' - | '\U00010140' .. '\U00010174' - | '\U00010280' .. '\U0001029c' - | '\U000102a0' .. '\U000102d0' - | '\U00010300' .. '\U0001031e' - | '\U00010330' .. '\U00010340' - | '\U00010341' - | '\U00010342' .. '\U00010349' - | '\U0001034a' - | '\U00010380' .. '\U0001039d' - | '\U000103a0' .. '\U000103c3' - | '\U000103c8' .. '\U000103cf' - | '\U000103d1' .. '\U000103d5' - | '\U00010400' .. '\U0001044f' - | '\U00010450' .. '\U0001049d' - | '\U00010800' .. '\U00010805' - | '\U00010808' - | '\U0001080a' .. '\U00010835' - | '\U00010837' .. '\U00010838' - | '\U0001083c' - | '\U0001083f' .. '\U00010855' - | '\U00010900' .. '\U00010915' - | '\U00010920' .. '\U00010939' - | '\U00010a00' - | '\U00010a10' .. '\U00010a13' - | '\U00010a15' .. '\U00010a17' - | '\U00010a19' .. '\U00010a33' - | '\U00010a60' .. '\U00010a7c' - | '\U00010b00' .. '\U00010b35' - | '\U00010b40' .. '\U00010b55' - | '\U00010b60' .. '\U00010b72' - | '\U00010c00' .. '\U00010c48' - | '\U00011003' .. '\U00011037' - | '\U00011083' .. '\U000110af' - | '\U00012000' .. '\U0001236e' - | '\U00012400' .. '\U00012462' - | '\U00013000' .. '\U0001342e' - | '\U00016800' .. '\U00016a38' - | '\U0001b000' .. '\U0001b001' - | '\U0001d400' .. '\U0001d454' - | '\U0001d456' .. '\U0001d49c' - | '\U0001d49e' .. '\U0001d49f' - | '\U0001d4a2' - | '\U0001d4a5' .. '\U0001d4a6' - | '\U0001d4a9' .. '\U0001d4ac' - | '\U0001d4ae' .. '\U0001d4b9' - | '\U0001d4bb' - | '\U0001d4bd' .. '\U0001d4c3' - | '\U0001d4c5' .. '\U0001d505' - | '\U0001d507' .. '\U0001d50a' - | '\U0001d50d' .. '\U0001d514' - | '\U0001d516' .. '\U0001d51c' - | '\U0001d51e' .. '\U0001d539' - | '\U0001d53b' .. '\U0001d53e' - | '\U0001d540' .. '\U0001d544' - | '\U0001d546' - | '\U0001d54a' .. '\U0001d550' - | '\U0001d552' .. '\U0001d6a5' - | '\U0001d6a8' .. '\U0001d6c0' - | '\U0001d6c2' .. '\U0001d6da' - | '\U0001d6dc' .. '\U0001d6fa' - | '\U0001d6fc' .. '\U0001d714' - | '\U0001d716' .. '\U0001d734' - | '\U0001d736' .. '\U0001d74e' - | '\U0001d750' .. '\U0001d76e' - | '\U0001d770' .. '\U0001d788' - | '\U0001d78a' .. '\U0001d7a8' - | '\U0001d7aa' .. '\U0001d7c2' - | '\U0001d7c4' .. '\U0001d7cb' - | '\U00020000' .. '\U0002a6d6' - | '\U0002a700' .. '\U0002b734' - | '\U0002b740' .. '\U0002b81d' - | '\U0002f800' .. '\U0002fa1d' - => true, - _ => false - }; + bsearch_range_table(c, XID_Start_table) } } diff --git a/src/libcore/unstable.rs b/src/libcore/unstable.rs index 665a3e1b6b6d4..c057fce0abd8c 100644 --- a/src/libcore/unstable.rs +++ b/src/libcore/unstable.rs @@ -16,6 +16,7 @@ use comm::{GenericChan, GenericPort}; use prelude::*; use task; use task::atomically; +use self::finally::Finally; #[path = "unstable/at_exit.rs"] pub mod at_exit; @@ -106,13 +107,13 @@ fn compare_and_swap(address: &mut int, oldval: int, newval: int) -> bool { ****************************************************************************/ struct ArcData { - mut count: libc::intptr_t, + count: libc::intptr_t, // FIXME(#3224) should be able to make this non-option to save memory - mut data: Option, + data: Option, } struct ArcDestruct { - mut data: *libc::c_void, + data: *libc::c_void, } #[unsafe_destructor] @@ -120,7 +121,7 @@ impl Drop for ArcDestruct{ fn finalize(&self) { unsafe { do task::unkillable { - let data: ~ArcData = cast::reinterpret_cast(&self.data); + let mut data: ~ArcData = cast::reinterpret_cast(&self.data); let new_count = intrinsics::atomic_xsub(&mut data.count, 1) - 1; assert!(new_count >= 0); @@ -151,45 +152,37 @@ pub type SharedMutableState = ArcDestruct; pub unsafe fn shared_mutable_state(data: T) -> SharedMutableState { let data = ~ArcData { count: 1, data: Some(data) }; - unsafe { - let ptr = cast::transmute(data); - ArcDestruct(ptr) - } + let ptr = cast::transmute(data); + ArcDestruct(ptr) } #[inline(always)] pub unsafe fn get_shared_mutable_state( rc: *SharedMutableState) -> *mut T { - unsafe { - let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); - assert!(ptr.count > 0); - let r = cast::transmute(ptr.data.get_ref()); - cast::forget(ptr); - return r; - } + let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); + assert!(ptr.count > 0); + let r = cast::transmute(ptr.data.get_ref()); + cast::forget(ptr); + return r; } #[inline(always)] pub unsafe fn get_shared_immutable_state<'a,T:Owned>( rc: &'a SharedMutableState) -> &'a T { - unsafe { - let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); - assert!(ptr.count > 0); - // Cast us back into the correct region - let r = cast::transmute_region(ptr.data.get_ref()); - cast::forget(ptr); - return r; - } + let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); + assert!(ptr.count > 0); + // Cast us back into the correct region + let r = cast::transmute_region(ptr.data.get_ref()); + cast::forget(ptr); + return r; } pub unsafe fn clone_shared_mutable_state(rc: &SharedMutableState) -> SharedMutableState { - unsafe { - let ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); - let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1; - assert!(new_count >= 2); - cast::forget(ptr); - } + let mut ptr: ~ArcData = cast::reinterpret_cast(&(*rc).data); + let new_count = intrinsics::atomic_xadd(&mut ptr.count, 1) + 1; + assert!(new_count >= 2); + cast::forget(ptr); ArcDestruct((*rc).data) } @@ -229,30 +222,18 @@ fn LittleLock() -> LittleLock { pub impl LittleLock { #[inline(always)] unsafe fn lock(&self, f: &fn() -> T) -> T { - struct Unlock { - l: rust_little_lock, - drop { - unsafe { - rustrt::rust_unlock_little_lock(self.l); - } - } - } - - fn Unlock(l: rust_little_lock) -> Unlock { - Unlock { - l: l - } - } - do atomically { rustrt::rust_lock_little_lock(self.l); - let _r = Unlock(self.l); - f() + do (|| { + f() + }).finally { + rustrt::rust_unlock_little_lock(self.l); + } } } } -struct ExData { lock: LittleLock, mut failed: bool, mut data: T, } +struct ExData { lock: LittleLock, failed: bool, data: T, } /** * An arc over mutable data that is protected by a lock. For library use only. */ @@ -260,7 +241,7 @@ pub struct Exclusive { x: SharedMutableState> } pub fn exclusive(user_data: T) -> Exclusive { let data = ExData { - lock: LittleLock(), mut failed: false, mut data: user_data + lock: LittleLock(), failed: false, data: user_data }; Exclusive { x: unsafe { shared_mutable_state(data) } } } @@ -305,14 +286,14 @@ pub impl Exclusive { } #[cfg(test)] -pub mod tests { +mod tests { use comm; use super::exclusive; use task; use uint; #[test] - pub fn exclusive_arc() { + fn exclusive_arc() { let mut futures = ~[]; let num_tasks = 10; @@ -343,7 +324,7 @@ pub mod tests { } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn exclusive_poison() { + fn exclusive_poison() { // Tests that if one task fails inside of an exclusive, subsequent // accesses will also fail. let x = exclusive(1); diff --git a/src/libcore/unstable/exchange_alloc.rs b/src/libcore/unstable/exchange_alloc.rs index fdf99e9dffea6..8ca5486d92992 100644 --- a/src/libcore/unstable/exchange_alloc.rs +++ b/src/libcore/unstable/exchange_alloc.rs @@ -19,27 +19,25 @@ use ptr::null; use intrinsic::TyDesc; pub unsafe fn malloc(td: *TypeDesc, size: uint) -> *c_void { - unsafe { - assert!(td.is_not_null()); + assert!(td.is_not_null()); - let total_size = get_box_size(size, (*td).align); - let p = c_malloc(total_size as size_t); - assert!(p.is_not_null()); + let total_size = get_box_size(size, (*td).align); + let p = c_malloc(total_size as size_t); + assert!(p.is_not_null()); - // FIXME #3475: Converting between our two different tydesc types - let td: *TyDesc = transmute(td); + // FIXME #3475: Converting between our two different tydesc types + let td: *TyDesc = transmute(td); - let box: &mut BoxRepr = transmute(p); - box.header.ref_count = -1; // Exchange values not ref counted - box.header.type_desc = td; - box.header.prev = null(); - box.header.next = null(); + let box: &mut BoxRepr = transmute(p); + box.header.ref_count = -1; // Exchange values not ref counted + box.header.type_desc = td; + box.header.prev = null(); + box.header.next = null(); - let exchange_count = &mut *rust_get_exchange_count_ptr(); - atomic_xadd(exchange_count, 1); + let exchange_count = &mut *rust_get_exchange_count_ptr(); + atomic_xadd(exchange_count, 1); - return transmute(box); - } + return transmute(box); } /** Thin wrapper around libc::malloc, none of the box header diff --git a/src/libcore/unstable/extfmt.rs b/src/libcore/unstable/extfmt.rs index be2aecf0c2a3b..ad3dce0a74992 100644 --- a/src/libcore/unstable/extfmt.rs +++ b/src/libcore/unstable/extfmt.rs @@ -512,7 +512,7 @@ pub mod rt { None } } else { Some('-') }; - unsafe { pad(cv, s, head, PadSigned, buf) }; + pad(cv, s, head, PadSigned, buf); } pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) { let prec = get_int_precision(cv); @@ -524,7 +524,7 @@ pub mod rt { TyBits => uint_to_str_prec(u, 2, prec), TyOctal => uint_to_str_prec(u, 8, prec) }; - unsafe { pad(cv, rs, None, PadUnsigned, buf) }; + pad(cv, rs, None, PadUnsigned, buf); } pub fn conv_bool(cv: Conv, b: bool, buf: &mut ~str) { let s = if b { "true" } else { "false" }; @@ -533,7 +533,7 @@ pub mod rt { conv_str(cv, s, buf); } pub fn conv_char(cv: Conv, c: char, buf: &mut ~str) { - unsafe { pad(cv, "", Some(c), PadNozero, buf) }; + pad(cv, "", Some(c), PadNozero, buf); } pub fn conv_str(cv: Conv, s: &str, buf: &mut ~str) { // For strings, precision is the maximum characters @@ -546,14 +546,14 @@ pub mod rt { s } }; - unsafe { pad(cv, unpadded, None, PadNozero, buf) }; + pad(cv, unpadded, None, PadNozero, buf); } pub fn conv_float(cv: Conv, f: float, buf: &mut ~str) { let (to_str, digits) = match cv.precision { CountIs(c) => (float::to_str_exact, c as uint), CountImplied => (float::to_str_digits, 6u) }; - let mut s = unsafe { to_str(f, digits) }; + let mut s = to_str(f, digits); let head = if 0.0 <= f { if have_flag(cv.flags, flag_sign_always) { Some('+') @@ -563,7 +563,7 @@ pub mod rt { None } } else { None }; - unsafe { pad(cv, s, head, PadFloat, buf) }; + pad(cv, s, head, PadFloat, buf); } pub fn conv_poly(cv: Conv, v: &T, buf: &mut ~str) { let s = sys::log_str(v); diff --git a/src/libcore/unstable/finally.rs b/src/libcore/unstable/finally.rs index 4d2daa6f15027..559287b529772 100644 --- a/src/libcore/unstable/finally.rs +++ b/src/libcore/unstable/finally.rs @@ -25,7 +25,7 @@ do || { use ops::Drop; -#[cfg(test)] use task::failing; +#[cfg(test)] use task::{failing, spawn}; pub trait Finally { fn finally(&self, dtor: &fn()) -> T; @@ -41,6 +41,26 @@ impl<'self,T> Finally for &'self fn() -> T { } } +impl Finally for ~fn() -> T { + fn finally(&self, dtor: &fn()) -> T { + let _d = Finallyalizer { + dtor: dtor + }; + + (*self)() + } +} + +impl Finally for @fn() -> T { + fn finally(&self, dtor: &fn()) -> T { + let _d = Finallyalizer { + dtor: dtor + }; + + (*self)() + } +} + struct Finallyalizer<'self> { dtor: &'self fn() } @@ -96,3 +116,24 @@ fn test_compact() { do_some_fallible_work.finally( but_always_run_this_function); } + +#[test] +fn test_owned() { + fn spawn_with_finalizer(f: ~fn()) { + do spawn { do f.finally { } } + } + let owned: ~fn() = || { }; + spawn_with_finalizer(owned); +} + +#[test] +fn test_managed() { + let i = @mut 10; + let managed: @fn() -> int = || { + let r = *i; + *i += 10; + r + }; + assert!(do managed.finally {} == 10); + assert!(*i == 20); +} \ No newline at end of file diff --git a/src/libcore/unstable/global.rs b/src/libcore/unstable/global.rs index ef5970658a192..41d0842002f67 100644 --- a/src/libcore/unstable/global.rs +++ b/src/libcore/unstable/global.rs @@ -34,7 +34,7 @@ use ops::Drop; use unstable::{Exclusive, exclusive}; use unstable::at_exit::at_exit; use unstable::intrinsics::atomic_cxchg; -use hashmap::linear::LinearMap; +use hashmap::HashMap; use sys::Closure; #[cfg(test)] use unstable::{SharedMutableState, shared_mutable_state}; @@ -144,7 +144,7 @@ pub unsafe fn global_data_clone( // destructor. Keys are pointers derived from the type of the // global value. There is a single GlobalState instance per runtime. struct GlobalState { - map: LinearMap + map: HashMap } impl Drop for GlobalState { @@ -171,7 +171,7 @@ fn get_global_state() -> Exclusive { // The global state object let state = GlobalState { - map: LinearMap::new() + map: HashMap::new() }; // It's under a reference-counted mutex diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index dad990c0f97cf..be776a39742f0 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -44,7 +44,7 @@ pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { } #[lang="fail_bounds_check"] -pub unsafe fn fail_bounds_check(file: *c_char, line: size_t, +pub fn fail_bounds_check(file: *c_char, line: size_t, index: size_t, len: size_t) { let msg = fmt!("index out of bounds: the len is %d but the index is %d", len as int, index as int); @@ -53,7 +53,7 @@ pub unsafe fn fail_bounds_check(file: *c_char, line: size_t, } } -pub unsafe fn fail_borrowed() { +pub fn fail_borrowed() { let msg = "borrowed"; do str::as_buf(msg) |msg_p, _| { do str::as_buf("???") |file_p, _| { diff --git a/src/libcore/unstable/weak_task.rs b/src/libcore/unstable/weak_task.rs index 8b24c2fa6f622..6eabb0629d1fc 100644 --- a/src/libcore/unstable/weak_task.rs +++ b/src/libcore/unstable/weak_task.rs @@ -21,7 +21,7 @@ is trying to shut down. use cell::Cell; use comm::{GenericSmartChan, stream}; use comm::{Port, Chan, SharedChan, GenericChan, GenericPort}; -use hashmap::linear::LinearMap; +use hashmap::HashMap; use option::{Some, None}; use unstable::at_exit::at_exit; use unstable::finally::Finally; @@ -97,7 +97,7 @@ fn create_global_service() -> ~WeakTaskService { fn run_weak_task_service(port: Port) { - let mut shutdown_map = LinearMap::new(); + let mut shutdown_map = HashMap::new(); loop { match port.recv() { diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 0ac86ac280d06..f123489e075bd 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -167,7 +167,7 @@ pub fn from_slice(t: &[T]) -> ~[T] { pub fn with_capacity(capacity: uint) -> ~[T] { let mut vec = ~[]; - unsafe { reserve(&mut vec, capacity); } + reserve(&mut vec, capacity); vec } @@ -186,7 +186,7 @@ pub fn with_capacity(capacity: uint) -> ~[T] { #[inline(always)] pub fn build_sized(size: uint, builder: &fn(push: &fn(v: A))) -> ~[A] { let mut vec = with_capacity(size); - builder(|x| unsafe { vec.push(x) }); + builder(|x| vec.push(x)); vec } @@ -437,12 +437,10 @@ pub fn partitioned(v: &[T], f: &fn(&T) -> bool) -> (~[T], ~[T]) { let mut rights = ~[]; for each(v) |elt| { - unsafe { - if f(elt) { - lefts.push(*elt); - } else { - rights.push(*elt); - } + if f(elt) { + lefts.push(*elt); + } else { + rights.push(*elt); } } @@ -633,7 +631,7 @@ pub fn push(v: &mut ~[T], initval: T) { // This doesn't bother to make sure we have space. #[inline(always)] // really pretty please unsafe fn push_fast(v: &mut ~[T], initval: T) { - let repr: **raw::VecRepr = ::cast::transmute(v); + let repr: **mut raw::VecRepr = ::cast::transmute(v); let fill = (**repr).unboxed.fill; (**repr).unboxed.fill += sys::nonzero_size_of::(); let p = addr_of(&((**repr).unboxed.data)); @@ -735,16 +733,14 @@ pub fn dedup(v: &mut ~[T]) { #[inline(always)] pub fn append(lhs: ~[T], rhs: &const [T]) -> ~[T] { let mut v = lhs; - unsafe { - v.push_all(rhs); - } + v.push_all(rhs); v } #[inline(always)] pub fn append_one(lhs: ~[T], x: T) -> ~[T] { let mut v = lhs; - unsafe { v.push(x); } + v.push(x); v } @@ -811,9 +807,7 @@ pub fn grow_set(v: &mut ~[T], index: uint, initval: &T, val: T) { pub fn map(v: &[T], f: &fn(t: &T) -> U) -> ~[U] { let mut result = with_capacity(len(v)); for each(v) |elem| { - unsafe { - result.push(f(elem)); - } + result.push(f(elem)); } result } @@ -841,7 +835,7 @@ pub fn mapi(v: &[T], f: &fn(uint, t: &T) -> U) -> ~[U] { */ pub fn flat_map(v: &[T], f: &fn(t: &T) -> ~[U]) -> ~[U] { let mut result = ~[]; - for each(v) |elem| { unsafe{ result.push_all_move(f(elem)); } } + for each(v) |elem| { result.push_all_move(f(elem)); } result } @@ -853,7 +847,7 @@ pub fn map2(v0: &[T], v1: &[U], let mut u: ~[V] = ~[]; let mut i = 0u; while i < v0_len { - unsafe { u.push(f(&v0[i], &v1[i])) }; + u.push(f(&v0[i], &v1[i])); i += 1u; } u @@ -894,7 +888,7 @@ pub fn filter_mapped( for each(v) |elem| { match f(elem) { None => {/* no-op */ } - Some(result_elem) => unsafe { result.push(result_elem); } + Some(result_elem) => { result.push(result_elem); } } } result @@ -927,7 +921,7 @@ pub fn filter(v: ~[T], f: &fn(t: &T) -> bool) -> ~[T] { pub fn filtered(v: &[T], f: &fn(t: &T) -> bool) -> ~[T] { let mut result = ~[]; for each(v) |elem| { - if f(elem) { unsafe { result.push(*elem); } } + if f(elem) { result.push(*elem); } } result } @@ -959,7 +953,7 @@ pub fn retain(v: &mut ~[T], f: &fn(t: &T) -> bool) { */ pub fn concat(v: &[~[T]]) -> ~[T] { let mut r = ~[]; - for each(v) |inner| { unsafe { r.push_all(*inner); } } + for each(v) |inner| { r.push_all(*inner); } r } @@ -968,8 +962,8 @@ pub fn connect(v: &[~[T]], sep: &T) -> ~[T] { let mut r: ~[T] = ~[]; let mut first = true; for each(v) |inner| { - if first { first = false; } else { unsafe { r.push(*sep); } } - unsafe { r.push_all(*inner) }; + if first { first = false; } else { r.push(*sep); } + r.push_all(*inner); } r } @@ -1225,6 +1219,46 @@ pub fn rposition_between(v: &[T], start: uint, end: uint, None } + + +/** + * Binary search a sorted vector with a comparator function. + * + * The comparator should implement an order consistent with the sort + * order of the underlying vector, returning an order code that indicates + * whether its argument is `Less`, `Equal` or `Greater` the desired target. + * + * Returns the index where the comparator returned `Equal`, or `None` if + * not found. + */ +pub fn bsearch(v: &[T], f: &fn(&T) -> Ordering) -> Option { + let mut base : uint = 0; + let mut lim : uint = v.len(); + + while lim != 0 { + let ix = base + (lim >> 1); + match f(&v[ix]) { + Equal => return Some(ix), + Less => { + base = ix + 1; + lim -= 1; + } + Greater => () + } + lim >>= 1; + } + return None; +} + +/** + * Binary search a sorted vector for a given element. + * + * Returns the index of the element or None if not found. + */ +pub fn bsearch_elem(v: &[T], x: &T) -> Option { + bsearch(v, |p| p.cmp(x)) +} + // FIXME: if issue #586 gets implemented, could have a postcondition // saying the two result lists have the same length -- or, could // return a nominal record with a constraint saying that, instead of @@ -1236,10 +1270,8 @@ pub fn unzip_slice(v: &[(T, U)]) -> (~[T], ~[U]) { let mut ts = ~[], us = ~[]; for each(v) |p| { let (t, u) = *p; - unsafe { - ts.push(t); - us.push(u); - } + ts.push(t); + us.push(u); } (ts, us) } @@ -1254,12 +1286,10 @@ pub fn unzip_slice(v: &[(T, U)]) -> (~[T], ~[U]) { */ pub fn unzip(v: ~[(T, U)]) -> (~[T], ~[U]) { let mut ts = ~[], us = ~[]; - unsafe { - do consume(v) |_i, p| { - let (t, u) = p; - ts.push(t); - us.push(u); - } + do consume(v) |_i, p| { + let (t, u) = p; + ts.push(t); + us.push(u); } (ts, us) } @@ -1274,7 +1304,8 @@ pub fn zip_slice(v: &const [T], u: &const [U]) let mut i = 0u; assert!(sz == len(u)); while i < sz { - unsafe { zipped.push((v[i], u[i])); i += 1u; } + zipped.push((v[i], u[i])); + i += 1u; } zipped } @@ -1290,10 +1321,10 @@ pub fn zip(mut v: ~[T], mut u: ~[U]) -> ~[(T, U)] { assert!(i == len(u)); let mut w = with_capacity(i); while i > 0 { - unsafe { w.push((v.pop(),u.pop())); } + w.push((v.pop(),u.pop())); i -= 1; } - unsafe { reverse(w); } + reverse(w); w } @@ -1322,10 +1353,8 @@ pub fn reversed(v: &const [T]) -> ~[T] { let mut rs: ~[T] = ~[]; let mut i = len::(v); if i == 0 { return (rs); } else { i -= 1; } - unsafe { - while i != 0 { rs.push(v[i]); i -= 1; } - rs.push(v[0]); - } + while i != 0 { rs.push(v[i]); i -= 1; } + rs.push(v[0]); rs } @@ -1495,12 +1524,10 @@ pub fn each_permutation(v: &[T], put: &fn(ts: &[T]) -> bool) { while i < ln { let elt = v[i]; let mut rest = slice(v, 0u, i).to_vec(); - unsafe { - rest.push_all(const_slice(v, i+1u, ln)); - for each_permutation(rest) |permutation| { - if !put(append(~[elt], permutation)) { - return; - } + rest.push_all(const_slice(v, i+1u, ln)); + for each_permutation(rest) |permutation| { + if !put(append(~[elt], permutation)) { + return; } } i += 1u; @@ -1508,18 +1535,35 @@ pub fn each_permutation(v: &[T], put: &fn(ts: &[T]) -> bool) { } } -pub fn windowed(nn: uint, xx: &[TT]) -> ~[~[TT]] { - let mut ww = ~[]; - assert!(1u <= nn); - for vec::eachi (xx) |ii, _x| { - let len = xx.len(); - if ii+nn <= len { - unsafe { - ww.push(slice(xx, ii, ii+nn).to_vec()); - } - } +/** + * Iterate over all contiguous windows of length `n` of the vector `v`. + * + * # Example + * + * Print the adjacent pairs of a vector (i.e. `[1,2]`, `[2,3]`, `[3,4]`) + * + * ~~~ + * for windowed(2, &[1,2,3,4]) |v| { + * io::println(fmt!("%?", v)); + * } + * ~~~ + * + */ +#[cfg(stage0)] // XXX: lifetimes! +pub fn windowed(n: uint, v: &[T], it: &fn(&[T]) -> bool) { + assert!(1u <= n); + for uint::range(0, v.len() - n + 1) |i| { + if !it(v.slice(i, i+n)) { return } + } +} +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub fn windowed<'r, T>(n: uint, v: &'r [T], it: &fn(&'r [T]) -> bool) { + assert!(1u <= n); + for uint::range(0, v.len() - n + 1) |i| { + if !it(v.slice(i, i + n)) { return } } - ww } /** @@ -1778,6 +1822,7 @@ impl<'self,T:Copy> CopyableVector for &'self const [T] { } } +#[cfg(stage0)] pub trait ImmutableVector { fn slice(&self, start: uint, end: uint) -> &'self [T]; fn head(&self) -> &'self T; @@ -1800,6 +1845,7 @@ pub trait ImmutableVector { } /// Extension methods for vectors +#[cfg(stage0)] impl<'self,T> ImmutableVector for &'self [T] { /// Return a slice that points into another slice. #[inline] @@ -1908,6 +1954,142 @@ impl<'self,T> ImmutableVector for &'self [T] { } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub trait ImmutableVector<'self, T> { + fn slice(&self, start: uint, end: uint) -> &'self [T]; + fn head(&self) -> &'self T; + fn head_opt(&self) -> Option<&'self T>; + fn tail(&self) -> &'self [T]; + fn tailn(&self, n: uint) -> &'self [T]; + fn init(&self) -> &'self [T]; + fn initn(&self, n: uint) -> &'self [T]; + fn last(&self) -> &'self T; + fn last_opt(&self) -> Option<&'self T>; + fn each_reverse(&self, blk: &fn(&T) -> bool); + fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool); + fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U; + fn map(&self, f: &fn(t: &T) -> U) -> ~[U]; + fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; + fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U]; + fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool; + fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; + fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U]; +} + +/// Extension methods for vectors +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +impl<'self,T> ImmutableVector<'self, T> for &'self [T] { + /// Return a slice that points into another slice. + #[inline] + fn slice(&self, start: uint, end: uint) -> &'self [T] { + slice(*self, start, end) + } + + /// Returns the first element of a vector, failing if the vector is empty. + #[inline] + fn head(&self) -> &'self T { head(*self) } + + /// Returns the first element of a vector + #[inline] + fn head_opt(&self) -> Option<&'self T> { head_opt(*self) } + + /// Returns all but the first element of a vector + #[inline] + fn tail(&self) -> &'self [T] { tail(*self) } + + /// Returns all but the first `n' elements of a vector + #[inline] + fn tailn(&self, n: uint) -> &'self [T] { tailn(*self, n) } + + /// Returns all but the last elemnt of a vector + #[inline] + fn init(&self) -> &'self [T] { init(*self) } + + /// Returns all but the last `n' elemnts of a vector + #[inline] + fn initn(&self, n: uint) -> &'self [T] { initn(*self, n) } + + /// Returns the last element of a `v`, failing if the vector is empty. + #[inline] + fn last(&self) -> &'self T { last(*self) } + + /// Returns the last element of a `v`, failing if the vector is empty. + #[inline] + fn last_opt(&self) -> Option<&'self T> { last_opt(*self) } + + /// Iterates over a vector's elements in reverse. + #[inline] + fn each_reverse(&self, blk: &fn(&T) -> bool) { + each_reverse(*self, blk) + } + + /// Iterates over a vector's elements and indices in reverse. + #[inline] + fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) { + eachi_reverse(*self, blk) + } + + /// Reduce a vector from right to left + #[inline] + fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U { + foldr(*self, z, p) + } + + /// Apply a function to each element of a vector and return the results + #[inline] + fn map(&self, f: &fn(t: &T) -> U) -> ~[U] { map(*self, f) } + + /** + * Apply a function to the index and value of each element in the vector + * and return the results + */ + fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U] { + mapi(*self, f) + } + + #[inline] + fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U] { + let mut r = ~[]; + let mut i = 0; + while i < self.len() { + r.push(f(&self[i])); + i += 1; + } + r + } + + /** + * Returns true if the function returns true for all elements. + * + * If the vector is empty, true is returned. + */ + fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool { + alli(*self, f) + } + /** + * Apply a function to each element of a vector and return a concatenation + * of each result vector + */ + #[inline] + fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U] { + flat_map(*self, f) + } + /** + * Apply a function to each element of a vector and return the results + * + * If function `f` returns `none` then that element is excluded from + * the resulting vector. + */ + #[inline] + fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U] { + filter_mapped(*self, f) + } +} + pub trait ImmutableEqVector { fn position(&self, f: &fn(t: &T) -> bool) -> Option; fn position_elem(&self, t: &T) -> Option; @@ -2148,8 +2330,8 @@ pub unsafe fn from_buf(ptr: *T, elts: uint) -> ~[T] { /// The internal 'unboxed' representation of a vector pub struct UnboxedVecRepr { - mut fill: uint, - mut alloc: uint, + fill: uint, + alloc: uint, data: u8 } @@ -2171,8 +2353,8 @@ pub mod raw { } pub struct SliceRepr { - mut data: *u8, - mut len: uint + data: *u8, + len: uint } /** @@ -2184,7 +2366,7 @@ pub mod raw { */ #[inline(always)] pub unsafe fn set_len(v: &mut ~[T], new_len: uint) { - let repr: **VecRepr = ::cast::transmute(v); + let repr: **mut VecRepr = ::cast::transmute(v); (**repr).unboxed.fill = new_len * sys::nonzero_size_of::(); } @@ -2368,6 +2550,7 @@ pub mod bytes { // ___________________________________________________________________________ // ITERATION TRAIT METHODS +#[cfg(stage0)] impl<'self,A> iter::BaseIter for &'self [A] { #[inline(always)] fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } @@ -2375,7 +2558,18 @@ impl<'self,A> iter::BaseIter for &'self [A] { fn size_hint(&self) -> Option { Some(self.len()) } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +impl<'self,A> iter::BaseIter for &'self [A] { + #[inline(always)] + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } + #[inline(always)] + fn size_hint(&self) -> Option { Some(self.len()) } +} + // FIXME(#4148): This should be redundant +#[cfg(stage0)] impl iter::BaseIter for ~[A] { #[inline(always)] fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } @@ -2384,6 +2578,18 @@ impl iter::BaseIter for ~[A] { } // FIXME(#4148): This should be redundant +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +impl iter::BaseIter for ~[A] { + #[inline(always)] + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } + #[inline(always)] + fn size_hint(&self) -> Option { Some(self.len()) } +} + +// FIXME(#4148): This should be redundant +#[cfg(stage0)] impl iter::BaseIter for @[A] { #[inline(always)] fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } @@ -2391,6 +2597,18 @@ impl iter::BaseIter for @[A] { fn size_hint(&self) -> Option { Some(self.len()) } } +// FIXME(#4148): This should be redundant +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +impl iter::BaseIter for @[A] { + #[inline(always)] + fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } + #[inline(always)] + fn size_hint(&self) -> Option { Some(self.len()) } +} + +#[cfg(stage0)] impl<'self,A> iter::MutableIter for &'self mut [A] { #[inline(always)] fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { @@ -2398,7 +2616,18 @@ impl<'self,A> iter::MutableIter for &'self mut [A] { } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +impl<'self,A> iter::MutableIter for &'self mut [A] { + #[inline(always)] + fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { + each_mut(*self, blk) + } +} + // FIXME(#4148): This should be redundant +#[cfg(stage0)] impl iter::MutableIter for ~[A] { #[inline(always)] fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { @@ -2406,6 +2635,16 @@ impl iter::MutableIter for ~[A] { } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +impl iter::MutableIter for ~[A] { + #[inline(always)] + fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { + each_mut(*self, blk) + } +} + // FIXME(#4148): This should be redundant impl iter::MutableIter for @mut [A] { #[inline(always)] @@ -3471,6 +3710,51 @@ mod tests { assert!(rfind_between(v, 4u, 4u, f).is_none()); } + #[test] + fn test_bsearch_elem() { + assert!(bsearch_elem([1,2,3,4,5], &5) == Some(4)); + assert!(bsearch_elem([1,2,3,4,5], &4) == Some(3)); + assert!(bsearch_elem([1,2,3,4,5], &3) == Some(2)); + assert!(bsearch_elem([1,2,3,4,5], &2) == Some(1)); + assert!(bsearch_elem([1,2,3,4,5], &1) == Some(0)); + + assert!(bsearch_elem([2,4,6,8,10], &1) == None); + assert!(bsearch_elem([2,4,6,8,10], &5) == None); + assert!(bsearch_elem([2,4,6,8,10], &4) == Some(1)); + assert!(bsearch_elem([2,4,6,8,10], &10) == Some(4)); + + assert!(bsearch_elem([2,4,6,8], &1) == None); + assert!(bsearch_elem([2,4,6,8], &5) == None); + assert!(bsearch_elem([2,4,6,8], &4) == Some(1)); + assert!(bsearch_elem([2,4,6,8], &8) == Some(3)); + + assert!(bsearch_elem([2,4,6], &1) == None); + assert!(bsearch_elem([2,4,6], &5) == None); + assert!(bsearch_elem([2,4,6], &4) == Some(1)); + assert!(bsearch_elem([2,4,6], &6) == Some(2)); + + assert!(bsearch_elem([2,4], &1) == None); + assert!(bsearch_elem([2,4], &5) == None); + assert!(bsearch_elem([2,4], &2) == Some(0)); + assert!(bsearch_elem([2,4], &4) == Some(1)); + + assert!(bsearch_elem([2], &1) == None); + assert!(bsearch_elem([2], &5) == None); + assert!(bsearch_elem([2], &2) == Some(0)); + + assert!(bsearch_elem([], &1) == None); + assert!(bsearch_elem([], &5) == None); + + assert!(bsearch_elem([1,1,1,1,1], &1) != None); + assert!(bsearch_elem([1,1,1,1,2], &1) != None); + assert!(bsearch_elem([1,1,1,2,2], &1) != None); + assert!(bsearch_elem([1,1,2,2,2], &1) != None); + assert!(bsearch_elem([1,2,2,2,2], &1) == Some(0)); + + assert!(bsearch_elem([1,2,3,4,5], &6) == None); + assert!(bsearch_elem([1,2,3,4,5], &0) == None); + } + #[test] fn reverse_and_reversed() { let mut v: ~[int] = ~[10, 20]; @@ -3581,20 +3865,26 @@ mod tests { #[test] fn test_windowed () { - assert!(~[~[1u,2u,3u],~[2u,3u,4u],~[3u,4u,5u],~[4u,5u,6u]] - == windowed (3u, ~[1u,2u,3u,4u,5u,6u])); - - assert!(~[~[1u,2u,3u,4u],~[2u,3u,4u,5u],~[3u,4u,5u,6u]] - == windowed (4u, ~[1u,2u,3u,4u,5u,6u])); + fn t(n: uint, expected: &[&[int]]) { + let mut i = 0; + for windowed(n, ~[1,2,3,4,5,6]) |v| { + assert_eq!(v, expected[i]); + i += 1; + } - assert!(~[] == windowed (7u, ~[1u,2u,3u,4u,5u,6u])); + // check that we actually iterated the right number of times + assert_eq!(i, expected.len()); + } + t(3, &[&[1,2,3],&[2,3,4],&[3,4,5],&[4,5,6]]); + t(4, &[&[1,2,3,4],&[2,3,4,5],&[3,4,5,6]]); + t(7, &[]); } #[test] #[should_fail] #[ignore(cfg(windows))] fn test_windowed_() { - let _x = windowed (0u, ~[1u,2u,3u,4u,5u,6u]); + for windowed (0u, ~[1u,2u,3u,4u,5u,6u]) |_v| {} } #[test] diff --git a/src/libfuzzer/fuzzer.rc b/src/libfuzzer/fuzzer.rc index aad48bbb8e636..46c7d4da22e4e 100644 --- a/src/libfuzzer/fuzzer.rc +++ b/src/libfuzzer/fuzzer.rc @@ -10,7 +10,7 @@ #[link(name = "fuzzer", - vers = "0.6", + vers = "0.7-pre", uuid = "d6418797-2736-4833-bd82-d3c684b7c1b0", url = "https://github.com/mozilla/rust/tree/master/src/libfuzzer")]; @@ -26,9 +26,9 @@ #[allow(deprecated_mode)]; #[allow(deprecated_pattern)]; -extern mod core(vers = "0.6"); -extern mod std(vers = "0.6"); -extern mod syntax(vers = "0.6"); +extern mod core(vers = "0.7-pre"); +extern mod std(vers = "0.7-pre"); +extern mod syntax(vers = "0.7-pre"); use core::*; use core::io::WriterUtil; diff --git a/src/librust/rust.rc b/src/librust/rust.rc index d407cf216a88e..bf35cae27ddeb 100644 --- a/src/librust/rust.rc +++ b/src/librust/rust.rc @@ -13,14 +13,14 @@ // FIXME #2238 Make run only accept source that emits an executable #[link(name = "rust", - vers = "0.6", + vers = "0.7-pre", uuid = "4a24da33-5cc8-4037-9352-2cbe9bd9d27c", url = "https://github.com/mozilla/rust/tree/master/src/rust")]; #[license = "MIT/ASL2"]; #[crate_type = "lib"]; -extern mod core(vers = "0.6"); +extern mod core(vers = "0.7-pre"); use core::run; @@ -64,11 +64,11 @@ static commands: &'static [Command<'static>] = &[ Command{ cmd: "run", action: Call(cmd_run), - usage_line: "build a executable, and run it", + usage_line: "build an executable, and run it", usage_full: UsgStr( "The run command is an shortcut for the command line \n\ - \"rustc -o ~ && ./~\".\ - \n\nUsage:\trust run " + \"rustc -o ~ && ./~ [...]\".\ + \n\nUsage:\trust run [...]" ) }, Command{ @@ -169,14 +169,14 @@ fn cmd_test(args: &[~str]) -> ValidUsage { fn cmd_run(args: &[~str]) -> ValidUsage { match args { - [filename] => { + [filename, ..prog_args] => { let exec = Path(filename).filestem().unwrap() + "~"; if run::run_program("rustc", [ filename.to_owned(), ~"-o", exec.to_owned() ]) == 0 { - run::run_program(~"./"+exec, []); + run::run_program(~"./"+exec, prog_args); } Valid } diff --git a/src/librustc/README.txt b/src/librustc/README.txt index 9ac35aa444877..487a7927d279d 100644 --- a/src/librustc/README.txt +++ b/src/librustc/README.txt @@ -75,7 +75,7 @@ The 3 central data structures: Control and information flow within the compiler: ------------------------------------------------- -- main() in driver/rustc.rs assumes control on startup. Options are +- 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 diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index fae56aac38f3c..1c99566280815 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -615,9 +615,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path, } pub fn truncated_hash_result(symbol_hasher: &hash::State) -> ~str { - unsafe { - symbol_hasher.result_str() - } + symbol_hasher.result_str() } diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index 6c485df84b484..49935eea0e13d 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -18,7 +18,7 @@ use core::os; use core::uint; use core::util; use core::vec; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; fn not_win32(os: session::os) -> bool { match os { @@ -186,7 +186,7 @@ pub fn get_install_prefix_rpath(target_triple: &str) -> Path { } pub fn minimize_rpaths(rpaths: &[Path]) -> ~[Path] { - let mut set = LinearSet::new(); + let mut set = HashSet::new(); let mut minimized = ~[]; for rpaths.each |rpath| { if set.insert(rpath.to_str()) { @@ -212,14 +212,14 @@ mod test { use driver::session; #[test] - pub fn test_rpaths_to_flags() { + fn test_rpaths_to_flags() { let flags = rpaths_to_flags(~[Path("path1"), Path("path2")]); assert!(flags == ~[~"-Wl,-rpath,path1", ~"-Wl,-rpath,path2"]); } #[test] - pub fn test_prefix_rpath() { + fn test_prefix_rpath() { let res = get_install_prefix_rpath("triple"); let d = Path(env!("CFG_PREFIX")) .push_rel(&Path("lib/rustc/triple/lib")); @@ -230,13 +230,13 @@ mod test { } #[test] - pub fn test_prefix_rpath_abs() { + fn test_prefix_rpath_abs() { let res = get_install_prefix_rpath("triple"); assert!(res.is_absolute); } #[test] - pub fn test_minimize1() { + fn test_minimize1() { let res = minimize_rpaths([Path("rpath1"), Path("rpath2"), Path("rpath1")]); @@ -244,7 +244,7 @@ mod test { } #[test] - pub fn test_minimize2() { + fn test_minimize2() { let res = minimize_rpaths(~[Path("1a"), Path("2"), Path("2"), Path("1a"), Path("4a"),Path("1a"), Path("2"), Path("3"), Path("4a"), @@ -253,7 +253,7 @@ mod test { } #[test] - pub fn test_relative_to1() { + fn test_relative_to1() { let p1 = Path("/usr/bin/rustc"); let p2 = Path("/usr/lib/mylib"); let res = get_relative_to(&p1, &p2); @@ -261,7 +261,7 @@ mod test { } #[test] - pub fn test_relative_to2() { + fn test_relative_to2() { let p1 = Path("/usr/bin/rustc"); let p2 = Path("/usr/bin/../lib/mylib"); let res = get_relative_to(&p1, &p2); @@ -269,7 +269,7 @@ mod test { } #[test] - pub fn test_relative_to3() { + fn test_relative_to3() { let p1 = Path("/usr/bin/whatever/rustc"); let p2 = Path("/usr/lib/whatever/mylib"); let res = get_relative_to(&p1, &p2); @@ -277,7 +277,7 @@ mod test { } #[test] - pub fn test_relative_to4() { + fn test_relative_to4() { let p1 = Path("/usr/bin/whatever/../rustc"); let p2 = Path("/usr/lib/whatever/mylib"); let res = get_relative_to(&p1, &p2); @@ -285,7 +285,7 @@ mod test { } #[test] - pub fn test_relative_to5() { + fn test_relative_to5() { let p1 = Path("/usr/bin/whatever/../rustc"); let p2 = Path("/usr/lib/whatever/../mylib"); let res = get_relative_to(&p1, &p2); @@ -293,7 +293,7 @@ mod test { } #[test] - pub fn test_relative_to6() { + fn test_relative_to6() { let p1 = Path("/1"); let p2 = Path("/2/3"); let res = get_relative_to(&p1, &p2); @@ -301,7 +301,7 @@ mod test { } #[test] - pub fn test_relative_to7() { + fn test_relative_to7() { let p1 = Path("/1/2"); let p2 = Path("/3"); let res = get_relative_to(&p1, &p2); @@ -309,7 +309,7 @@ mod test { } #[test] - pub fn test_relative_to8() { + fn test_relative_to8() { let p1 = Path("/home/brian/Dev/rust/build/").push_rel( &Path("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); let p2 = Path("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( @@ -324,7 +324,7 @@ mod test { #[test] #[cfg(target_os = "linux")] #[cfg(target_os = "andorid")] - pub fn test_rpath_relative() { + fn test_rpath_relative() { let o = session::os_linux; let res = get_rpath_relative_to_output(o, &Path("bin/rustc"), &Path("lib/libstd.so")); @@ -333,7 +333,7 @@ mod test { #[test] #[cfg(target_os = "freebsd")] - pub fn test_rpath_relative() { + fn test_rpath_relative() { let o = session::os_freebsd; let res = get_rpath_relative_to_output(o, &Path("bin/rustc"), &Path("lib/libstd.so")); @@ -342,7 +342,7 @@ mod test { #[test] #[cfg(target_os = "macos")] - pub fn test_rpath_relative() { + fn test_rpath_relative() { // this is why refinements would be nice let o = session::os_macos; let res = get_rpath_relative_to_output(o, @@ -352,7 +352,7 @@ mod test { } #[test] - pub fn test_get_absolute_rpath() { + fn test_get_absolute_rpath() { let res = get_absolute_rpath(&Path("lib/libstd.so")); debug!("test_get_absolute_rpath: %s vs. %s", res.to_str(), diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 5d0ba4bb911f2..a804469ac6511 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -89,7 +89,7 @@ pub fn default_configuration(sess: Session, +argv0: ~str, input: input) -> abi::X86 => (~"little",~"x86",~"32"), abi::X86_64 => (~"little",~"x86_64",~"64"), abi::Arm => (~"little",~"arm",~"32"), - abi::Mips => (~"little",~"arm",~"32") + abi::Mips => (~"big",~"mips",~"32") }; return ~[ // Target bindings. @@ -151,7 +151,7 @@ pub fn parse_input(sess: Session, +cfg: ast::crate_cfg, input: input) -> @ast::crate { match input { file_input(ref file) => { - parse::parse_crate_from_file(&(*file), cfg, sess.parse_sess) + parse::parse_crate_from_file_using_tts(&(*file), cfg, sess.parse_sess) } str_input(ref src) => { // FIXME (#2319): Don't really want to box the source string @@ -308,7 +308,7 @@ pub fn compile_rest(sess: Session, cfg: ast::crate_cfg, }; - // NOTE: Android hack + // NB: Android hack if sess.targ_cfg.arch == abi::Arm && (sess.opts.output_type == link::output_type_object || sess.opts.output_type == link::output_type_exe) { @@ -698,7 +698,8 @@ pub fn build_session_(sopts: @session::options, parse_sess: p_s, codemap: cm, // For a library crate, this is always none - main_fn: @mut None, + entry_fn: @mut None, + entry_type: @mut None, span_diagnostic: span_diagnostic_handler, filesearch: filesearch, building_library: @mut false, @@ -875,7 +876,7 @@ pub fn list_metadata(sess: Session, path: &Path, out: @io::Writer) { } #[cfg(test)] -pub mod test { +mod test { use core::prelude::*; use driver::driver::{build_configuration, build_session}; @@ -889,7 +890,7 @@ pub mod test { // When the user supplies --test we should implicitly supply --cfg test #[test] - pub fn test_switch_implies_cfg_test() { + fn test_switch_implies_cfg_test() { let matches = &match getopts(~[~"--test"], optgroups()) { Ok(copy m) => m, @@ -906,7 +907,7 @@ pub mod test { // When the user supplies --test and --cfg test, don't implicitly add // another --cfg test #[test] - pub fn test_switch_implies_cfg_test_unless_cfg_test() { + fn test_switch_implies_cfg_test_unless_cfg_test() { let matches = &match getopts(~[~"--test", ~"--cfg=test"], optgroups()) { Ok(copy m) => m, diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 95740e0f83750..aee5e01e09108 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -144,6 +144,16 @@ pub struct crate_metadata { data: ~[u8] } +// The type of entry function, so +// users can have their own entry +// functions that don't start a +// scheduler +#[deriving(Eq)] +pub enum EntryFnType { + EntryMain, + EntryStart +} + pub struct Session_ { targ_cfg: @config, opts: @options, @@ -151,7 +161,8 @@ pub struct Session_ { parse_sess: @mut ParseSess, codemap: @codemap::CodeMap, // For a library crate, this is always none - main_fn: @mut Option<(node_id, codemap::span)>, + entry_fn: @mut Option<(node_id, codemap::span)>, + entry_type: @mut Option, span_diagnostic: @diagnostic::span_handler, filesearch: @filesearch::FileSearch, building_library: @mut bool, @@ -343,14 +354,14 @@ pub fn sess_os_to_meta_os(os: os) -> metadata::loader::os { } #[cfg(test)] -pub mod test { +mod test { use driver::session::{bin_crate, building_library, lib_crate}; use driver::session::{unknown_crate}; use syntax::ast; use syntax::codemap; - pub fn make_crate_type_attr(+t: ~str) -> ast::attribute { + fn make_crate_type_attr(+t: ~str) -> ast::attribute { codemap::respan(codemap::dummy_sp(), ast::attribute_ { style: ast::attr_outer, value: @codemap::respan(codemap::dummy_sp(), @@ -362,7 +373,7 @@ pub mod test { }) } - pub fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate { + fn make_crate(with_bin: bool, with_lib: bool) -> @ast::crate { let mut attrs = ~[]; if with_bin { attrs += ~[make_crate_type_attr(~"bin")]; } if with_lib { attrs += ~[make_crate_type_attr(~"lib")]; } @@ -374,43 +385,43 @@ pub mod test { } #[test] - pub fn bin_crate_type_attr_results_in_bin_output() { + fn bin_crate_type_attr_results_in_bin_output() { let crate = make_crate(true, false); assert!(!building_library(unknown_crate, crate, false)); } #[test] - pub fn lib_crate_type_attr_results_in_lib_output() { + fn lib_crate_type_attr_results_in_lib_output() { let crate = make_crate(false, true); assert!(building_library(unknown_crate, crate, false)); } #[test] - pub fn bin_option_overrides_lib_crate_type() { + fn bin_option_overrides_lib_crate_type() { let crate = make_crate(false, true); assert!(!building_library(bin_crate, crate, false)); } #[test] - pub fn lib_option_overrides_bin_crate_type() { + fn lib_option_overrides_bin_crate_type() { let crate = make_crate(true, false); assert!(building_library(lib_crate, crate, false)); } #[test] - pub fn bin_crate_type_is_default() { + fn bin_crate_type_is_default() { let crate = make_crate(false, false); assert!(!building_library(unknown_crate, crate, false)); } #[test] - pub fn test_option_overrides_lib_crate_type() { + fn test_option_overrides_lib_crate_type() { let crate = make_crate(false, true); assert!(!building_library(unknown_crate, crate, true)); } #[test] - pub fn test_option_does_not_override_requested_lib_type() { + fn test_option_does_not_override_requested_lib_type() { let crate = make_crate(false, false); assert!(building_library(lib_crate, crate, true)); } diff --git a/src/librustc/front/core_inject.rs b/src/librustc/front/core_inject.rs index 6e134d25ff2cf..132023beeb400 100644 --- a/src/librustc/front/core_inject.rs +++ b/src/librustc/front/core_inject.rs @@ -19,7 +19,7 @@ use syntax::codemap; use syntax::codemap::dummy_sp; use syntax::fold; -static CORE_VERSION: &'static str = "0.6"; +static CORE_VERSION: &'static str = "0.7-pre"; pub fn maybe_inject_libcore_ref(sess: Session, crate: @ast::crate) -> @ast::crate { @@ -77,7 +77,7 @@ fn inject_libcore_ref(sess: Session, fold_mod: |module, fld| { let n2 = sess.next_node_id(); - let prelude_path = @ast::path { + let prelude_path = @ast::Path { span: dummy_sp(), global: false, idents: ~[ diff --git a/src/librustc/front/intrinsic.rs b/src/librustc/front/intrinsic.rs index 7d5177a6dfb5d..dcf300bd31da6 100644 --- a/src/librustc/front/intrinsic.rs +++ b/src/librustc/front/intrinsic.rs @@ -28,6 +28,8 @@ pub mod intrinsic { // Remaining fields not listed } + pub enum Opaque { } + pub trait TyVisitor { fn visit_bot(&self) -> bool; fn visit_nil(&self) -> bool; @@ -91,17 +93,19 @@ pub mod intrinsic { sz: uint, align: uint) -> bool; fn visit_enter_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) -> bool; fn visit_enter_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool; - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool; + fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool; fn visit_leave_enum_variant(&self, variant: uint, disr_val: int, n_fields: uint, name: &str) -> bool; fn visit_leave_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) -> bool; fn visit_enter_fn(&self, purity: uint, proto: uint, diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index dbedeeaa5cc80..8d3e9d5e89fb0 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -265,7 +265,7 @@ mod __test { */ fn mk_std(cx: &TestCtxt) -> @ast::view_item { - let vers = ast::lit_str(@~"0.6"); + let vers = ast::lit_str(@~"0.7-pre"); let vers = nospan(vers); let mi = ast::meta_name_value(@~"vers", vers); let mi = nospan(mi); @@ -336,16 +336,16 @@ fn nospan(t: T) -> codemap::spanned { codemap::spanned { node: t, span: dummy_sp() } } -fn path_node(+ids: ~[ast::ident]) -> @ast::path { - @ast::path { span: dummy_sp(), +fn path_node(+ids: ~[ast::ident]) -> @ast::Path { + @ast::Path { span: dummy_sp(), global: false, idents: ids, rp: None, types: ~[] } } -fn path_node_global(+ids: ~[ast::ident]) -> @ast::path { - @ast::path { span: dummy_sp(), +fn path_node_global(+ids: ~[ast::ident]) -> @ast::Path { + @ast::Path { span: dummy_sp(), global: true, idents: ids, rp: None, diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 34678d1803c17..b6d3fce7e7546 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -10,7 +10,7 @@ use core::prelude::*; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::libc::c_uint; use core::option; use core::ptr; @@ -1467,8 +1467,8 @@ pub fn SetLinkage(Global: ValueRef, Link: Linkage) { /* Memory-managed object interface to type handles. */ pub struct TypeNames { - type_names: @mut LinearMap, - named_types: @mut LinearMap<@str, TypeRef> + type_names: @mut HashMap, + named_types: @mut HashMap<@str, TypeRef> } pub fn associate_type(tn: @TypeNames, s: @str, t: TypeRef) { @@ -1486,8 +1486,8 @@ pub fn name_has_type(tn: @TypeNames, s: @str) -> Option { pub fn mk_type_names() -> @TypeNames { @TypeNames { - type_names: @mut LinearMap::new(), - named_types: @mut LinearMap::new() + type_names: @mut HashMap::new(), + named_types: @mut HashMap::new() } } diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 920631a55b4ec..e2672338a8a0b 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -74,7 +74,9 @@ pub static tag_crate_dep_vers: uint = 0x2cu; pub static tag_mod_impl: uint = 0x30u; pub static tag_item_trait_method: uint = 0x31u; -pub static tag_impl_trait: uint = 0x32u; + +pub static tag_item_trait_ref: uint = 0x32u; +pub static tag_item_super_trait_ref: uint = 0x33u; // discriminator value for variants pub static tag_disr_val: uint = 0x34u; @@ -102,6 +104,7 @@ pub static tag_item_dtor: uint = 0x49u; pub static tag_item_trait_method_self_ty: uint = 0x4b; pub static tag_item_trait_method_self_ty_region: uint = 0x4c; + // Reexports are found within module tags. Each reexport contains def_ids // and names. pub static tag_items_data_item_reexport: uint = 0x4d; @@ -124,7 +127,7 @@ pub enum astencode_tag { // Reserves 0x50 -- 0x6f tag_table_node_type_subst = 0x58, tag_table_freevars = 0x59, tag_table_tcache = 0x5a, - tag_table_param_bounds = 0x5b, + tag_table_param_defs = 0x5b, tag_table_inferred_modes = 0x5c, tag_table_mutbl = 0x5d, tag_table_last_use = 0x5e, @@ -159,6 +162,10 @@ pub static tag_items_data_item_visibility: uint = 0x78; pub static tag_link_args: uint = 0x79; pub static tag_link_args_arg: uint = 0x7a; +pub static tag_item_method_tps: uint = 0x7b; +pub static tag_item_method_fty: uint = 0x7c; +pub static tag_item_method_transformed_self_ty: uint = 0x7d; + pub struct LinkMeta { name: @str, vers: @str, diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 086c6a33b3ec8..8609434e6df29 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -18,7 +18,7 @@ use metadata::decoder; use metadata::filesearch::FileSearch; use metadata::loader; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::vec; use syntax::attr; use syntax::codemap::{span, dummy_sp}; @@ -302,7 +302,7 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { debug!("resolving deps of external crate"); // The map from crate numbers in the crate we're resolving to local crate // numbers - let mut cnum_map = LinearMap::new(); + let mut cnum_map = HashMap::new(); for decoder::get_crate_deps(e.intr, cdata).each |dep| { let extrn_cnum = dep.cnum; let cname = dep.name; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 16b896f11d6a4..f7de281194f39 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -111,12 +111,24 @@ pub fn get_impls_for_mod(cstore: @mut cstore::CStore, def: ast::def_id, } } -pub fn get_trait_methods(tcx: ty::ctxt, - def: ast::def_id) - -> @~[ty::method] { - let cstore = tcx.cstore; +pub fn get_method(tcx: ty::ctxt, + def: ast::def_id) -> ty::method +{ + let cdata = cstore::get_crate_data(tcx.cstore, def.crate); + decoder::get_method(tcx.cstore.intr, cdata, def.node, tcx) +} + +pub fn get_method_name_and_self_ty(cstore: @mut cstore::CStore, + def: ast::def_id) -> (ast::ident, ast::self_ty_) +{ + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_method_name_and_self_ty(cstore.intr, cdata, def.node) +} + +pub fn get_trait_method_def_ids(cstore: @mut cstore::CStore, + def: ast::def_id) -> ~[ast::def_id] { let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::get_trait_methods(cstore.intr, cdata, def.node, tcx) + decoder::get_trait_method_def_ids(cdata, def.node) } pub fn get_provided_trait_methods(tcx: ty::ctxt, @@ -127,19 +139,12 @@ pub fn get_provided_trait_methods(tcx: ty::ctxt, decoder::get_provided_trait_methods(cstore.intr, cdata, def.node, tcx) } -pub fn get_supertraits(tcx: ty::ctxt, def: ast::def_id) -> ~[ty::t] { +pub fn get_supertraits(tcx: ty::ctxt, def: ast::def_id) -> ~[@ty::TraitRef] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); decoder::get_supertraits(cdata, def.node, tcx) } -pub fn get_method_names_if_trait(cstore: @mut cstore::CStore, - def: ast::def_id) - -> Option<~[(ast::ident, ast::self_ty_)]> { - let cdata = cstore::get_crate_data(cstore, def.crate); - return decoder::get_method_names_if_trait(cstore.intr, cdata, def.node); -} - pub fn get_type_name_if_impl(cstore: @mut cstore::CStore, def: ast::def_id) -> Option { let cdata = cstore::get_crate_data(cstore, def.crate); @@ -175,6 +180,12 @@ pub fn get_type(tcx: ty::ctxt, decoder::get_type(cdata, def.node, tcx) } +pub fn get_trait_def(tcx: ty::ctxt, def: ast::def_id) -> ty::TraitDef { + let cstore = tcx.cstore; + let cdata = cstore::get_crate_data(cstore, def.crate); + decoder::get_trait_def(cdata, def.node, tcx) +} + pub fn get_region_param(cstore: @mut metadata::cstore::CStore, def: ast::def_id) -> Option { let cdata = cstore::get_crate_data(cstore, def.crate); @@ -199,8 +210,8 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::def_id, debug!("got field data %?", the_field); let ty = decoder::item_type(def, the_field, tcx, cdata); ty::ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics {type_param_defs: @~[], + region_param: None}, ty: ty } } @@ -208,7 +219,8 @@ 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::t] { +pub fn get_impl_traits(tcx: ty::ctxt, + def: ast::def_id) -> ~[@ty::TraitRef] { let cstore = tcx.cstore; let cdata = cstore::get_crate_data(cstore, def.crate); decoder::get_impl_traits(cdata, def.node, tcx) diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index c836538e1e6c8..d738c3e774794 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -17,7 +17,7 @@ use core::prelude::*; use metadata::cstore; use metadata::decoder; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::vec; use std; use syntax::ast; @@ -27,7 +27,7 @@ use syntax::parse::token::ident_interner; // local crate numbers (as generated during this session). Each external // crate may refer to types in other external crates, and each has their // own crate numbers. -pub type cnum_map = @mut LinearMap; +pub type cnum_map = @mut HashMap; pub struct crate_metadata { name: @~str, @@ -37,7 +37,7 @@ pub struct crate_metadata { } pub struct CStore { - priv metas: LinearMap , + priv metas: HashMap , priv extern_mod_crate_map: extern_mod_crate_map, priv used_crate_files: ~[Path], priv used_libraries: ~[~str], @@ -46,12 +46,12 @@ pub struct CStore { } // Map from node_id's of local extern mod statements to crate numbers -type extern_mod_crate_map = LinearMap; +type extern_mod_crate_map = HashMap; pub fn mk_cstore(intr: @ident_interner) -> CStore { return CStore { - metas: LinearMap::new(), - extern_mod_crate_map: LinearMap::new(), + metas: HashMap::new(), + extern_mod_crate_map: HashMap::new(), used_crate_files: ~[], used_libraries: ~[], used_link_args: ~[], @@ -86,7 +86,7 @@ pub fn have_crate_data(cstore: &CStore, cnum: ast::crate_num) -> bool { pub fn iter_crate_data(cstore: &CStore, i: &fn(ast::crate_num, @crate_metadata)) { - for cstore.metas.each |&(&k, &v)| { + for cstore.metas.each |&k, &v| { i(k, v); } } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index dcea22b09d6d6..472b455b73531 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -19,7 +19,9 @@ use metadata::csearch::{ProvidedTraitMethodInfo, StaticMethodInfo}; use metadata::csearch; use metadata::cstore; use metadata::decoder; -use metadata::tydecode::{parse_ty_data, parse_def_id, parse_bounds_data}; +use metadata::tydecode::{parse_ty_data, parse_def_id, + parse_type_param_def_data, + parse_bare_fn_ty_data, parse_trait_ref_data}; use middle::{ty, resolve}; use core::hash::HashUtil; @@ -229,6 +231,22 @@ fn doc_type(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::t { |_, did| translate_def_id(cdata, did)) } +fn doc_method_fty(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::BareFnTy { + let tp = reader::get_doc(doc, tag_item_method_fty); + parse_bare_fn_ty_data(tp.data, cdata.cnum, tp.start, tcx, + |_, did| translate_def_id(cdata, did)) +} + +fn doc_transformed_self_ty(doc: ebml::Doc, + tcx: ty::ctxt, + cdata: cmd) -> Option +{ + do reader::maybe_get_doc(doc, tag_item_method_transformed_self_ty).map |tp| { + parse_ty_data(tp.data, cdata.cnum, tp.start, tcx, + |_, did| translate_def_id(cdata, did)) + } +} + pub fn item_type(item_id: ast::def_id, item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::t { let t = doc_type(item, tcx, cdata); @@ -239,20 +257,24 @@ pub fn item_type(item_id: ast::def_id, item: ebml::Doc, } } -fn item_impl_traits(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ~[ty::t] { - let mut results = ~[]; - for reader::tagged_docs(item, tag_impl_trait) |ity| { - results.push(doc_type(ity, tcx, cdata)); - }; - results +fn doc_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::TraitRef { + parse_trait_ref_data(doc.data, cdata.cnum, doc.start, tcx, + |_, did| translate_def_id(cdata, did)) +} + +fn item_trait_ref(doc: ebml::Doc, tcx: ty::ctxt, cdata: cmd) -> ty::TraitRef { + let tp = reader::get_doc(doc, tag_item_trait_ref); + doc_trait_ref(tp, tcx, cdata) } -fn item_ty_param_bounds(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) - -> @~[ty::param_bounds] { +fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, + tag: uint) + -> @~[ty::TypeParameterDef] { let mut bounds = ~[]; - for reader::tagged_docs(item, tag_items_data_item_ty_param_bounds) |p| { - let bd = parse_bounds_data(p.data, p.start, cdata.cnum, tcx, - |_, did| translate_def_id(cdata, did)); + for reader::tagged_docs(item, tag) |p| { + let bd = parse_type_param_def_data( + p.data, p.start, cdata.cnum, tcx, + |_, did| translate_def_id(cdata, did)); bounds.push(bd); } @bounds @@ -338,7 +360,8 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::crate_num) let enum_did = item_reqd_and_translated_parent_item(cnum, item); dl_def(ast::def_variant(enum_did, did)) } - Trait | Enum => dl_def(ast::def_ty(did)), + Trait => dl_def(ast::def_trait(did)), + Enum => dl_def(ast::def_ty(did)), Impl => dl_impl(did), PublicField | PrivateField | InheritedField => dl_field, } @@ -352,19 +375,34 @@ pub fn lookup_def(cnum: ast::crate_num, data: @~[u8], did_: ast::def_id) -> return def_like_to_def(item_to_def_like(item, did, cnum)); } +pub fn get_trait_def(cdata: cmd, + item_id: ast::node_id, + tcx: ty::ctxt) -> ty::TraitDef +{ + let item_doc = lookup_item(item_id, cdata.data); + let tp_defs = item_ty_param_defs(item_doc, tcx, cdata, + tag_items_data_item_ty_param_bounds); + let rp = item_ty_region_param(item_doc); + ty::TraitDef { + generics: ty::Generics {type_param_defs: tp_defs, + region_param: rp}, + trait_ref: @item_trait_ref(item_doc, tcx, cdata) + } +} + pub fn get_type(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) -> ty::ty_param_bounds_and_ty { let item = lookup_item(id, cdata.data); let t = item_type(ast::def_id { crate: cdata.cnum, node: id }, item, tcx, cdata); - let tp_bounds = if family_has_type_params(item_family(item)) { - item_ty_param_bounds(item, tcx, cdata) + let tp_defs = if family_has_type_params(item_family(item)) { + item_ty_param_defs(item, tcx, cdata, tag_items_data_item_ty_param_bounds) } else { @~[] }; let rp = item_ty_region_param(item); ty::ty_param_bounds_and_ty { - bounds: tp_bounds, - region_param: rp, + generics: ty::Generics {type_param_defs: tp_defs, + region_param: rp}, ty: t } } @@ -380,9 +418,19 @@ 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, id: ast::node_id, tcx: ty::ctxt) - -> ~[ty::t] { - item_impl_traits(lookup_item(id, cdata.data), tcx, cdata) +pub fn get_impl_traits(cdata: cmd, + id: ast::node_id, + tcx: ty::ctxt) -> ~[@ty::TraitRef] +{ + let item_doc = lookup_item(id, cdata.data); + let mut results = ~[]; + 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); + }; + results } pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, @@ -690,36 +738,52 @@ pub fn get_impls_for_mod(intr: @ident_interner, @result } -/* Works for both classes and traits */ -pub fn get_trait_methods(intr: @ident_interner, cdata: cmd, id: ast::node_id, - tcx: ty::ctxt) -> @~[ty::method] { +pub fn get_method_name_and_self_ty( + intr: @ident_interner, + cdata: cmd, + id: ast::node_id) -> (ast::ident, ast::self_ty_) +{ + let method_doc = lookup_item(id, cdata.data); + let name = item_name(intr, method_doc); + let self_ty = get_self_ty(method_doc); + (name, self_ty) +} + +pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, + tcx: ty::ctxt) -> ty::method +{ + let method_doc = lookup_item(id, cdata.data); + let def_id = item_def_id(method_doc, cdata); + let name = item_name(intr, method_doc); + let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata, + tag_item_method_tps); + let transformed_self_ty = doc_transformed_self_ty(method_doc, tcx, cdata); + let fty = doc_method_fty(method_doc, tcx, cdata); + let vis = item_visibility(method_doc); + let self_ty = get_self_ty(method_doc); + ty::method { + ident: name, + generics: ty::Generics { + type_param_defs: type_param_defs, + region_param: None + }, + transformed_self_ty: transformed_self_ty, + fty: fty, + self_ty: self_ty, + vis: vis, + def_id: def_id + } +} + +pub fn get_trait_method_def_ids(cdata: cmd, + id: ast::node_id) -> ~[ast::def_id] { let data = cdata.data; let item = lookup_item(id, data); let mut result = ~[]; for reader::tagged_docs(item, tag_item_trait_method) |mth| { - let bounds = item_ty_param_bounds(mth, tcx, cdata); - let name = item_name(intr, mth); - let ty = doc_type(mth, tcx, cdata); - let def_id = item_def_id(mth, cdata); - let fty = match ty::get(ty).sty { - ty::ty_bare_fn(ref f) => copy *f, - _ => { - tcx.diag.handler().bug( - ~"get_trait_methods: id has non-function type"); - } - }; - let self_ty = get_self_ty(mth); - result.push(ty::method { - ident: name, - tps: bounds, - fty: fty, - self_ty: self_ty, - vis: ast::public, - def_id: def_id - }); + result.push(item_def_id(mth, cdata)); } - debug!("get_trait_methods: }"); - @result + result } pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, @@ -734,7 +798,9 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, let did = item_def_id(mth, cdata); - let bounds = item_ty_param_bounds(mth, tcx, cdata); + let type_param_defs = + item_ty_param_defs(mth, tcx, cdata, + tag_items_data_item_ty_param_bounds); let name = item_name(intr, mth); let ty = doc_type(mth, tcx, cdata); @@ -746,10 +812,15 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, } }; + let transformed_self_ty = doc_transformed_self_ty(mth, tcx, cdata); let self_ty = get_self_ty(mth); let ty_method = ty::method { ident: name, - tps: bounds, + generics: ty::Generics { + type_param_defs: type_param_defs, + region_param: None + }, + transformed_self_ty: transformed_self_ty, fty: fty, self_ty: self_ty, vis: ast::public, @@ -768,35 +839,15 @@ pub fn get_provided_trait_methods(intr: @ident_interner, cdata: cmd, /// Returns the supertraits of the given trait. pub fn get_supertraits(cdata: cmd, id: ast::node_id, tcx: ty::ctxt) - -> ~[ty::t] { + -> ~[@ty::TraitRef] { let mut results = ~[]; let item_doc = lookup_item(id, cdata.data); - for reader::tagged_docs(item_doc, tag_impl_trait) |trait_doc| { - results.push(doc_type(trait_doc, tcx, cdata)); + for reader::tagged_docs(item_doc, tag_item_super_trait_ref) |trait_doc| { + results.push(@doc_trait_ref(trait_doc, tcx, cdata)); } return results; } -// If the item in question is a trait, returns its set of methods and -// their self types. Otherwise, returns none. This overlaps in an -// annoying way with get_trait_methods. -pub fn get_method_names_if_trait(intr: @ident_interner, cdata: cmd, - node_id: ast::node_id) - -> Option<~[(ast::ident, ast::self_ty_)]> { - - let item = lookup_item(node_id, cdata.data); - if item_family(item) != Trait { - return None; - } - - let mut resulting_methods = ~[]; - for reader::tagged_docs(item, tag_item_trait_method) |method| { - resulting_methods.push( - (item_name(intr, method), get_self_ty(method))); - } - return Some(resulting_methods); -} - pub fn get_type_name_if_impl(intr: @ident_interner, cdata: cmd, node_id: ast::node_id) -> Option { @@ -821,8 +872,8 @@ pub fn get_static_methods_if_impl(intr: @ident_interner, return None; } - // If this impl has a trait ref, don't consider it. - for reader::tagged_docs(item, tag_impl_trait) |_doc| { + // If this impl implements a trait, don't consider it. + for reader::tagged_docs(item, tag_item_trait_ref) |_doc| { return None; } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 340ad443b5888..cc86d50af4288 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -25,7 +25,7 @@ use util::ppaux::ty_to_str; use core::flate; use core::hash::HashUtil; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::int; use core::io::{Writer, WriterUtil}; use core::io; @@ -50,7 +50,7 @@ use syntax; use writer = std::ebml::writer; // used by astencode: -type abbrev_map = @mut LinearMap; +type abbrev_map = @mut HashMap; pub type encode_inlined_item = @fn(ecx: @EncodeContext, ebml_w: writer::Encoder, @@ -62,8 +62,8 @@ pub struct EncodeParams { tcx: ty::ctxt, reachable: reachable::map, reexports2: middle::resolve::ExportMap2, - item_symbols: @mut LinearMap, - discrim_symbols: @mut LinearMap, + item_symbols: @mut HashMap, + discrim_symbols: @mut HashMap, link_meta: LinkMeta, cstore: @mut cstore::CStore, encode_inlined_item: encode_inlined_item @@ -89,8 +89,8 @@ pub struct EncodeContext { stats: @mut Stats, reachable: reachable::map, reexports2: middle::resolve::ExportMap2, - item_symbols: @mut LinearMap, - discrim_symbols: @mut LinearMap, + item_symbols: @mut HashMap, + discrim_symbols: @mut HashMap, link_meta: LinkMeta, cstore: @mut cstore::CStore, encode_inlined_item: encode_inlined_item, @@ -153,14 +153,23 @@ fn add_to_index(ecx: @EncodeContext, ebml_w: writer::Encoder, path: &[ident], }); } -fn encode_trait_ref(ebml_w: writer::Encoder, ecx: @EncodeContext, - t: @trait_ref) { - ebml_w.start_tag(tag_impl_trait); - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, t.ref_id)); +fn encode_trait_ref(ebml_w: writer::Encoder, + ecx: @EncodeContext, + trait_ref: &ty::TraitRef, + tag: uint) +{ + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + + ebml_w.start_tag(tag); + tyencode::enc_trait_ref(ebml_w.writer, ty_str_ctxt, trait_ref); ebml_w.end_tag(); } - // Item info table encoding fn encode_family(ebml_w: writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); @@ -170,8 +179,10 @@ fn encode_family(ebml_w: writer::Encoder, c: char) { pub fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) } -fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext, - params: @~[ty::param_bounds]) { +fn encode_ty_type_param_defs(ebml_w: writer::Encoder, + ecx: @EncodeContext, + params: @~[ty::TypeParameterDef], + tag: uint) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, @@ -179,8 +190,8 @@ fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext, reachable: |a| reachable(ecx, a), abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; for params.each |param| { - ebml_w.start_tag(tag_items_data_item_ty_param_bounds); - tyencode::enc_bounds(ebml_w.writer, ty_str_ctxt, *param); + ebml_w.start_tag(tag); + tyencode::enc_type_param_def(ebml_w.writer, ty_str_ctxt, param); ebml_w.end_tag(); } } @@ -188,9 +199,10 @@ fn encode_ty_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext, fn encode_type_param_bounds(ebml_w: writer::Encoder, ecx: @EncodeContext, params: &OptVec) { - let ty_param_bounds = - @params.map_to_vec(|param| *ecx.tcx.ty_param_bounds.get(¶m.id)); - encode_ty_type_param_bounds(ebml_w, ecx, ty_param_bounds); + let ty_param_defs = + @params.map_to_vec(|param| *ecx.tcx.ty_param_defs.get(¶m.id)); + encode_ty_type_param_defs(ebml_w, ecx, ty_param_defs, + tag_items_data_item_ty_param_bounds); } @@ -227,6 +239,34 @@ fn encode_type(ecx: @EncodeContext, ebml_w: writer::Encoder, typ: ty::t) { ebml_w.end_tag(); } +fn encode_transformed_self_ty(ecx: @EncodeContext, + ebml_w: writer::Encoder, + opt_typ: Option) +{ + for opt_typ.each |&typ| { + ebml_w.start_tag(tag_item_method_transformed_self_ty); + write_type(ecx, ebml_w, typ); + ebml_w.end_tag(); + } +} + +fn encode_method_fty(ecx: @EncodeContext, + ebml_w: writer::Encoder, + typ: &ty::BareFnTy) +{ + ebml_w.start_tag(tag_item_method_fty); + + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + tyencode::enc_bare_fn_ty(ebml_w.writer, ty_str_ctxt, typ); + + ebml_w.end_tag(); +} + fn encode_symbol(ecx: @EncodeContext, ebml_w: writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); match ecx.item_symbols.find(&id) { @@ -245,7 +285,7 @@ fn encode_symbol(ecx: @EncodeContext, ebml_w: writer::Encoder, id: node_id) { fn encode_discriminant(ecx: @EncodeContext, ebml_w: writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); - ebml_w.writer.write(str::to_bytes(*ecx.discrim_symbols.get(&id))); + ebml_w.writer.write(str::to_bytes(**ecx.discrim_symbols.get(&id))); ebml_w.end_tag(); } @@ -542,13 +582,27 @@ fn encode_info_for_struct_ctor(ecx: @EncodeContext, ebml_w.end_tag(); } +fn encode_method_ty_fields(ecx: @EncodeContext, + ebml_w: writer::Encoder, + method_ty: &ty::method) +{ + encode_def_id(ebml_w, method_ty.def_id); + encode_name(ecx, ebml_w, method_ty.ident); + encode_ty_type_param_defs(ebml_w, ecx, + method_ty.generics.type_param_defs, + tag_item_method_tps); + encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); + encode_method_fty(ecx, ebml_w, &method_ty.fty); + encode_visibility(ebml_w, method_ty.vis); + encode_self_type(ebml_w, method_ty.self_ty); +} + fn encode_info_for_method(ecx: @EncodeContext, ebml_w: writer::Encoder, impl_path: &[ast_map::path_elt], should_inline: bool, parent_id: node_id, m: @method, - parent_visibility: ast::visibility, owner_generics: &ast::Generics, method_generics: &ast::Generics) { debug!("encode_info_for_method: %d %s %u %u", m.id, @@ -556,7 +610,10 @@ fn encode_info_for_method(ecx: @EncodeContext, owner_generics.ty_params.len(), method_generics.ty_params.len()); ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(m.id)); + + let method_def_id = local_def(m.id); + let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); + encode_method_ty_fields(ecx, ebml_w, method_ty); match m.self_ty.node { ast::sty_static => { @@ -572,16 +629,7 @@ fn encode_info_for_method(ecx: @EncodeContext, encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); - encode_name(ecx, ebml_w, m.ident); encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); - encode_self_type(ebml_w, m.self_ty.node); - - // Combine parent visibility and this visibility. - let visibility = match m.vis { - ast::inherited => parent_visibility, - vis => vis, - }; - encode_visibility(ebml_w, visibility); if len > 0u || should_inline { (ecx.encode_inlined_item)( @@ -590,6 +638,7 @@ fn encode_info_for_method(ecx: @EncodeContext, } else { encode_symbol(ecx, ebml_w, m.id); } + ebml_w.end_tag(); } @@ -833,8 +882,9 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, ebml_w.writer.write(str::to_bytes(def_to_str(method_def_id))); ebml_w.end_tag(); } - for opt_trait.each |associated_trait| { - encode_trait_ref(ebml_w, ecx, *associated_trait); + for opt_trait.each |ast_trait_ref| { + let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); + encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); ebml_w.end_tag(); @@ -843,17 +893,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, let mut impl_path = vec::append(~[], path); impl_path += ~[ast_map::path_name(item.ident)]; - // If there is a trait reference, treat the methods as always public. - // This is to work around some incorrect behavior in privacy checking: - // when the method belongs to a trait, it should acquire the privacy - // from the trait, not the impl. Forcing the visibility to be public - // makes things sorta work. - let parent_visibility = if opt_trait.is_some() { - ast::public - } else { - item.vis - }; - for methods.each |m| { index.push(entry {val: m.id, pos: ebml_w.writer.tell()}); encode_info_for_method(ecx, @@ -862,113 +901,96 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: writer::Encoder, should_inline(m.attrs), item.id, *m, - parent_visibility, generics, &m.generics); } } - item_trait(ref generics, ref traits, ref ms) => { - let mut provided_methods = ~[]; - + item_trait(ref generics, ref super_traits, ref ms) => { add_to_index(); ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(item.id)); encode_family(ebml_w, 'I'); encode_region_param(ecx, ebml_w, item); encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + let trait_def = ty::lookup_trait_def(tcx, local_def(item.id)); + encode_trait_ref(ebml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); encode_name(ecx, ebml_w, item.ident); encode_attributes(ebml_w, item.attrs); - let mut i = 0u; - for vec::each(*ty::trait_methods(tcx, local_def(item.id))) |mty| { - match (*ms)[i] { - required(ref ty_m) => { - ebml_w.start_tag(tag_item_trait_method); - encode_def_id(ebml_w, local_def((*ty_m).id)); - encode_name(ecx, ebml_w, mty.ident); - encode_type_param_bounds(ebml_w, ecx, - &ty_m.generics.ty_params); - encode_type(ecx, ebml_w, - ty::mk_bare_fn(tcx, copy mty.fty)); - encode_family(ebml_w, purity_fn_family(mty.fty.purity)); - encode_self_type(ebml_w, mty.self_ty); - encode_method_sort(ebml_w, 'r'); - encode_visibility(ebml_w, ast::public); - ebml_w.end_tag(); - } - provided(m) => { - provided_methods.push(m); - - ebml_w.start_tag(tag_item_trait_method); - encode_def_id(ebml_w, local_def(m.id)); - encode_name(ecx, ebml_w, mty.ident); - encode_type_param_bounds(ebml_w, ecx, - &m.generics.ty_params); - encode_type(ecx, ebml_w, - ty::mk_bare_fn(tcx, copy mty.fty)); - encode_family(ebml_w, purity_fn_family(mty.fty.purity)); - encode_self_type(ebml_w, mty.self_ty); - encode_method_sort(ebml_w, 'p'); - encode_visibility(ebml_w, m.vis); - ebml_w.end_tag(); - } - } - i += 1; + for ty::trait_method_def_ids(tcx, local_def(item.id)).each |&method_def_id| { + ebml_w.start_tag(tag_item_trait_method); + encode_def_id(ebml_w, method_def_id); + ebml_w.end_tag(); } encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - for traits.each |associated_trait| { - encode_trait_ref(ebml_w, ecx, *associated_trait) + for super_traits.each |ast_trait_ref| { + let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); + encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref); } - ebml_w.end_tag(); - // Now, output all of the static methods as items. Note that for the - // method info, we output static methods with type signatures as - // written. Here, we output the *real* type signatures. I feel like - // maybe we should only ever handle the real type signatures. - for ms.each |m| { - let ty_m = ast_util::trait_method_to_ty_method(m); - if ty_m.self_ty.node != ast::sty_static { loop; } + // Now output the method info for each method. + for ty::trait_method_def_ids(tcx, local_def(item.id)).eachi |i, &method_def_id| { + assert!(method_def_id.crate == ast::local_crate); - index.push(entry { val: ty_m.id, pos: ebml_w.writer.tell() }); + let method_ty: @ty::method = ty::method(tcx, method_def_id); + + index.push(entry {val: method_def_id.node, pos: ebml_w.writer.tell()}); ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(ty_m.id)); + + encode_method_ty_fields(ecx, ebml_w, method_ty); + encode_parent_item(ebml_w, local_def(item.id)); - encode_name(ecx, ebml_w, ty_m.ident); - encode_family(ebml_w, - purity_static_method_family(ty_m.purity)); - let polyty = ecx.tcx.tcache.get(&local_def(ty_m.id)); - encode_ty_type_param_bounds(ebml_w, ecx, polyty.bounds); - encode_type(ecx, ebml_w, polyty.ty); - let mut m_path = vec::append(~[], path); // :-( - m_path += [ast_map::path_name(item.ident)]; - encode_path(ecx, ebml_w, m_path, ast_map::path_name(ty_m.ident)); - - // For now, use the item visibility until trait methods can have - // real visibility in the AST. - encode_visibility(ebml_w, item.vis); - ebml_w.end_tag(); - } + let mut trait_path = vec::append(~[], path); + trait_path.push(ast_map::path_name(item.ident)); + encode_path(ecx, ebml_w, trait_path, ast_map::path_name(method_ty.ident)); + + match method_ty.self_ty { + sty_static => { + encode_family(ebml_w, + purity_static_method_family( + method_ty.fty.purity)); + + let tpt = ty::lookup_item_type(tcx, method_def_id); + encode_ty_type_param_defs(ebml_w, ecx, + tpt.generics.type_param_defs, + tag_items_data_item_ty_param_bounds); + encode_type(ecx, ebml_w, tpt.ty); + } - // Finally, output all the provided methods as items. - for provided_methods.each |m| { - index.push(entry { val: m.id, pos: ebml_w.writer.tell() }); + _ => { + encode_family(ebml_w, + purity_fn_family( + method_ty.fty.purity)); + } + } - // We do not concatenate the generics of the owning impl and that - // of provided methods. I am not sure why this is. -ndm - let owner_generics = ast_util::empty_generics(); + match ms[i] { + required(_) => { + encode_method_sort(ebml_w, 'r'); + } - encode_info_for_method(ecx, - ebml_w, - /*bad*/copy path, - true, - item.id, - *m, - item.vis, - &owner_generics, - &m.generics); + provided(m) => { + // This is obviously a bogus assert but I don't think this + // ever worked before anyhow...near as I can tell, before + // we would emit two items. + if method_ty.self_ty == sty_static { + tcx.sess.span_unimpl( + item.span, + fmt!("Method %s is both provided and static", + *tcx.sess.intr().get(method_ty.ident))); + } + encode_type_param_bounds(ebml_w, ecx, + &m.generics.ty_params); + encode_method_sort(ebml_w, 'p'); + (ecx.encode_inlined_item)( + ecx, ebml_w, path, + ii_method(local_def(item.id), m)); + } + } + + ebml_w.end_tag(); } } item_mac(*) => fail!(~"item macros unimplemented") @@ -1345,7 +1367,7 @@ pub fn encode_metadata(+parms: EncodeParams, crate: &crate) -> ~[u8] { link_meta: link_meta, cstore: cstore, encode_inlined_item: encode_inlined_item, - type_abbrevs: @mut LinearMap::new() + type_abbrevs: @mut HashMap::new() }; let ebml_w = writer::Encoder(wr as @io::Writer); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 9c61205667750..cfe9c8cd40a66 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -206,7 +206,8 @@ fn get_metadata_section(os: os, while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { let name_buf = llvm::LLVMGetSectionName(si.llsi); let name = unsafe { str::raw::from_c_str(name_buf) }; - if name == meta_section_name(os) { + debug!("get_matadata_section: name %s", name); + if name == read_meta_section_name(os) { let cbuf = llvm::LLVMGetSectionContents(si.llsi); let csz = llvm::LLVMGetSectionSize(si.llsi) as uint; let mut found = None; @@ -251,6 +252,16 @@ pub fn meta_section_name(os: os) -> ~str { } } +pub fn read_meta_section_name(os: os) -> ~str { + match os { + os_macos => ~"__note.rustc", + os_win32 => ~".note.rustc", + os_linux => ~".note.rustc", + os_android => ~".note.rustc", + os_freebsd => ~".note.rustc" + } +} + // A diagnostic function for dumping crate metadata to an output stream pub fn list_file_metadata(intr: @ident_interner, os: os, diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 111bc307ed308..f52ff056472f9 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -119,13 +119,25 @@ pub fn parse_ty_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, parse_ty(st, conv) } +pub fn parse_bare_fn_ty_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, + conv: conv_did) -> ty::BareFnTy { + let st = parse_state_from_data(data, crate_num, pos, tcx); + parse_bare_fn_ty(st, conv) +} + +pub fn parse_trait_ref_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, + conv: conv_did) -> ty::TraitRef { + let st = parse_state_from_data(data, crate_num, pos, tcx); + parse_trait_ref(st, conv) +} + pub fn parse_arg_data(data: @~[u8], crate_num: int, pos: uint, tcx: ty::ctxt, conv: conv_did) -> ty::arg { let st = parse_state_from_data(data, crate_num, pos, tcx); parse_arg(st, conv) } -fn parse_path(st: @mut PState) -> @ast::path { +fn parse_path(st: @mut PState) -> @ast::Path { let mut idents: ~[ast::ident] = ~[]; fn is_last(c: char) -> bool { return c == '(' || c == ':'; } idents.push(parse_ident_(st, is_last)); @@ -134,7 +146,7 @@ fn parse_path(st: @mut PState) -> @ast::path { ':' => { next(st); next(st); } c => { if c == '(' { - return @ast::path { span: dummy_sp(), + return @ast::Path { span: dummy_sp(), global: false, idents: idents, rp: None, @@ -159,7 +171,7 @@ fn parse_vstore(st: @mut PState) -> ty::vstore { let c = peek(st); if '0' <= c && c <= '9' { - let n = parse_int(st) as uint; + let n = parse_uint(st); assert!(next(st) == '|'); return ty::vstore_fixed(n); } @@ -177,7 +189,6 @@ fn parse_trait_store(st: @mut PState) -> ty::TraitStore { '~' => ty::UniqTraitStore, '@' => ty::BoxTraitStore, '&' => ty::RegionTraitStore(parse_region(st)), - '.' => ty::BareTraitStore, c => st.tcx.sess.bug(fmt!("parse_trait_store(): bad input '%c'", c)) } } @@ -203,13 +214,13 @@ fn parse_bound_region(st: @mut PState) -> ty::bound_region { match next(st) { 's' => ty::br_self, 'a' => { - let id = parse_int(st) as uint; + let id = parse_uint(st); assert!(next(st) == '|'); ty::br_anon(id) } '[' => ty::br_named(st.tcx.sess.ident_of(parse_str(st, ']'))), 'c' => { - let id = parse_int(st); + let id = parse_uint(st) as int; assert!(next(st) == '|'); ty::br_cap_avoid(id, @parse_bound_region(st)) }, @@ -224,14 +235,15 @@ fn parse_region(st: @mut PState) -> ty::Region { } 'f' => { assert!(next(st) == '['); - let id = parse_int(st); + let id = parse_uint(st) as int; assert!(next(st) == '|'); let br = parse_bound_region(st); assert!(next(st) == ']'); - ty::re_free(id, br) + ty::re_free(ty::FreeRegion {scope_id: id, + bound_region: br}) } 's' => { - let id = parse_int(st); + let id = parse_uint(st) as int; assert!(next(st) == '|'); ty::re_scope(id) } @@ -259,6 +271,12 @@ fn parse_str(st: @mut PState, term: char) -> ~str { return result; } +fn parse_trait_ref(st: @mut PState, conv: conv_did) -> ty::TraitRef { + let def = parse_def(st, NominalType, conv); + let substs = parse_substs(st, conv); + ty::TraitRef {def_id: def, substs: substs} +} + fn parse_ty(st: @mut PState, conv: conv_did) -> ty::t { match next(st) { 'n' => return ty::mk_nil(st.tcx), @@ -301,7 +319,7 @@ fn parse_ty(st: @mut PState, conv: conv_did) -> ty::t { 'p' => { let did = parse_def(st, TypeParameter, conv); debug!("parsed ty_param: did=%?", did); - return ty::mk_param(st.tcx, parse_int(st) as uint, did); + return ty::mk_param(st.tcx, parse_uint(st), did); } 's' => { let did = parse_def(st, TypeParameter, conv); @@ -396,14 +414,14 @@ fn parse_def(st: @mut PState, source: DefIdSource, return conv(source, parse_def_id(def)); } -fn parse_int(st: @mut PState) -> int { +fn parse_uint(st: @mut PState) -> uint { let mut n = 0; loop { let cur = peek(st); if cur < '0' || cur > '9' { return n; } st.pos = st.pos + 1u; n *= 10; - n += (cur as int) - ('0' as int); + n += (cur as uint) - ('0' as uint); }; } @@ -530,11 +548,17 @@ pub fn parse_def_id(buf: &[u8]) -> ast::def_id { ast::def_id { crate: crate_num, node: def_num } } -pub fn parse_bounds_data(data: @~[u8], start: uint, - crate_num: int, tcx: ty::ctxt, conv: conv_did) - -> @~[ty::param_bound] { +pub fn parse_type_param_def_data(data: @~[u8], start: uint, + crate_num: int, tcx: ty::ctxt, + conv: conv_did) -> ty::TypeParameterDef +{ let st = parse_state_from_data(data, crate_num, start, tcx); - parse_bounds(st, conv) + parse_type_param_def(st, conv) +} + +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)} } fn parse_bounds(st: @mut PState, conv: conv_did) -> @~[ty::param_bound] { @@ -545,7 +569,7 @@ fn parse_bounds(st: @mut PState, conv: conv_did) -> @~[ty::param_bound] { 'C' => ty::bound_copy, 'K' => ty::bound_const, 'O' => ty::bound_durable, - 'I' => ty::bound_trait(parse_ty(st, conv)), + 'I' => ty::bound_trait(@parse_trait_ref(st, conv)), '.' => break, _ => fail!(~"parse_bounds: bad bounds") }); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 9b777332c27c3..2e1dd8b6dad86 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -16,7 +16,7 @@ use core::prelude::*; use middle::ty::param_ty; use middle::ty; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::io::WriterUtil; use core::io; use core::uint; @@ -47,7 +47,7 @@ pub struct ty_abbrev { pub enum abbrev_ctxt { ac_no_abbrevs, - ac_use_abbrevs(@mut LinearMap), + ac_use_abbrevs(@mut HashMap), } fn cx_uses_abbrevs(cx: @ctxt) -> bool { @@ -146,12 +146,12 @@ fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) { w.write_char('b'); enc_bound_region(w, cx, br); } - ty::re_free(id, br) => { + ty::re_free(ref fr) => { w.write_char('f'); w.write_char('['); - w.write_int(id); + w.write_int(fr.scope_id); w.write_char('|'); - enc_bound_region(w, cx, br); + enc_bound_region(w, cx, fr.bound_region); w.write_char(']'); } ty::re_scope(nid) => { @@ -214,11 +214,16 @@ pub fn enc_vstore(w: @io::Writer, cx: @ctxt, v: ty::vstore) { } } +pub fn enc_trait_ref(w: @io::Writer, cx: @ctxt, s: &ty::TraitRef) { + w.write_str((cx.ds)(s.def_id)); + w.write_char('|'); + enc_substs(w, cx, s.substs); +} + pub fn enc_trait_store(w: @io::Writer, cx: @ctxt, s: ty::TraitStore) { match s { ty::UniqTraitStore => w.write_char('~'), ty::BoxTraitStore => w.write_char('@'), - ty::BareTraitStore => w.write_char('.'), ty::RegionTraitStore(re) => { w.write_char('&'); enc_region(w, cx, re); @@ -384,7 +389,7 @@ fn enc_onceness(w: @io::Writer, o: Onceness) { } } -fn enc_bare_fn_ty(w: @io::Writer, cx: @ctxt, ft: &ty::BareFnTy) { +pub fn enc_bare_fn_ty(w: @io::Writer, cx: @ctxt, ft: &ty::BareFnTy) { enc_purity(w, ft.purity); enc_abi_set(w, ft.abis); enc_fn_sig(w, cx, &ft.sig); @@ -407,7 +412,7 @@ fn enc_fn_sig(w: @io::Writer, cx: @ctxt, fsig: &ty::FnSig) { enc_ty(w, cx, fsig.output); } -pub fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { +fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { for vec::each(*bs) |bound| { match *bound { ty::bound_owned => w.write_char('S'), @@ -415,14 +420,20 @@ pub fn enc_bounds(w: @io::Writer, cx: @ctxt, bs: @~[ty::param_bound]) { ty::bound_const => w.write_char('K'), ty::bound_durable => w.write_char('O'), ty::bound_trait(tp) => { - w.write_char('I'); - enc_ty(w, cx, tp); + w.write_char('I'); + enc_trait_ref(w, cx, tp); } } } w.write_char('.'); } +pub fn enc_type_param_def(w: @io::Writer, cx: @ctxt, v: &ty::TypeParameterDef) { + w.write_str((cx.ds)(v.def_id)); + w.write_char('|'); + enc_bounds(w, cx, v.bounds); +} + // // Local Variables: // mode: rust diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index b6b6730620e9e..a67be995171ff 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -417,6 +417,7 @@ impl tr for ast::def { ast::def_variant(e_did, v_did) => { ast::def_variant(e_did.tr(xcx), v_did.tr(xcx)) } + ast::def_trait(did) => ast::def_trait(did.tr(xcx)), ast::def_ty(did) => ast::def_ty(did.tr(xcx)), ast::def_prim_ty(p) => ast::def_prim_ty(p), ast::def_ty_param(did, v) => ast::def_ty_param(did.tr(xcx), v), @@ -474,9 +475,12 @@ impl tr for ty::Region { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::Region { match *self { ty::re_bound(br) => ty::re_bound(br.tr(xcx)), - ty::re_free(id, br) => ty::re_free(xcx.tr_id(id), br.tr(xcx)), ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)), ty::re_static | ty::re_infer(*) => *self, + ty::re_free(ref fr) => { + ty::re_free(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), + bound_region: fr.bound_region.tr(xcx)}) + } } } } @@ -555,6 +559,7 @@ trait read_method_map_entry_helper { -> method_map_entry; } +#[cfg(stage0)] fn encode_method_map_entry(ecx: @e::EncodeContext, ebml_w: writer::Encoder, mme: method_map_entry) { @@ -571,7 +576,27 @@ fn encode_method_map_entry(ecx: @e::EncodeContext, } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +fn encode_method_map_entry(ecx: @e::EncodeContext, + ebml_w: writer::Encoder, + mme: method_map_entry) { + do ebml_w.emit_struct("method_map_entry", 3) { + do ebml_w.emit_struct_field("self_arg", 0u) { + ebml_w.emit_arg(ecx, mme.self_arg); + } + do ebml_w.emit_struct_field("explicit_self", 2u) { + mme.explicit_self.encode(&ebml_w); + } + do ebml_w.emit_struct_field("origin", 1u) { + mme.origin.encode(&ebml_w); + } + } +} + impl read_method_map_entry_helper for reader::Decoder { + #[cfg(stage0)] fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) -> method_map_entry { do self.read_struct("method_map_entry", 3) { @@ -591,6 +616,29 @@ impl read_method_map_entry_helper for reader::Decoder { } } } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) + -> method_map_entry { + do self.read_struct("method_map_entry", 3) { + method_map_entry { + self_arg: self.read_struct_field("self_arg", 0u, || { + self.read_arg(xcx) + }), + explicit_self: self.read_struct_field("explicit_self", 2u, || { + let self_type: ast::self_ty_ = Decodable::decode(self); + self_type + }), + origin: self.read_struct_field("origin", 1u, || { + let method_origin: method_origin = + Decodable::decode(self); + method_origin.tr(xcx) + }), + } + } + } } impl tr for method_origin { @@ -740,7 +788,9 @@ trait ebml_writer_helpers { fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t); fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore); fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]); - fn emit_bounds(&self, ecx: @e::EncodeContext, bs: ty::param_bounds); + fn emit_type_param_def(&self, + ecx: @e::EncodeContext, + type_param_def: &ty::TypeParameterDef); fn emit_tpbt(&self, ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty); } @@ -770,24 +820,60 @@ impl ebml_writer_helpers for writer::Encoder { } } - fn emit_bounds(&self, ecx: @e::EncodeContext, bs: ty::param_bounds) { + fn emit_type_param_def(&self, + ecx: @e::EncodeContext, + type_param_def: &ty::TypeParameterDef) { do self.emit_opaque { - tyencode::enc_bounds(self.writer, ecx.ty_str_ctxt(), bs) + tyencode::enc_type_param_def(self.writer, ecx.ty_str_ctxt(), + type_param_def) } } + #[cfg(stage0)] fn emit_tpbt(&self, ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { - do self.emit_struct("ty_param_bounds_and_ty", 3) { - do self.emit_field(~"bounds", 0) { - do self.emit_from_vec(*tpbt.bounds) |bs| { - self.emit_bounds(ecx, *bs); + do self.emit_struct("ty_param_bounds_and_ty", 2) { + do self.emit_field(~"generics", 0) { + do self.emit_struct("Generics", 2) { + do self.emit_field(~"type_param_defs", 0) { + do self.emit_from_vec(*tpbt.generics.type_param_defs) + |type_param_def| + { + self.emit_type_param_def(ecx, type_param_def); + } + } + do self.emit_field(~"region_param", 1) { + tpbt.generics.region_param.encode(self); + } } } - do self.emit_field(~"region_param", 1u) { - tpbt.region_param.encode(self); + do self.emit_field(~"ty", 1) { + self.emit_ty(ecx, tpbt.ty); + } + } + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_tpbt(&self, ecx: @e::EncodeContext, + tpbt: ty::ty_param_bounds_and_ty) { + do self.emit_struct("ty_param_bounds_and_ty", 2) { + do self.emit_struct_field("generics", 0) { + do self.emit_struct("Generics", 2) { + do self.emit_struct_field("type_param_defs", 0) { + do self.emit_from_vec(*tpbt.generics.type_param_defs) + |type_param_def| + { + self.emit_type_param_def(ecx, type_param_def); + } + } + do self.emit_struct_field("region_param", 1) { + tpbt.generics.region_param.encode(self); + } + } } - do self.emit_field(~"ty", 2u) { + do self.emit_struct_field("ty", 1) { self.emit_ty(ecx, tpbt.ty); } } @@ -884,11 +970,11 @@ fn encode_side_tables_for_id(ecx: @e::EncodeContext, } } - for tcx.ty_param_bounds.find(&id).each |&pbs| { - do ebml_w.tag(c::tag_table_param_bounds) { + for tcx.ty_param_defs.find(&id).each |&type_param_def| { + do ebml_w.tag(c::tag_table_param_defs) { ebml_w.id(id); do ebml_w.tag(c::tag_table_val) { - ebml_w.emit_bounds(ecx, *pbs) + ebml_w.emit_type_param_def(ecx, type_param_def) } } } @@ -985,7 +1071,7 @@ trait ebml_decoder_decoder_helpers { fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg; fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t; fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t]; - fn read_bounds(&self, xcx: @ExtendedDecodeContext) -> @~[ty::param_bound]; + fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef; fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty; fn convert_def_id(&self, xcx: @ExtendedDecodeContext, @@ -1033,27 +1119,56 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { self.read_to_vec(|| self.read_ty(xcx) ) } - fn read_bounds(&self, xcx: @ExtendedDecodeContext) - -> @~[ty::param_bound] { + fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef { do self.read_opaque |doc| { - tydecode::parse_bounds_data( + tydecode::parse_type_param_def_data( doc.data, doc.start, xcx.dcx.cdata.cnum, xcx.dcx.tcx, |s, a| self.convert_def_id(xcx, s, a)) } } + #[cfg(stage0)] fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty { - do self.read_struct("ty_param_bounds_and_ty", 3) { + do self.read_struct("ty_param_bounds_and_ty", 2) { ty::ty_param_bounds_and_ty { - bounds: self.read_field(~"bounds", 0u, || { - @self.read_to_vec(|| self.read_bounds(xcx) ) - }), - region_param: self.read_field(~"region_param", 1u, || { - Decodable::decode(self) - }), - ty: self.read_field(~"ty", 2u, || { + generics: do self.read_struct("Generics", 2) { + ty::Generics { + type_param_defs: self.read_field("type_param_defs", 0, || { + @self.read_to_vec(|| self.read_type_param_def(xcx)) + }), + region_param: self.read_field(~"region_param", 1, || { + Decodable::decode(self) + }) + } + }, + ty: self.read_field(~"ty", 1, || { + self.read_ty(xcx) + }) + } + } + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) + -> ty::ty_param_bounds_and_ty + { + do self.read_struct("ty_param_bounds_and_ty", 2) { + ty::ty_param_bounds_and_ty { + generics: do self.read_struct("Generics", 2) { + ty::Generics { + type_param_defs: self.read_struct_field("type_param_defs", 0, || { + @self.read_to_vec(|| self.read_type_param_def(xcx)) + }), + region_param: self.read_struct_field(~"region_param", 1, || { + Decodable::decode(self) + }) + } + }, + ty: self.read_struct_field("ty", 1, || { self.read_ty(xcx) }) } @@ -1125,9 +1240,9 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx); let lid = ast::def_id { crate: ast::local_crate, node: id }; dcx.tcx.tcache.insert(lid, tpbt); - } else if tag == (c::tag_table_param_bounds as uint) { - let bounds = val_dsr.read_bounds(xcx); - dcx.tcx.ty_param_bounds.insert(id, bounds); + } else if tag == (c::tag_table_param_defs as uint) { + let bounds = val_dsr.read_type_param_def(xcx); + dcx.tcx.ty_param_defs.insert(id, bounds); } else if tag == (c::tag_table_last_use as uint) { let ids = val_dsr.read_to_vec(|| { xcx.tr_id(val_dsr.read_int()) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index ac74dc25fd0d7..116b70bf7e320 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -31,8 +31,9 @@ use middle::mem_categorization::{lp_comp, lp_deref, lp_local}; use middle::ty; use util::ppaux::ty_to_str; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use core::uint; +use core::util::with; use syntax::ast::m_mutbl; use syntax::ast; use syntax::ast_util; @@ -40,13 +41,18 @@ use syntax::codemap::span; use syntax::print::pprust; use syntax::visit; +struct PurityState { + def: ast::node_id, + purity: ast::purity +} + struct CheckLoanCtxt { bccx: @BorrowckCtxt, req_maps: ReqMaps, - reported: LinearSet, + reported: HashSet, - declared_purity: @mut ast::purity, + declared_purity: @mut PurityState, fn_args: @mut @~[ast::node_id] } @@ -62,14 +68,25 @@ enum purity_cause { pc_cmt(bckerr) } +// if we're not pure, why? +#[deriving(Eq)] +enum impurity_cause { + // some surrounding block was marked as 'unsafe' + pc_unsafe, + + // nothing was unsafe, and nothing was pure + pc_default, +} + pub fn check_loans(bccx: @BorrowckCtxt, +req_maps: ReqMaps, crate: @ast::crate) { let clcx = @mut CheckLoanCtxt { bccx: bccx, req_maps: req_maps, - reported: LinearSet::new(), - declared_purity: @mut ast::impure_fn, + reported: HashSet::new(), + declared_purity: @mut PurityState { purity: ast::impure_fn, + def: 0 }, fn_args: @mut @~[] }; let vt = visit::mk_vt(@visit::Visitor {visit_expr: check_loans_in_expr, @@ -106,16 +123,18 @@ pub impl assignment_type { pub impl CheckLoanCtxt { fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - fn purity(&mut self, scope_id: ast::node_id) -> Option { - let default_purity = match *self.declared_purity { + fn purity(&mut self, scope_id: ast::node_id) + -> Either + { + let default_purity = match self.declared_purity.purity { // an unsafe declaration overrides all - ast::unsafe_fn => return None, + ast::unsafe_fn => return Right(pc_unsafe), // otherwise, remember what was declared as the // default, but we must scan for requirements // imposed by the borrow check - ast::pure_fn => Some(pc_pure_fn), - ast::extern_fn | ast::impure_fn => None + ast::pure_fn => Left(pc_pure_fn), + ast::extern_fn | ast::impure_fn => Right(pc_default) }; // scan to see if this scope or any enclosing scope requires @@ -125,12 +144,12 @@ pub impl CheckLoanCtxt { loop { match self.req_maps.pure_map.find(&scope_id) { None => (), - Some(e) => return Some(pc_cmt(*e)) + Some(e) => return Left(pc_cmt(*e)) } - match self.tcx().region_map.find(&scope_id) { + match self.tcx().region_maps.opt_encl_scope(scope_id) { None => return default_purity, - Some(&next_scope_id) => scope_id = next_scope_id + Some(next_scope_id) => scope_id = next_scope_id } } } @@ -146,9 +165,9 @@ pub impl CheckLoanCtxt { } } - match self.tcx().region_map.find(&scope_id) { + match self.tcx().region_maps.opt_encl_scope(scope_id) { None => return, - Some(&next_scope_id) => scope_id = next_scope_id, + Some(next_scope_id) => scope_id = next_scope_id, } } } @@ -171,7 +190,7 @@ pub impl CheckLoanCtxt { // overloaded operators the callee has an id but no expr. // annoying. fn check_pure_callee_or_arg(&mut self, - pc: purity_cause, + pc: Either, opt_expr: Option<@ast::expr>, callee_id: ast::node_id, callee_span: span) { @@ -196,7 +215,7 @@ pub impl CheckLoanCtxt { match opt_expr { Some(expr) => { match expr.node { - ast::expr_path(_) if pc == pc_pure_fn => { + ast::expr_path(_) if pc == Left(pc_pure_fn) => { let def = *self.tcx().def_map.get(&expr.id); let did = ast_util::def_id_of_def(def); let is_fn_arg = @@ -270,7 +289,7 @@ pub impl CheckLoanCtxt { debug!("new_loans has length %?", new_loans.len()); - let par_scope_id = *self.tcx().region_map.get(&scope_id); + let par_scope_id = self.tcx().region_maps.encl_scope(scope_id); for self.walk_loans(par_scope_id) |old_loan| { debug!("old_loan=%?", self.bccx.loan_to_repr(old_loan)); @@ -361,10 +380,10 @@ pub impl CheckLoanCtxt { // if this is a pure function, only loan-able state can be // assigned, because it is uniquely tied to this function and // is not visible from the outside - match self.purity(ex.id) { - None => (), - Some(pc_cmt(_)) => { - let purity = self.purity(ex.id).get(); + let purity = self.purity(ex.id); + match purity { + Right(_) => (), + Left(pc_cmt(_)) => { // Subtle: Issue #3162. If we are enforcing purity // because there is a reference to aliasable, mutable data // that we require to be immutable, we can't allow writes @@ -376,10 +395,10 @@ pub impl CheckLoanCtxt { ex.span, at.ing_form(self.bccx.cmt_to_str(cmt))); } - Some(pc_pure_fn) => { + Left(pc_pure_fn) => { if cmt.lp.is_none() { self.report_purity_error( - pc_pure_fn, ex.span, + purity, ex.span, at.ing_form(self.bccx.cmt_to_str(cmt))); } } @@ -462,14 +481,23 @@ pub impl CheckLoanCtxt { } } - fn report_purity_error(&mut self, pc: purity_cause, sp: span, msg: ~str) { + fn report_purity_error(&mut self, pc: Either, + sp: span, msg: ~str) { match pc { - pc_pure_fn => { + Right(pc_default) => { fail!(~"pc_default should be filtered sooner") } + Right(pc_unsafe) => { + // this error was prevented by being marked as unsafe, so flag the + // definition as having contributed to the validity of the program + let def = self.declared_purity.def; + debug!("flagging %? as a used unsafe source", def); + self.tcx().used_unsafe.insert(def); + } + Left(pc_pure_fn) => { self.tcx().sess.span_err( sp, fmt!("%s prohibited in pure context", msg)); } - pc_cmt(ref e) => { + Left(pc_cmt(ref e)) => { if self.reported.insert((*e).cmt.id) { self.tcx().sess.span_err( (*e).cmt.span, @@ -556,16 +584,32 @@ pub impl CheckLoanCtxt { callee_id: ast::node_id, callee_span: span, args: &[@ast::expr]) { - match self.purity(expr.id) { - None => {} - Some(ref pc) => { - self.check_pure_callee_or_arg( - (*pc), callee, callee_id, callee_span); - for args.each |arg| { - self.check_pure_callee_or_arg( - (*pc), Some(*arg), arg.id, arg.span); + let pc = self.purity(expr.id); + match pc { + // no purity, no need to check for anything + Right(pc_default) => return, + + // some form of purity, definitely need to check + Left(_) => (), + + // Unsafe trumped. To see if the unsafe is necessary, see what the + // purity would have been without a trump, and if it's some form + // of purity then we need to go ahead with the check + Right(pc_unsafe) => { + match do with(&mut self.declared_purity.purity, + ast::impure_fn) { self.purity(expr.id) } { + Right(pc_unsafe) => fail!(~"unsafe can't trump twice"), + Right(pc_default) => return, + Left(_) => () + } } - } + + } + self.check_pure_callee_or_arg( + pc, callee, callee_id, callee_span); + for args.each |arg| { + self.check_pure_callee_or_arg( + pc, Some(*arg), arg.id, arg.span); } } } @@ -580,27 +624,32 @@ fn check_loans_in_fn(fk: &visit::fn_kind, let is_stack_closure = self.is_stack_closure(id); let fty = ty::node_id_to_type(self.tcx(), id); - let declared_purity; + let declared_purity, src; match *fk { visit::fk_item_fn(*) | visit::fk_method(*) | visit::fk_dtor(*) => { declared_purity = ty::ty_fn_purity(fty); + src = id; } visit::fk_anon(*) | visit::fk_fn_block(*) => { let fty_sigil = ty::ty_closure_sigil(fty); check_moves_from_captured_variables(self, id, fty_sigil); - declared_purity = ty::determine_inherited_purity( - *self.declared_purity, - ty::ty_fn_purity(fty), + let pair = ty::determine_inherited_purity( + (self.declared_purity.purity, self.declared_purity.def), + (ty::ty_fn_purity(fty), id), fty_sigil); + declared_purity = pair.first(); + src = pair.second(); } } debug!("purity on entry=%?", copy self.declared_purity); do save_and_restore_managed(self.declared_purity) { do save_and_restore_managed(self.fn_args) { - *self.declared_purity = declared_purity; + self.declared_purity = @mut PurityState { + purity: declared_purity, def: src + }; match *fk { visit::fk_anon(*) | @@ -754,7 +803,10 @@ fn check_loans_in_block(blk: &ast::blk, ast::default_blk => { } ast::unsafe_blk => { - *self.declared_purity = ast::unsafe_fn; + *self.declared_purity = PurityState { + purity: ast::unsafe_fn, + def: blk.node.id, + }; } } diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index 925659984d4bd..4e61b5738912f 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -29,9 +29,9 @@ use middle::pat_util; use middle::ty::{ty_region}; use middle::ty; use util::common::indenter; -use util::ppaux::{expr_repr, region_to_str}; +use util::ppaux::{Repr, region_to_str}; -use core::hashmap::linear::{LinearSet, LinearMap}; +use core::hashmap::{HashSet, HashMap}; use core::vec; use syntax::ast::{m_const, m_imm, m_mutbl}; use syntax::ast; @@ -72,17 +72,17 @@ struct GatherLoanCtxt { req_maps: ReqMaps, item_ub: ast::node_id, root_ub: ast::node_id, - ignore_adjustments: LinearSet + ignore_adjustments: HashSet } pub fn gather_loans(bccx: @BorrowckCtxt, crate: @ast::crate) -> ReqMaps { let glcx = @mut GatherLoanCtxt { bccx: bccx, - req_maps: ReqMaps { req_loan_map: LinearMap::new(), - pure_map: LinearMap::new() }, + req_maps: ReqMaps { req_loan_map: HashMap::new(), + pure_map: HashMap::new() }, item_ub: 0, root_ub: 0, - ignore_adjustments: LinearSet::new() + ignore_adjustments: HashSet::new() }; let v = visit::mk_vt(@visit::Visitor {visit_expr: req_loans_in_expr, visit_fn: req_loans_in_fn, @@ -242,7 +242,7 @@ fn req_loans_in_expr(ex: @ast::expr, // (if used like `a.b(...)`), the call where it's an argument // (if used like `x(a.b)`), or the block (if used like `let x // = a.b`). - let scope_r = ty::re_scope(*self.tcx().region_map.get(&ex.id)); + let scope_r = self.tcx().region_maps.encl_region(ex.id); let rcvr_cmt = self.bccx.cat_expr(rcvr); self.guarantee_valid(rcvr_cmt, m_imm, scope_r); visit::visit_expr(ex, self, vt); @@ -282,7 +282,7 @@ pub impl GatherLoanCtxt { expr: @ast::expr, adjustment: &ty::AutoAdjustment) { debug!("guarantee_adjustments(expr=%s, adjustment=%?)", - expr_repr(self.tcx(), expr), adjustment); + expr.repr(self.tcx()), adjustment); let _i = indenter(); match *adjustment { @@ -524,7 +524,10 @@ pub impl GatherLoanCtxt { // immutable structures, this is just the converse I suppose) let scope_id = match scope_r { - ty::re_scope(scope_id) | ty::re_free(scope_id, _) => scope_id, + ty::re_scope(scope_id) | + ty::re_free(ty::FreeRegion {scope_id, _}) => { + scope_id + } _ => { self.bccx.tcx.sess.span_bug( cmt.span, diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs index 146e0c712a33d..a38cd015654b5 100644 --- a/src/librustc/middle/borrowck/loan.rs +++ b/src/librustc/middle/borrowck/loan.rs @@ -130,8 +130,8 @@ pub impl LoanContext { } cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => { // FIXME(#4903) - let local_scope_id = *self.bccx.tcx.region_map.get(&local_id); - self.issue_loan(cmt, ty::re_scope(local_scope_id), loan_kind, + let local_region = self.bccx.tcx.region_maps.encl_region(local_id); + self.issue_loan(cmt, local_region, loan_kind, owns_lent_data) } cat_stack_upvar(cmt) => { diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 3f4f7469832f5..01fea2a960d4b 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -227,14 +227,13 @@ Borrowck results in two maps. use core::prelude::*; use middle::mem_categorization::*; -use middle::region; use middle::ty; use middle::typeck; use middle::moves; use util::common::stmt_set; use util::ppaux::note_and_explain_region; -use core::hashmap::linear::{LinearSet, LinearMap}; +use core::hashmap::{HashSet, HashMap}; use core::io; use core::result::{Result, Ok, Err}; use core::to_bytes; @@ -260,9 +259,9 @@ pub fn check_crate( moves_map: moves_map, capture_map: capture_map, root_map: root_map(), - mutbl_map: @mut LinearSet::new(), - write_guard_map: @mut LinearSet::new(), - stmt_map: @mut LinearSet::new(), + mutbl_map: @mut HashSet::new(), + write_guard_map: @mut HashSet::new(), + stmt_map: @mut HashSet::new(), stats: @mut BorrowStats { loaned_paths_same: 0, loaned_paths_imm: 0, @@ -333,7 +332,7 @@ pub struct RootInfo { // a map mapping id's of expressions of gc'd type (@T, @[], etc) where // the box needs to be kept live to the id of the scope for which they // must stay live. -pub type root_map = @mut LinearMap; +pub type root_map = @mut HashMap; // the keys to the root map combine the `id` of the expression with // the number of types that it is autodereferenced. So, for example, @@ -348,11 +347,11 @@ pub struct root_map_key { // set of ids of local vars / formal arguments that are modified / moved. // this is used in trans for optimization purposes. -pub type mutbl_map = @mut LinearSet; +pub type mutbl_map = @mut HashSet; // A set containing IDs of expressions of gc'd type that need to have a write // guard. -pub type write_guard_map = @mut LinearSet; +pub type write_guard_map = @mut HashSet; // Errors that can occur #[deriving(Eq)] @@ -405,8 +404,8 @@ pub struct Loan { /// - `pure_map`: map from block/expr that must be pure to the error message /// that should be reported if they are not pure pub struct ReqMaps { - req_loan_map: LinearMap, - pure_map: LinearMap + req_loan_map: HashMap, + pure_map: HashMap } pub fn save_and_restore(save_and_restore_t: &mut T, @@ -450,7 +449,7 @@ impl to_bytes::IterBytes for root_map_key { } pub fn root_map() -> root_map { - return @mut LinearMap::new(); + return @mut HashMap::new(); } // ___________________________________________________________________________ @@ -458,7 +457,7 @@ pub fn root_map() -> root_map { pub impl BorrowckCtxt { fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region) -> bool { - region::is_subregion_of(self.tcx.region_map, r_sub, r_sup) + self.tcx.region_maps.is_subregion_of(r_sub, r_sup) } fn cat_expr(&self, expr: @ast::expr) -> cmt { diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs index 3056edea233fb..40a59e2f89f26 100644 --- a/src/librustc/middle/borrowck/preserve.rs +++ b/src/librustc/middle/borrowck/preserve.rs @@ -108,7 +108,7 @@ pub impl<'self> PreserveCtxt<'self> { // Maybe if we pass in the parent instead here, // we can prevent the "scope not found" error debug!("scope_region thing: %? ", cmt.id); - ty::re_scope(*self.tcx().region_map.get(&cmt.id)) + self.tcx().region_maps.encl_region(cmt.id) }; self.compare_scope(cmt, scope_region) @@ -128,27 +128,27 @@ pub impl<'self> PreserveCtxt<'self> { cmt.span, ~"preserve() called with local and !root_managed_data"); } - let local_scope_id = *self.tcx().region_map.get(&local_id); - self.compare_scope(cmt, ty::re_scope(local_scope_id)) + let local_region = self.tcx().region_maps.encl_region(local_id); + self.compare_scope(cmt, local_region) } cat_binding(local_id) => { // Bindings are these kind of weird implicit pointers (cc // #2329). We require (in gather_loans) that they be // rooted in an immutable location. - let local_scope_id = *self.tcx().region_map.get(&local_id); - self.compare_scope(cmt, ty::re_scope(local_scope_id)) + let local_region = self.tcx().region_maps.encl_region(local_id); + self.compare_scope(cmt, local_region) } cat_arg(local_id) => { // This can happen as not all args are lendable (e.g., && // modes). In that case, the caller guarantees stability // for at least the scope of the fn. This is basically a // deref of a region ptr. - let local_scope_id = *self.tcx().region_map.get(&local_id); - self.compare_scope(cmt, ty::re_scope(local_scope_id)) + let local_region = self.tcx().region_maps.encl_region(local_id); + self.compare_scope(cmt, local_region) } cat_self(local_id) => { - let local_scope_id = *self.tcx().region_map.get(&local_id); - self.compare_scope(cmt, ty::re_scope(local_scope_id)) + let local_region = self.tcx().region_maps.encl_region(local_id); + self.compare_scope(cmt, local_region) } cat_comp(cmt_base, comp_field(*)) | cat_comp(cmt_base, comp_index(*)) | diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index fdea403cc2a00..6898dcca45dd8 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -596,8 +596,11 @@ pub fn specialize(cx: @MatchCheckCtxt, class_id); } _ => { - cx.tcx.sess.span_bug(pat_span, - ~"struct pattern didn't resolve to a struct"); + cx.tcx.sess.span_bug( + pat_span, + fmt!("struct pattern resolved to %s, \ + not a struct", + ty_to_str(cx.tcx, left_ty))); } } let args = vec::map(class_fields, |class_field| { diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index d610b007f3503..63122a82eafdf 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -20,7 +20,7 @@ use core::vec; use syntax::{ast, ast_map, ast_util, visit}; use syntax::ast::*; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; // // This pass classifies expressions by their constant-ness. @@ -189,14 +189,14 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, } } else { let maps = astencode::Maps { - mutbl_map: @mut LinearSet::new(), - root_map: @mut LinearMap::new(), - last_use_map: @mut LinearMap::new(), - method_map: @mut LinearMap::new(), - vtable_map: @mut LinearMap::new(), - write_guard_map: @mut LinearSet::new(), - moves_map: @mut LinearSet::new(), - capture_map: @mut LinearMap::new() + mutbl_map: @mut HashSet::new(), + root_map: @mut HashMap::new(), + last_use_map: @mut HashMap::new(), + method_map: @mut HashMap::new(), + vtable_map: @mut HashMap::new(), + write_guard_map: @mut HashSet::new(), + moves_map: @mut HashSet::new(), + capture_map: @mut HashMap::new() }; match csearch::maybe_get_item_ast(tcx, def_id, |a, b, c, d| astencode::decode_inlined_item(a, b, maps, /*bar*/ copy c, d)) { @@ -371,32 +371,31 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) expr_cast(base, _) => { let ety = ty::expr_ty(tcx, e); let base = eval_const_expr_partial(tcx, base); - match ty::get(ety).sty { - ty::ty_float(_) => { - match base { - Ok(const_uint(u)) => Ok(const_float(u as f64)), - Ok(const_int(i)) => Ok(const_float(i as f64)), - Ok(const_float(_)) => base, - _ => Err(~"Can't cast float to str") - } - } - ty::ty_uint(_) => { - match base { - Ok(const_uint(_)) => base, - Ok(const_int(i)) => Ok(const_uint(i as u64)), - Ok(const_float(f)) => Ok(const_uint(f as u64)), - _ => Err(~"Can't cast str to uint") - } - } - ty::ty_int(_) | ty::ty_bool => { - match base { - Ok(const_uint(u)) => Ok(const_int(u as i64)), - Ok(const_int(_)) => base, - Ok(const_float(f)) => Ok(const_int(f as i64)), - _ => Err(~"Can't cast str to int") + match /*bad*/copy base { + Err(_) => base, + Ok(val) => { + match ty::get(ety).sty { + ty::ty_float(_) => match val { + const_uint(u) => Ok(const_float(u as f64)), + const_int(i) => Ok(const_float(i as f64)), + const_float(_) => base, + _ => Err(~"Can't cast float to str"), + }, + ty::ty_uint(_) => match val { + const_uint(_) => base, + const_int(i) => Ok(const_uint(i as u64)), + const_float(f) => Ok(const_uint(f as u64)), + _ => Err(~"Can't cast str to uint"), + }, + ty::ty_int(_) | ty::ty_bool => match val { + const_uint(u) => Ok(const_int(u as i64)), + const_int(_) => base, + const_float(f) => Ok(const_int(f as i64)), + _ => Err(~"Can't cast str to int"), + }, + _ => Err(~"Can't cast this type") + } } - } - _ => Err(~"Can't cast this type") } } expr_path(_) => { diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index 19d3e1f431db2..e6e9f3be85d21 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -17,7 +17,7 @@ use core::prelude::*; use middle::resolve; use middle::ty; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use syntax::codemap::span; use syntax::{ast, ast_util, visit}; @@ -30,7 +30,7 @@ pub struct freevar_entry { span: span //< First span where it is accessed (there can be multiple) } pub type freevar_info = @~[@freevar_entry]; -pub type freevar_map = @mut LinearMap; +pub type freevar_map = @mut HashMap; // Searches through part of the AST for all references to locals or // upvars in this frame and returns the list of definition IDs thus found. @@ -39,7 +39,7 @@ pub type freevar_map = @mut LinearMap; // in order to start the search. fn collect_freevars(def_map: resolve::DefMap, blk: &ast::blk) -> freevar_info { - let seen = @mut LinearMap::new(); + let seen = @mut HashMap::new(); let refs = @mut ~[]; fn ignore_item(_i: @ast::item, &&_depth: int, _v: visit::vt) { } @@ -92,7 +92,7 @@ fn collect_freevars(def_map: resolve::DefMap, blk: &ast::blk) // one pass. This could be improved upon if it turns out to matter. pub fn annotate_freevars(def_map: resolve::DefMap, crate: @ast::crate) -> freevar_map { - let freevars = @mut LinearMap::new(); + let freevars = @mut HashMap::new(); let walk_fn: @fn(&visit::fn_kind, &ast::fn_decl, diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index a25e2f49e099e..e5fc9f2d60391 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -16,7 +16,7 @@ use middle::liveness; use middle::pat_util; use middle::ty; use middle::typeck; -use util::ppaux::{ty_to_str, tys_to_str}; +use util::ppaux::{Repr, ty_to_str}; use syntax::ast::*; use syntax::attr::attrs_contains_name; @@ -91,7 +91,7 @@ fn check_struct_safe_for_destructor(cx: Context, span: span, struct_did: def_id) { let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); - if struct_tpt.bounds.len() == 0 { + if !struct_tpt.generics.has_type_params() { let struct_ty = ty::mk_struct(cx.tcx, struct_did, ty::substs { self_r: None, self_ty: None, @@ -276,10 +276,10 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { for cx.tcx.node_type_substs.find(&type_parameter_id).each |ts| { // FIXME(#5562): removing this copy causes a segfault before stage2 let ts = /*bad*/ copy **ts; - let bounds = match e.node { + let type_param_defs = match e.node { expr_path(_) => { let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&e.id)); - ty::lookup_item_type(cx.tcx, did).bounds + ty::lookup_item_type(cx.tcx, did).generics.type_param_defs } _ => { // Type substitutions should only occur on paths and @@ -287,20 +287,20 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { // Even though the callee_id may have been the id with // node_type_substs, e.id is correct here. - ty::method_call_bounds(cx.tcx, cx.method_map, e.id).expect( + ty::method_call_type_param_defs(cx.tcx, cx.method_map, e.id).expect( ~"non path/method call expr has type substs??") } }; - if ts.len() != bounds.len() { + if ts.len() != type_param_defs.len() { // Fail earlier to make debugging easier fail!(fmt!("internal error: in kind::check_expr, length \ mismatch between actual and declared bounds: actual = \ - %s (%u tys), declared = %? (%u tys)", - tys_to_str(cx.tcx, ts), ts.len(), - *bounds, bounds.len())); + %s, declared = %s", + ts.repr(cx.tcx), + type_param_defs.repr(cx.tcx))); } - for vec::each2(ts, *bounds) |ty, bound| { - check_bounds(cx, type_parameter_id, e.span, *ty, *bound) + for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + check_bounds(cx, type_parameter_id, e.span, ty, type_param_def) } } @@ -340,9 +340,10 @@ fn check_ty(aty: @Ty, cx: Context, v: visit::vt) { // FIXME(#5562): removing this copy causes a segfault before stage2 let ts = /*bad*/ copy **ts; let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&id)); - let bounds = ty::lookup_item_type(cx.tcx, did).bounds; - for vec::each2(ts, *bounds) |ty, bound| { - check_bounds(cx, aty.id, aty.span, *ty, *bound) + let type_param_defs = + ty::lookup_item_type(cx.tcx, did).generics.type_param_defs; + for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + check_bounds(cx, aty.id, aty.span, ty, type_param_def) } } } @@ -355,11 +356,11 @@ pub fn check_bounds(cx: Context, _type_parameter_id: node_id, sp: span, ty: ty::t, - bounds: ty::param_bounds) + type_param_def: &ty::TypeParameterDef) { let kind = ty::type_contents(cx.tcx, ty); let mut missing = ~[]; - for bounds.each |bound| { + for type_param_def.bounds.each |bound| { match *bound { ty::bound_trait(_) => { /* Not our job, checking in typeck */ @@ -477,13 +478,13 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { } } -/// This is rather subtle. When we are casting a value to a -/// instantiated trait like `a as trait<'r>`, regionck already ensures -/// that any borrowed pointers that appear in the type of `a` are -/// bounded by `&r`. However, it is possible that there are *type -/// parameters* in the type of `a`, and those *type parameters* may -/// have borrowed pointers within them. We have to guarantee that the -/// regions which appear in those type parameters are not obscured. +/// This is rather subtle. When we are casting a value to a instantiated +/// trait like `a as trait<'r>`, regionck already ensures that any borrowed +/// pointers that appear in the type of `a` are bounded by `'r` (ed.: modulo +/// FIXME(#5723)). However, it is possible that there are *type parameters* +/// in the type of `a`, and those *type parameters* may have borrowed pointers +/// within them. We have to guarantee that the regions which appear in those +/// type parameters are not obscured. /// /// Therefore, we ensure that one of three conditions holds: /// @@ -500,6 +501,8 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { /// /// (3) The type parameter is owned (and therefore does not contain /// borrowed ptrs). +/// +/// FIXME(#5723)---This code should probably move into regionck. pub fn check_cast_for_escaping_regions( cx: Context, source: @expr, @@ -508,40 +511,78 @@ pub fn check_cast_for_escaping_regions( // Determine what type we are casting to; if it is not an trait, then no // worries. let target_ty = ty::expr_ty(cx.tcx, target); - let target_substs = match ty::get(target_ty).sty { - ty::ty_trait(_, ref substs, _) => {(/*bad*/copy *substs)} - _ => { return; /* not a cast to a trait */ } - }; + match ty::get(target_ty).sty { + ty::ty_trait(*) => {} + _ => { return; } + } + + // Collect up the regions that appear in the target type. We want to + // ensure that these lifetimes are shorter than all lifetimes that are in + // the source type. See test `src/test/compile-fail/regions-trait-2.rs` + let mut target_regions = ~[]; + ty::walk_regions_and_ty( + cx.tcx, + target_ty, + |r| { + if !r.is_bound() { + target_regions.push(r); + } + }, + |_| true); // Check, based on the region associated with the trait, whether it can // possibly escape the enclosing fn item (note that all type parameters - // must have been declared on the enclosing fn item): - match target_substs.self_r { - Some(ty::re_scope(*)) => { return; /* case (1) */ } - None | Some(ty::re_static) | Some(ty::re_free(*)) => {} - Some(ty::re_bound(*)) | Some(ty::re_infer(*)) => { - cx.tcx.sess.span_bug( - source.span, - fmt!("bad region found in kind: %?", target_substs.self_r)); - } + // must have been declared on the enclosing fn item). + if target_regions.any(|r| is_re_scope(*r)) { + return; /* case (1) */ } // Assuming the trait instance can escape, then ensure that each parameter - // either appears in the trait type or is owned: + // either appears in the trait type or is owned. let target_params = ty::param_tys_in_type(target_ty); let source_ty = ty::expr_ty(cx.tcx, source); - do ty::walk_ty(source_ty) |ty| { - match ty::get(ty).sty { - ty::ty_param(source_param) => { - if target_params.contains(&source_param) { - /* case (2) */ - } else { - check_durable(cx.tcx, ty, source.span); /* case (3) */ + ty::walk_regions_and_ty( + cx.tcx, + source_ty, + + |_r| { + // FIXME(#5723) --- turn this check on once &Objects are usable + // + // if !target_regions.any(|t_r| is_subregion_of(cx, *t_r, r)) { + // cx.tcx.sess.span_err( + // source.span, + // fmt!("source contains borrowed pointer with lifetime \ + // not found in the target type `%s`", + // ty_to_str(cx.tcx, target_ty))); + // note_and_explain_region( + // cx.tcx, "source data is only valid for ", r, ""); + // } + }, + + |ty| { + match ty::get(ty).sty { + ty::ty_param(source_param) => { + if target_params.contains(&source_param) { + /* case (2) */ + } else { + check_durable(cx.tcx, ty, source.span); /* case (3) */ + } + } + _ => {} } - } - _ => {} + true + }); + + fn is_re_scope(+r: ty::Region) -> bool { + match r { + ty::re_scope(*) => true, + _ => false } } + + fn is_subregion_of(cx: Context, r_sub: ty::Region, r_sup: ty::Region) -> bool { + cx.tcx.region_maps.is_subregion_of(r_sub, r_sup) + } } /// Ensures that values placed into a ~Trait are copyable and sendable. diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 566a52c3894d1..bacbeb851aa82 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -31,7 +31,7 @@ use syntax::ast_util::local_def; use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor}; use syntax::visit::visit_crate; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::ptr; pub enum LangItem { @@ -259,7 +259,7 @@ fn LanguageItemCollector<'r>(crate: @crate, session: Session, items: &'r mut LanguageItems) -> LanguageItemCollector<'r> { - let mut item_refs = LinearMap::new(); + let mut item_refs = HashMap::new(); item_refs.insert(@~"const", ConstTraitLangItem as uint); item_refs.insert(@~"copy", CopyTraitLangItem as uint); @@ -317,7 +317,7 @@ struct LanguageItemCollector<'self> { crate: @crate, session: Session, - item_refs: LinearMap<@~str, uint>, + item_refs: HashMap<@~str, uint>, } pub impl<'self> LanguageItemCollector<'self> { @@ -369,7 +369,7 @@ pub impl<'self> LanguageItemCollector<'self> { } fn collect_local_language_items(&self) { - let this = unsafe { ptr::addr_of(&self) }; + let this = ptr::addr_of(&self); visit_crate(*self.crate, (), mk_simple_visitor(@SimpleVisitor { visit_item: |item| { for item.attrs.each |attribute| { @@ -397,7 +397,7 @@ pub impl<'self> LanguageItemCollector<'self> { } fn check_completeness(&self) { - for self.item_refs.each |&(&key, &item_ref)| { + for self.item_refs.each |&key, &item_ref| { match self.items.items[item_ref] { None => { self.session.err(fmt!("no item found for `%s`", *key)); diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index ba232f55f74f6..876ed76f98741 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -15,7 +15,7 @@ use driver::session; use middle::ty; use util::ppaux::{ty_to_str}; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::char; use core::cmp; use core::i8; @@ -75,6 +75,7 @@ pub enum lint { default_methods, deprecated_mutable_fields, deprecated_drop, + unused_unsafe, foreign_mode, managed_heap_memory, @@ -83,9 +84,8 @@ pub enum lint { legacy_modes, - // FIXME(#3266)--make liveness warnings lintable - // unused_variable, - // dead_assignment + unused_variable, + dead_assignment, } pub fn level_to_str(lv: level) -> &'static str { @@ -108,7 +108,7 @@ struct LintSpec { default: level } -pub type LintDict = @LinearMap<~str, LintSpec>; +pub type LintDict = @HashMap<~str, LintSpec>; /* Pass names should not contain a '-', as the compiler normalizes @@ -257,23 +257,28 @@ pub fn get_lint_dict() -> LintDict { default: deny }), - /* FIXME(#3266)--make liveness warnings lintable - (@~"unused_variable", - @LintSpec { + (~"unused_unsafe", + LintSpec { + lint: unused_unsafe, + desc: "unnecessary use of an \"unsafe\" block or function", + default: warn + }), + + (~"unused_variable", + LintSpec { lint: unused_variable, desc: "detect variables which are not used in any way", default: warn - }), + }), - (@~"dead_assignment", - @LintSpec { + (~"dead_assignment", + LintSpec { lint: dead_assignment, desc: "detect assignments that will never be read", default: warn - }), - */ + }), ]; - let mut map = LinearMap::new(); + let mut map = HashMap::new(); do vec::consume(v) |_, (k, v)| { map.insert(k, v); } @@ -282,7 +287,7 @@ pub fn get_lint_dict() -> LintDict { // This is a highly not-optimal set of data structure decisions. type LintModes = @mut SmallIntMap; -type LintModeMap = @mut LinearMap; +type LintModeMap = @mut HashMap; // settings_map maps node ids of items with non-default lint settings // to their settings; default_settings contains the settings for everything @@ -295,7 +300,7 @@ pub struct LintSettings { pub fn mk_lint_settings() -> LintSettings { LintSettings { default_settings: @mut SmallIntMap::new(), - settings_map: @mut LinearMap::new() + settings_map: @mut HashMap::new() } } @@ -463,7 +468,7 @@ pub fn build_settings_crate(sess: session::Session, crate: @ast::crate) { do cx.with_lint_attrs(/*bad*/copy crate.node.attrs) |cx| { // Copy out the default settings - for cx.curr.each |&(k, &v)| { + for cx.curr.each |&k, &v| { sess.lint_settings.default_settings.insert(k, v); } @@ -493,6 +498,7 @@ fn check_item(i: @ast::item, cx: ty::ctxt) { check_item_default_methods(cx, i); check_item_deprecated_mutable_fields(cx, i); check_item_deprecated_drop(cx, i); + check_item_unused_unsafe(cx, i); } // Take a visitor, and modify it so that it will not proceed past subitems. @@ -825,8 +831,7 @@ fn check_item_heap(cx: ty::ctxt, it: @ast::item) { ast::item_fn(*) | ast::item_ty(*) | ast::item_enum(*) | - ast::item_struct(*) | - ast::item_trait(*) => check_type(cx, it.id, it.id, it.span, + ast::item_struct(*) => check_type(cx, it.id, it.id, it.span, ty::node_id_to_type(cx, it.id)), _ => () } @@ -927,19 +932,55 @@ fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) { } } +fn check_item_unused_unsafe(cx: ty::ctxt, it: @ast::item) { + 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"); + } + } + _ => () + } + }; + + let visit = item_stopping_visitor( + visit::mk_simple_visitor(@visit::SimpleVisitor { + visit_expr: visit_expr, + .. *visit::default_simple_visitor() + })); + visit::visit_item(it, (), visit); +} + fn check_fn(tcx: ty::ctxt, fk: &visit::fn_kind, decl: &ast::fn_decl, _body: &ast::blk, span: span, id: ast::node_id) { debug!("lint check_fn fk=%? id=%?", fk, id); - // don't complain about blocks, since they tend to get their modes - // specified from the outside + // Check for an 'unsafe fn' which doesn't need to be unsafe match *fk { - visit::fk_fn_block(*) => { return; } - _ => {} + visit::fk_item_fn(_, _, ast::unsafe_fn, _) => { + if !tcx.used_unsafe.contains(&id) { + tcx.sess.span_lint(unused_unsafe, id, id, span, + ~"unnecessary \"unsafe\" function"); + } + } + _ => () + } + + // Check for deprecated modes + match *fk { + // don't complain about blocks, since they tend to get their modes + // specified from the outside + visit::fk_fn_block(*) => {} + + _ => { + let fn_ty = ty::node_id_to_type(tcx, id); + check_fn_deprecated_modes(tcx, fn_ty, decl, span, id); + } } - let fn_ty = ty::node_id_to_type(tcx, id); - check_fn_deprecated_modes(tcx, fn_ty, decl, span, id); } fn check_fn_deprecated_modes(tcx: ty::ctxt, fn_ty: ty::t, decl: &ast::fn_decl, diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index e9e226d36d1f5..3a649e7cc3b2b 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -105,19 +105,21 @@ use core::prelude::*; +use middle::lint::{unused_variable, dead_assignment}; use middle::pat_util; use middle::ty; use middle::typeck; use middle::moves; use util::ppaux::ty_to_str; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::io::WriterUtil; use core::io; use core::ptr; use core::to_str; use core::uint; use core::vec; +use core::util::with; use syntax::ast::*; use syntax::codemap::span; use syntax::parse::token::special_idents; @@ -134,7 +136,7 @@ use syntax::{visit, ast_util}; // // Very subtle (#2633): borrowck will remove entries from this table // if it detects an outstanding loan (that is, the addr is taken). -pub type last_use_map = @mut LinearMap; +pub type last_use_map = @mut HashMap; #[deriving(Eq)] struct Variable(uint); @@ -169,15 +171,17 @@ 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 last_use_map = @mut LinearMap::new(); + let last_use_map = @mut HashMap::new(); let initial_maps = @mut IrMaps(tcx, method_map, variable_moves_map, capture_map, - last_use_map); + last_use_map, + 0); visit::visit_crate(*crate, initial_maps, visitor); tcx.sess.abort_if_errors(); return last_use_map; @@ -264,18 +268,21 @@ struct IrMaps { num_live_nodes: uint, num_vars: uint, - live_node_map: LinearMap, - variable_map: LinearMap, - capture_info_map: LinearMap, + live_node_map: HashMap, + variable_map: HashMap, + capture_info_map: HashMap, 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, - last_use_map: last_use_map) + last_use_map: last_use_map, + cur_item: node_id) -> IrMaps { IrMaps { tcx: tcx, @@ -285,11 +292,12 @@ fn IrMaps(tcx: ty::ctxt, last_use_map: last_use_map, num_live_nodes: 0, num_vars: 0, - live_node_map: LinearMap::new(), - variable_map: LinearMap::new(), - capture_info_map: LinearMap::new(), + live_node_map: HashMap::new(), + variable_map: HashMap::new(), + capture_info_map: HashMap::new(), var_kinds: ~[], - lnks: ~[] + lnks: ~[], + cur_item: cur_item, } } @@ -394,6 +402,12 @@ pub impl IrMaps { } } +fn visit_item(item: @item, &&self: @mut IrMaps, v: vt<@mut IrMaps>) { + do with(&mut self.cur_item, item.id) { + visit::visit_item(item, self, v) + } +} + fn visit_fn(fk: &visit::fn_kind, decl: &fn_decl, body: &blk, @@ -409,7 +423,8 @@ fn visit_fn(fk: &visit::fn_kind, self.method_map, self.variable_moves_map, self.capture_map, - self.last_use_map); + self.last_use_map, + self.cur_item); debug!("creating fn_maps: %x", ptr::addr_of(&(*fn_maps)) as uint); @@ -612,7 +627,7 @@ static ACC_READ: uint = 1u; static ACC_WRITE: uint = 2u; static ACC_USE: uint = 4u; -type LiveNodeMap = @mut LinearMap; +type LiveNodeMap = @mut HashMap; struct Liveness { tcx: ty::ctxt, @@ -639,8 +654,8 @@ fn Liveness(ir: @mut IrMaps, specials: Specials) -> Liveness { users: @mut vec::from_elem(ir.num_live_nodes * ir.num_vars, invalid_users()), loop_scope: @mut ~[], - break_ln: @mut LinearMap::new(), - cont_ln: @mut LinearMap::new() + break_ln: @mut HashMap::new(), + cont_ln: @mut HashMap::new() } } @@ -692,17 +707,19 @@ pub impl Liveness { } } - fn pat_bindings(&self, pat: @pat, f: &fn(LiveNode, Variable, span)) { + fn pat_bindings(&self, pat: @pat, + f: &fn(LiveNode, Variable, span, node_id)) { let def_map = self.tcx.def_map; do pat_util::pat_bindings(def_map, pat) |_bm, p_id, sp, _n| { let ln = self.live_node(p_id, sp); let var = self.variable(p_id, sp); - f(ln, var, sp); + f(ln, var, sp, p_id); } } fn arm_pats_bindings(&self, - pats: &[@pat], f: &fn(LiveNode, Variable, span)) { + pats: &[@pat], + f: &fn(LiveNode, Variable, span, node_id)) { // only consider the first pattern; any later patterns must have // the same bindings, and we also consider the first pattern to be // the "authoratative" set of ids @@ -718,7 +735,7 @@ pub impl Liveness { fn define_bindings_in_arm_pats(&self, pats: &[@pat], succ: LiveNode) -> LiveNode { let mut succ = succ; - do self.arm_pats_bindings(pats) |ln, var, _sp| { + do self.arm_pats_bindings(pats) |ln, var, _sp, _id| { self.init_from_succ(ln, succ); self.define(ln, var); succ = ln; @@ -1509,8 +1526,8 @@ fn check_local(local: @local, &&self: @Liveness, vt: vt<@Liveness>) { // should not be live at this point. debug!("check_local() with no initializer"); - do self.pat_bindings(local.node.pat) |ln, var, sp| { - if !self.warn_about_unused(sp, ln, var) { + do self.pat_bindings(local.node.pat) |ln, var, sp, id| { + if !self.warn_about_unused(sp, id, ln, var) { match self.live_on_exit(ln, var) { None => { /* not live: good */ } Some(lnk) => { @@ -1528,8 +1545,8 @@ fn check_local(local: @local, &&self: @Liveness, vt: vt<@Liveness>) { } fn check_arm(arm: &arm, &&self: @Liveness, vt: vt<@Liveness>) { - do self.arm_pats_bindings(arm.pats) |ln, var, sp| { - self.warn_about_unused(sp, ln, var); + do self.arm_pats_bindings(arm.pats) |ln, var, sp, id| { + self.warn_about_unused(sp, id, ln, var); } visit::visit_arm(arm, self, vt); } @@ -1691,14 +1708,14 @@ pub impl Liveness { let ln = self.live_node(expr.id, expr.span); let var = self.variable(nid, expr.span); self.check_for_reassignment(ln, var, expr.span); - self.warn_about_dead_assign(expr.span, ln, var); + self.warn_about_dead_assign(expr.span, expr.id, ln, var); } def => { match relevant_def(def) { Some(nid) => { let ln = self.live_node(expr.id, expr.span); let var = self.variable(nid, expr.span); - self.warn_about_dead_assign(expr.span, ln, var); + self.warn_about_dead_assign(expr.span, expr.id, ln, var); } None => {} } @@ -1715,7 +1732,7 @@ pub impl Liveness { } fn check_for_reassignments_in_pat(@self, pat: @pat) { - do self.pat_bindings(pat) |ln, var, sp| { + do self.pat_bindings(pat) |ln, var, sp, _id| { self.check_for_reassignment(ln, var, sp); } } @@ -1861,21 +1878,21 @@ pub impl Liveness { do pat_util::pat_bindings(self.tcx.def_map, arg.pat) |_bm, p_id, sp, _n| { let var = self.variable(p_id, sp); - self.warn_about_unused(sp, entry_ln, var); + self.warn_about_unused(sp, p_id, entry_ln, var); } } } fn warn_about_unused_or_dead_vars_in_pat(@self, pat: @pat) { - do self.pat_bindings(pat) |ln, var, sp| { - if !self.warn_about_unused(sp, ln, var) { - self.warn_about_dead_assign(sp, ln, var); + do self.pat_bindings(pat) |ln, var, sp, id| { + if !self.warn_about_unused(sp, id, ln, var) { + self.warn_about_dead_assign(sp, id, ln, var); } } } - fn warn_about_unused(@self, sp: span, ln: LiveNode, var: Variable) - -> bool { + fn warn_about_unused(@self, sp: span, id: node_id, + ln: LiveNode, var: Variable) -> bool { if !self.used_on_entry(ln, var) { for self.should_warn(var).each |name| { @@ -1889,14 +1906,14 @@ pub impl Liveness { }; if is_assigned { - // FIXME(#3266)--make liveness warnings lintable - self.tcx.sess.span_warn( - sp, fmt!("variable `%s` is assigned to, \ + self.tcx.sess.span_lint(unused_variable, id, + self.ir.cur_item, sp, + fmt!("variable `%s` is assigned to, \ but never used", **name)); } else { - // FIXME(#3266)--make liveness warnings lintable - self.tcx.sess.span_warn( - sp, fmt!("unused variable: `%s`", **name)); + self.tcx.sess.span_lint(unused_variable, id, + self.ir.cur_item, sp, + fmt!("unused variable: `%s`", **name)); } } return true; @@ -1904,12 +1921,12 @@ pub impl Liveness { return false; } - fn warn_about_dead_assign(@self, sp: span, ln: LiveNode, var: Variable) { + fn warn_about_dead_assign(@self, sp: span, id: node_id, + ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { for self.should_warn(var).each |name| { - // FIXME(#3266)--make liveness warnings lintable - self.tcx.sess.span_warn( - sp, + self.tcx.sess.span_lint(dead_assignment, id, + self.ir.cur_item, 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 b7ec6208d5607..6473cb8e8e006 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -462,7 +462,7 @@ pub impl mem_categorization_ctxt { ast::def_fn(*) | ast::def_static_method(*) | ast::def_mod(_) | ast::def_foreign_mod(_) | ast::def_const(_) | ast::def_use(_) | ast::def_variant(*) | - ast::def_ty(_) | ast::def_prim_ty(_) | + ast::def_trait(_) | ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*) | ast::def_struct(*) | ast::def_typaram_binder(*) | ast::def_region(_) | ast::def_label(_) | ast::def_self_ty(*) => { diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index a93618b66246f..1401d86123e64 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -211,11 +211,11 @@ use core::prelude::*; use middle::pat_util::{pat_bindings}; use middle::freevars; use middle::ty; -use middle::typeck::method_map; +use middle::typeck::{method_map}; use util::ppaux; use util::common::indenter; -use core::hashmap::linear::{LinearSet, LinearMap}; +use core::hashmap::{HashSet, HashMap}; use core::vec; use syntax::ast::*; use syntax::ast_util; @@ -240,14 +240,14 @@ pub struct CaptureVar { mode: CaptureMode // How variable is being accessed } -pub type CaptureMap = @mut LinearMap; +pub type CaptureMap = @mut HashMap; -pub type MovesMap = @mut LinearSet; +pub type MovesMap = @mut HashSet; /** * For each variable which will be moved, links to the * expression */ -pub type VariableMovesMap = @mut LinearMap; +pub type VariableMovesMap = @mut HashMap; /** See the section Output on the module comment for explanation. */ pub struct MoveMaps { @@ -280,9 +280,9 @@ pub fn compute_moves(tcx: ty::ctxt, tcx: tcx, method_map: method_map, move_maps: MoveMaps { - moves_map: @mut LinearSet::new(), - variable_moves_map: @mut LinearMap::new(), - capture_map: @mut LinearMap::new() + moves_map: @mut HashSet::new(), + variable_moves_map: @mut HashMap::new(), + capture_map: @mut HashMap::new() } }; visit::visit_crate(*crate, visit_cx, visitor); @@ -463,7 +463,7 @@ pub impl VisitContext { expr_method_call(callee, _, _, ref args, _) => { // callee.m(args) // Implicit self is equivalent to & mode, but every // other kind should be + mode. - self.use_receiver(expr.id, expr.span, callee, visitor); + self.use_receiver(callee, visitor); self.use_fn_args(expr.callee_id, *args, visitor); } @@ -665,7 +665,7 @@ pub impl VisitContext { return false; } - self.use_receiver(expr.id, expr.span, receiver_expr, visitor); + self.use_receiver(receiver_expr, visitor); // for overloaded operatrs, we are always passing in a // borrowed pointer, so it's always read mode: @@ -718,8 +718,6 @@ pub impl VisitContext { } fn use_receiver(&self, - _expr_id: node_id, - _span: span, receiver_expr: @expr, visitor: vt) { diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 0e47dabcce900..df0e508398ee4 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -12,17 +12,17 @@ use core::prelude::*; use middle::resolve; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use syntax::ast::*; use syntax::ast_util::{path_to_ident, walk_pat}; use syntax::codemap::span; -pub type PatIdMap = LinearMap; +pub type PatIdMap = HashMap; // This is used because same-named variables in alternative patterns need to // use the node_id of their namesake in the first pattern. pub fn pat_id_map(dm: resolve::DefMap, pat: @pat) -> PatIdMap { - let mut map = LinearMap::new(); + let mut map = HashMap::new(); do pat_bindings(dm, pat) |_bm, p_id, _s, n| { map.insert(path_to_ident(n), p_id); }; @@ -72,7 +72,7 @@ pub fn pat_is_binding_or_wild(dm: resolve::DefMap, pat: @pat) -> bool { } pub fn pat_bindings(dm: resolve::DefMap, pat: @pat, - it: &fn(binding_mode, node_id, span, @path)) { + it: &fn(binding_mode, node_id, span, @Path)) { do walk_pat(pat) |p| { match p.node { pat_ident(binding_mode, pth, _) if pat_is_binding(dm, p) => { diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 50e8ed23446de..e59ca9e658123 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -26,7 +26,7 @@ use syntax::ast::{decl_item, def, def_fn, def_id, def_static_method}; use syntax::ast::{def_variant, expr_field, expr_method_call, expr_path}; use syntax::ast::{expr_struct, expr_unary, ident, inherited, item_enum}; use syntax::ast::{item_foreign_mod, item_fn, item_impl, item_struct}; -use syntax::ast::{item_trait, local_crate, node_id, pat_struct, path}; +use syntax::ast::{item_trait, local_crate, node_id, pat_struct, Path}; use syntax::ast::{private, provided, public, required, stmt_decl, visibility}; use syntax::ast; use syntax::ast_map::{node_foreign_item, node_item, node_method}; @@ -276,7 +276,7 @@ pub fn check_crate(tcx: ty::ctxt, }; // Checks that a private path is in scope. - let check_path: @fn(span: span, def: def, path: @path) = + let check_path: @fn(span: span, def: def, path: @Path) = |span, def, path| { debug!("checking path"); match def { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index f6025548d71c0..ecb9fc2cd08b8 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -11,7 +11,7 @@ /*! This file actually contains two passes related to regions. The first -pass builds up the `region_map`, which describes the parent links in +pass builds up the `scope_map`, which describes the parent links in the region hierarchy. The second pass infers which types must be region parameterized. @@ -23,10 +23,10 @@ use driver::session::Session; use metadata::csearch; use middle::resolve; use middle::ty::{region_variance, rv_covariant, rv_invariant}; -use middle::ty::{rv_contravariant}; +use middle::ty::{rv_contravariant, FreeRegion}; use middle::ty; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::vec; use syntax::ast_map; use syntax::codemap::span; @@ -37,23 +37,31 @@ use syntax::{ast, visit}; pub type parent = Option; /** -Encodes the bounding lifetime for a given AST node: - -- Expressions are mapped to the expression or block encoding the maximum - (static) lifetime of a value produced by that expression. This is - generally the innermost call, statement, match, or block. - -- Variables and bindings are mapped to the block in which they are declared. - +The region maps encode information about region relationships. + +- `scope_map` maps from: + - an expression to the expression or block encoding the maximum + (static) lifetime of a value produced by that expression. This is + generally the innermost call, statement, match, or block. + - a variable or binding id to the block in which that variable is declared. +- `free_region_map` maps from: + - a free region `a` to a list of free regions `bs` such that + `a <= b for all b in bs` + - the free region map is populated during type check as we check + each function. See the function `relate_free_regions` for + more information. */ -pub type region_map = @mut LinearMap; +pub struct RegionMaps { + priv scope_map: HashMap, + priv free_region_map: HashMap, +} pub struct ctxt { sess: Session, def_map: resolve::DefMap, // Generated maps: - region_map: region_map, + region_maps: @mut RegionMaps, // Generally speaking, expressions are parented to their innermost // enclosing block. But some kinds of expressions serve as @@ -62,7 +70,7 @@ pub struct ctxt { // the condition in a while loop is always a parent. In those // cases, we add the node id of such an expression to this set so // that when we visit it we can view it as a parent. - root_exprs: @mut LinearSet, + root_exprs: @mut HashSet, // The parent scope is the innermost block, statement, call, or match // expression during the execution of which the current expression @@ -98,94 +106,215 @@ pub struct ctxt { parent: parent, } -/// Returns true if `subscope` is equal to or is lexically nested inside -/// `superscope` and false otherwise. -pub fn scope_contains(region_map: region_map, superscope: ast::node_id, - subscope: ast::node_id) -> bool { - let mut subscope = subscope; - while superscope != subscope { - match region_map.find(&subscope) { - None => return false, - Some(&scope) => subscope = scope +pub impl RegionMaps { + fn relate_free_regions(&mut self, + sub: FreeRegion, + sup: FreeRegion) + { + match self.free_region_map.find_mut(&sub) { + Some(sups) => { + if !sups.contains(&sup) { + sups.push(sup); + } + return; + } + None => {} } + + debug!("relate_free_regions(sub=%?, sup=%?)", sub, sup); + + self.free_region_map.insert(sub, ~[sup]); } - return true; -} -/// Determines whether one region is a subregion of another. This is -/// intended to run *after inference* and sadly the logic is somewhat -/// duplicated with the code in infer.rs. -pub fn is_subregion_of(region_map: region_map, - sub_region: ty::Region, - super_region: ty::Region) -> bool { - sub_region == super_region || - match (sub_region, super_region) { - (_, ty::re_static) => { - true - } + fn record_parent(&mut self, + sub: ast::node_id, + sup: ast::node_id) + { + debug!("record_parent(sub=%?, sup=%?)", sub, sup); - (ty::re_scope(sub_scope), ty::re_scope(super_scope)) | - (ty::re_scope(sub_scope), ty::re_free(super_scope, _)) => { - scope_contains(region_map, super_scope, sub_scope) - } + self.scope_map.insert(sub, sup); + } - _ => { - false + fn opt_encl_scope(&self, + id: ast::node_id) -> Option + { + //! Returns the narrowest scope that encloses `id`, if any. + + self.scope_map.find(&id).map(|&x| *x) + } + + fn encl_scope(&self, + id: ast::node_id) -> ast::node_id + { + //! Returns the narrowest scope that encloses `id`, if any. + + match self.scope_map.find(&id) { + Some(&r) => r, + None => { fail!(fmt!("No enclosing scope for id %?", id)); } + } + } + + fn encl_region(&self, + id: ast::node_id) -> ty::Region + { + //! Returns the narrowest scope region that encloses `id`, if any. + + ty::re_scope(self.encl_scope(id)) + } + + fn is_sub_scope(&self, + sub_scope: ast::node_id, + superscope: ast::node_id) -> bool + { + /*! + * Returns true if `sub_scope` is equal to or is lexically + * nested inside `superscope` and false otherwise. + */ + + let mut sub_scope = sub_scope; + while superscope != sub_scope { + match self.scope_map.find(&sub_scope) { + None => return false, + Some(&scope) => sub_scope = scope } } -} + return true; + } -/// Finds the nearest common ancestor (if any) of two scopes. That -/// is, finds the smallest scope which is greater than or equal to -/// both `scope_a` and `scope_b`. -pub fn nearest_common_ancestor(region_map: region_map, - scope_a: ast::node_id, - scope_b: ast::node_id) - -> Option { + fn sub_free_region(&self, + sub: FreeRegion, + sup: FreeRegion) -> bool + { + /*! + * Determines whether two free regions have a subregion relationship + * by walking the graph encoded in `free_region_map`. Note that + * it is possible that `sub != sup` and `sub <= sup` and `sup <= sub` + * (that is, the user can give two different names to the same lifetime). + */ + + if sub == sup { + return true; + } - fn ancestors_of(region_map: region_map, scope: ast::node_id) - -> ~[ast::node_id] { - let mut result = ~[scope]; - let mut scope = scope; - loop { - match region_map.find(&scope) { - None => return result, - Some(&superscope) => { - result.push(superscope); - scope = superscope; + // Do a little breadth-first-search here. The `queue` list + // doubles as a way to detect if we've seen a particular FR + // before. Note that we expect this graph to be an *extremely + // shallow* tree. + let mut queue = ~[sub]; + let mut i = 0; + while i < queue.len() { + match self.free_region_map.find(&queue[i]) { + Some(parents) => { + for parents.each |parent| { + if *parent == sup { + return true; + } + + if !queue.contains(parent) { + queue.push(*parent); + } + } } + None => {} } + i += 1; } + return false; } - if scope_a == scope_b { return Some(scope_a); } + fn is_subregion_of(&self, + sub_region: ty::Region, + super_region: ty::Region) -> bool + { + /*! + * Determines whether one region is a subregion of another. This is + * intended to run *after inference* and sadly the logic is somewhat + * duplicated with the code in infer.rs. + */ + + debug!("is_subregion_of(sub_region=%?, super_region=%?)", + sub_region, super_region); + + sub_region == super_region || { + match (sub_region, super_region) { + (_, ty::re_static) => { + true + } - let a_ancestors = ancestors_of(region_map, scope_a); - let b_ancestors = ancestors_of(region_map, scope_b); - let mut a_index = vec::len(a_ancestors) - 1u; - let mut b_index = vec::len(b_ancestors) - 1u; + (ty::re_scope(sub_scope), ty::re_scope(super_scope)) => { + self.is_sub_scope(sub_scope, super_scope) + } - // Here, ~[ab]_ancestors is a vector going from narrow to broad. - // The end of each vector will be the item where the scope is - // defined; if there are any common ancestors, then the tails of - // the vector will be the same. So basically we want to walk - // backwards from the tail of each vector and find the first point - // where they diverge. If one vector is a suffix of the other, - // then the corresponding scope is a superscope of the other. + (ty::re_scope(sub_scope), ty::re_free(ref fr)) => { + self.is_sub_scope(sub_scope, fr.scope_id) + } + + (ty::re_free(sub_fr), ty::re_free(super_fr)) => { + self.sub_free_region(sub_fr, super_fr) + } - if a_ancestors[a_index] != b_ancestors[b_index] { - return None; + _ => { + false + } + } + } } - loop { - // Loop invariant: a_ancestors[a_index] == b_ancestors[b_index] - // for all indices between a_index and the end of the array - if a_index == 0u { return Some(scope_a); } - if b_index == 0u { return Some(scope_b); } - a_index -= 1u; - b_index -= 1u; + fn nearest_common_ancestor(&self, + scope_a: ast::node_id, + scope_b: ast::node_id) -> Option + { + /*! + * Finds the nearest common ancestor (if any) of two scopes. That + * is, finds the smallest scope which is greater than or equal to + * both `scope_a` and `scope_b`. + */ + + if scope_a == scope_b { return Some(scope_a); } + + let a_ancestors = ancestors_of(self, scope_a); + let b_ancestors = ancestors_of(self, scope_b); + let mut a_index = vec::len(a_ancestors) - 1u; + let mut b_index = vec::len(b_ancestors) - 1u; + + // Here, ~[ab]_ancestors is a vector going from narrow to broad. + // The end of each vector will be the item where the scope is + // defined; if there are any common ancestors, then the tails of + // the vector will be the same. So basically we want to walk + // backwards from the tail of each vector and find the first point + // where they diverge. If one vector is a suffix of the other, + // then the corresponding scope is a superscope of the other. + if a_ancestors[a_index] != b_ancestors[b_index] { - return Some(a_ancestors[a_index + 1u]); + return None; + } + + loop { + // Loop invariant: a_ancestors[a_index] == b_ancestors[b_index] + // for all indices between a_index and the end of the array + if a_index == 0u { return Some(scope_a); } + if b_index == 0u { return Some(scope_b); } + a_index -= 1u; + b_index -= 1u; + if a_ancestors[a_index] != b_ancestors[b_index] { + return Some(a_ancestors[a_index + 1u]); + } + } + + fn ancestors_of(self: &RegionMaps, scope: ast::node_id) + -> ~[ast::node_id] + { + let mut result = ~[scope]; + let mut scope = scope; + loop { + match self.scope_map.find(&scope) { + None => return result, + Some(&superscope) => { + result.push(superscope); + scope = superscope; + } + } + } } } } @@ -205,8 +334,7 @@ pub fn parent_id(cx: ctxt, span: span) -> ast::node_id { /// Records the current parent (if any) as the parent of `child_id`. pub fn record_parent(cx: ctxt, child_id: ast::node_id) { for cx.parent.each |parent_id| { - debug!("parent of node %d is node %d", child_id, *parent_id); - cx.region_map.insert(child_id, *parent_id); + cx.region_maps.record_parent(child_id, *parent_id); } } @@ -328,7 +456,7 @@ pub fn resolve_fn(fk: &visit::fn_kind, // Record the ID of `self`. match *fk { visit::fk_method(_, _, method) => { - cx.region_map.insert(method.self_id, body.node.id); + cx.region_maps.record_parent(method.self_id, body.node.id); } _ => {} } @@ -338,7 +466,7 @@ pub fn resolve_fn(fk: &visit::fn_kind, body.node.id, cx.parent, fn_cx.parent); for decl.inputs.each |input| { - cx.region_map.insert(input.id, body.node.id); + cx.region_maps.record_parent(input.id, body.node.id); } visit::visit_fn(fk, decl, body, sp, id, fn_cx, visitor); @@ -346,12 +474,16 @@ pub fn resolve_fn(fk: &visit::fn_kind, pub fn resolve_crate(sess: Session, def_map: resolve::DefMap, - crate: @ast::crate) - -> region_map { + crate: @ast::crate) -> @mut RegionMaps +{ + let region_maps = @mut RegionMaps { + scope_map: HashMap::new(), + free_region_map: HashMap::new() + }; let cx: ctxt = ctxt {sess: sess, def_map: def_map, - region_map: @mut LinearMap::new(), - root_exprs: @mut LinearSet::new(), + region_maps: region_maps, + root_exprs: @mut HashSet::new(), parent: None}; let visitor = visit::mk_vt(@visit::Visitor { visit_block: resolve_block, @@ -365,7 +497,7 @@ pub fn resolve_crate(sess: Session, .. *visit::default_visitor() }); visit::visit_crate(*crate, cx, visitor); - return cx.region_map; + return region_maps; } // ___________________________________________________________________________ @@ -387,7 +519,7 @@ pub fn resolve_crate(sess: Session, // a worklist. We can then process the worklist, propagating indirect // dependencies until a fixed point is reached. -pub type region_paramd_items = @mut LinearMap; +pub type region_paramd_items = @mut HashMap; #[deriving(Eq)] pub struct region_dep { @@ -395,7 +527,7 @@ pub struct region_dep { id: ast::node_id } -pub type dep_map = @mut LinearMap; +pub type dep_map = @mut HashMap; pub struct DetermineRpCtxt { sess: Session, @@ -412,10 +544,6 @@ pub struct DetermineRpCtxt { // see long discussion on region_is_relevant(). anon_implies_rp: bool, - // true when we are not within an &self method. - // see long discussion on region_is_relevant(). - self_implies_rp: bool, - // encodes the context of the current type; invariant if // mutable, covariant otherwise ambient_variance: region_variance, @@ -557,7 +685,7 @@ pub impl DetermineRpCtxt { false } Some(ref l) if l.ident == special_idents::self_ => { - self.self_implies_rp + true } Some(_) => { false @@ -568,23 +696,18 @@ pub impl DetermineRpCtxt { fn with(@mut self, item_id: ast::node_id, anon_implies_rp: bool, - self_implies_rp: bool, f: &fn()) { let old_item_id = self.item_id; let old_anon_implies_rp = self.anon_implies_rp; - let old_self_implies_rp = self.self_implies_rp; self.item_id = item_id; self.anon_implies_rp = anon_implies_rp; - self.self_implies_rp = self_implies_rp; - debug!("with_item_id(%d, %b, %b)", + debug!("with_item_id(%d, %b)", item_id, - anon_implies_rp, - self_implies_rp); + anon_implies_rp); let _i = ::util::common::indenter(); f(); self.item_id = old_item_id; self.anon_implies_rp = old_anon_implies_rp; - self.self_implies_rp = old_self_implies_rp; } fn with_ambient_variance(@mut self, variance: region_variance, f: &fn()) { @@ -598,7 +721,7 @@ pub impl DetermineRpCtxt { pub fn determine_rp_in_item(item: @ast::item, &&cx: @mut DetermineRpCtxt, visitor: visit::vt<@mut DetermineRpCtxt>) { - do cx.with(item.id, true, true) { + do cx.with(item.id, true) { visit::visit_item(item, cx, visitor); } } @@ -610,12 +733,7 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind, _: ast::node_id, &&cx: @mut DetermineRpCtxt, visitor: visit::vt<@mut DetermineRpCtxt>) { - let self_implies_rp = match fk { - &visit::fk_method(_, _, m) => !m.self_ty.node.is_borrowed(), - _ => true - }; - - do cx.with(cx.item_id, false, self_implies_rp) { + do cx.with(cx.item_id, false) { do cx.with_ambient_variance(rv_contravariant) { for decl.inputs.each |a| { (visitor.visit_ty)(a.ty, cx, visitor); @@ -631,7 +749,7 @@ pub fn determine_rp_in_fn(fk: &visit::fn_kind, pub fn determine_rp_in_ty_method(ty_m: &ast::ty_method, &&cx: @mut DetermineRpCtxt, visitor: visit::vt<@mut DetermineRpCtxt>) { - do cx.with(cx.item_id, false, !ty_m.self_ty.node.is_borrowed()) { + do cx.with(cx.item_id, false) { visit::visit_ty_method(ty_m, cx, visitor); } } @@ -690,7 +808,9 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, match ty.node { ast::ty_path(path, id) => { match cx.def_map.find(&id) { - Some(&ast::def_ty(did)) | Some(&ast::def_struct(did)) => { + Some(&ast::def_ty(did)) | + Some(&ast::def_trait(did)) | + Some(&ast::def_struct(did)) => { if did.crate == ast::local_crate { if cx.region_is_relevant(path.rp) { cx.add_dep(did.node); @@ -734,7 +854,7 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, ast::ty_bare_fn(@ast::TyBareFn {decl: ref decl, _}) => { // fn() binds the & region, so do not consider &T types that // appear *inside* a fn() type to affect the enclosing item: - do cx.with(cx.item_id, false, true) { + do cx.with(cx.item_id, false) { // parameters are contravariant do cx.with_ambient_variance(rv_contravariant) { for decl.inputs.each |a| { @@ -790,12 +910,11 @@ pub fn determine_rp_in_crate(sess: Session, sess: sess, ast_map: ast_map, def_map: def_map, - region_paramd_items: @mut LinearMap::new(), - dep_map: @mut LinearMap::new(), + region_paramd_items: @mut HashMap::new(), + dep_map: @mut HashMap::new(), worklist: ~[], item_id: 0, anon_implies_rp: false, - self_implies_rp: true, ambient_variance: rv_covariant }; @@ -840,7 +959,7 @@ pub fn determine_rp_in_crate(sess: Session, debug!("%s", { debug!("Region variance results:"); let region_paramd_items = cx.region_paramd_items; - for region_paramd_items.each |&(&key, &value)| { + for region_paramd_items.each |&key, &value| { debug!("item %? (%s) is parameterized with variance %?", key, ast_map::node_id_to_str(ast_map, key, diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 70d9dfacb6940..b2225963d2c33 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -12,13 +12,14 @@ use core::prelude::*; use driver::session; use driver::session::Session; -use metadata::csearch::{each_path, get_method_names_if_trait}; +use metadata::csearch::{each_path, get_trait_method_def_ids}; +use metadata::csearch::get_method_name_and_self_ty; use metadata::csearch::get_static_methods_if_impl; 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::{deny, allow, forbid, level, unused_imports, warn}; +use middle::lint::{allow, level, unused_imports}; use middle::lint::{get_lint_level, get_lint_settings_level}; use middle::pat_util::pat_bindings; @@ -31,7 +32,7 @@ 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}; +use syntax::ast::{def_ty_param, def_typaram_binder, def_trait}; use syntax::ast::{def_upvar, def_use, def_variant, 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}; @@ -47,7 +48,7 @@ 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, mode, 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::{Path, pat_lit, pat_range, pat_struct}; use syntax::ast::{prim_ty, private, provided}; use syntax::ast::{public, required, rem, self_ty_, shl, shr, stmt_decl}; use syntax::ast::{struct_dtor, struct_field, struct_variant_kind}; @@ -77,10 +78,11 @@ use syntax::opt_vec::OptVec; use core::option::Some; use core::str::each_split_str; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; +use core::util; // Definition mapping -pub type DefMap = @mut LinearMap; +pub type DefMap = @mut HashMap; pub struct binding_info { span: span, @@ -88,7 +90,7 @@ pub struct binding_info { } // Map from the name in a pattern to its binding mode. -pub type BindingMap = LinearMap; +pub type BindingMap = HashMap; // Implementation resolution // @@ -109,11 +111,11 @@ pub struct Impl { } // Trait method resolution -pub type TraitMap = LinearMap; +pub type TraitMap = HashMap; // This is the replacement export map. It maps a module to all of the exports // within. -pub type ExportMap2 = @mut LinearMap; +pub type ExportMap2 = @mut HashMap; pub struct Export2 { name: @~str, // The name of the target. @@ -328,13 +330,13 @@ pub fn namespace_for_duplicate_checking_mode(mode: DuplicateCheckingMode) /// One local scope. pub struct Rib { - bindings: @mut LinearMap, + bindings: @mut HashMap, kind: RibKind, } pub fn Rib(kind: RibKind) -> Rib { Rib { - bindings: @mut LinearMap::new(), + bindings: @mut HashMap::new(), kind: kind } } @@ -450,12 +452,12 @@ pub struct Module { def_id: Option, kind: ModuleKind, - children: @mut LinearMap, + children: @mut HashMap, imports: @mut ~[@ImportDirective], // The external module children of this node that were declared with // `extern mod`. - external_module_children: @mut LinearMap, + external_module_children: @mut HashMap, // The anonymous children of this node. Anonymous children are pseudo- // modules that are implicitly created around items contained within @@ -472,10 +474,10 @@ pub struct Module { // There will be an anonymous module created around `g` with the ID of the // entry block for `f`. - anonymous_children: @mut LinearMap, + anonymous_children: @mut HashMap, // The status of resolving each import in this module. - import_resolutions: @mut LinearMap, + import_resolutions: @mut HashMap, // The number of unresolved globs that this module exports. glob_count: uint, @@ -492,11 +494,11 @@ pub fn Module(parent_link: ParentLink, parent_link: parent_link, def_id: def_id, kind: kind, - children: @mut LinearMap::new(), + children: @mut HashMap::new(), imports: @mut ~[], - external_module_children: @mut LinearMap::new(), - anonymous_children: @mut LinearMap::new(), - import_resolutions: @mut LinearMap::new(), + external_module_children: @mut HashMap::new(), + anonymous_children: @mut HashMap::new(), + import_resolutions: @mut HashMap::new(), glob_count: 0, resolved_import_count: 0 } @@ -707,7 +709,7 @@ pub fn NameBindings() -> NameBindings { /// Interns the names of the primitive types. pub struct PrimitiveTypeTable { - primitive_types: LinearMap, + primitive_types: HashMap, } pub impl PrimitiveTypeTable { @@ -720,7 +722,7 @@ pub impl PrimitiveTypeTable { pub fn PrimitiveTypeTable(intr: @ident_interner) -> PrimitiveTypeTable { let mut table = PrimitiveTypeTable { - primitive_types: LinearMap::new() + primitive_types: HashMap::new() }; table.intern(intr, @~"bool", ty_bool); @@ -775,8 +777,8 @@ pub fn Resolver(session: Session, graph_root: graph_root, - trait_info: LinearMap::new(), - structs: LinearSet::new(), + trait_info: HashMap::new(), + structs: HashSet::new(), unresolved_imports: 0, @@ -799,9 +801,11 @@ pub fn Resolver(session: Session, attr_main_fn: None, main_fns: ~[], - def_map: @mut LinearMap::new(), - export_map2: @mut LinearMap::new(), - trait_map: LinearMap::new(), + start_fn: None, + + def_map: @mut HashMap::new(), + export_map2: @mut HashMap::new(), + trait_map: HashMap::new(), intr: session.intr() }; @@ -819,8 +823,8 @@ pub struct Resolver { graph_root: @mut NameBindings, - trait_info: LinearMap>, - structs: LinearSet, + trait_info: HashMap>, + structs: HashSet, // The number of imports that are currently unresolved. unresolved_imports: uint, @@ -858,9 +862,13 @@ pub struct Resolver { // The function that has attribute named 'main' attr_main_fn: Option<(node_id, span)>, - // The functions named 'main' + + // The functions that could be main functions main_fns: ~[Option<(node_id, span)>], + // The function that has the attribute 'start' on it + start_fn: Option<(node_id, span)>, + def_map: DefMap, export_map2: ExportMap2, trait_map: TraitMap, @@ -1309,7 +1317,7 @@ pub impl Resolver { } // Add the names of all the methods to the trait info. - let mut method_names = LinearSet::new(); + let mut method_names = HashSet::new(); for methods.each |method| { let ty_m = trait_method_to_ty_method(method); @@ -1341,7 +1349,7 @@ pub impl Resolver { let def_id = local_def(item.id); self.trait_info.insert(def_id, method_names); - name_bindings.define_type(privacy, def_ty(def_id), sp); + name_bindings.define_type(privacy, def_trait(def_id), sp); visit_item(item, new_parent, visitor); } @@ -1543,7 +1551,7 @@ pub impl Resolver { fn handle_external_def(@mut self, def: def, - modules: &mut LinearMap, + modules: &mut HashMap, child_name_bindings: @mut NameBindings, final_ident: &str, ident: ident, @@ -1611,36 +1619,40 @@ pub impl Resolver { crate) building value %s", final_ident); child_name_bindings.define_value(Public, def, dummy_sp()); } - def_ty(def_id) => { - debug!("(building reduced graph for external \ - crate) building type %s", final_ident); - - // If this is a trait, add all the method names - // to the trait info. - - match get_method_names_if_trait(self.session.cstore, def_id) { - None => { - // Nothing to do. - } - Some(method_names) => { - let mut interned_method_names = LinearSet::new(); - for method_names.each |method_data| { - let (method_name, self_ty) = *method_data; - debug!("(building reduced graph for \ - external crate) ... adding \ - trait method '%s'", - *self.session.str_of(method_name)); - - // Add it to the trait info if not static. - if self_ty != sty_static { - interned_method_names.insert(method_name); - } - } - self.trait_info.insert(def_id, interned_method_names); + def_trait(def_id) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + // If this is a trait, add all the method names + // to the trait info. + + let method_def_ids = get_trait_method_def_ids(self.session.cstore, + def_id); + let mut interned_method_names = HashSet::new(); + for method_def_ids.each |&method_def_id| { + let (method_name, self_ty) = + get_method_name_and_self_ty(self.session.cstore, + method_def_id); + + debug!("(building reduced graph for \ + external crate) ... adding \ + trait method '%s'", + *self.session.str_of(method_name)); + + // Add it to the trait info if not static. + if self_ty != sty_static { + interned_method_names.insert(method_name); + } } - } + self.trait_info.insert(def_id, interned_method_names); - child_name_bindings.define_type(Public, def, dummy_sp()); + child_name_bindings.define_type(Public, def, dummy_sp()); + } + def_ty(_) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + child_name_bindings.define_type(Public, def, dummy_sp()); } def_struct(def_id) => { debug!("(building reduced graph for external \ @@ -1663,7 +1675,7 @@ pub impl Resolver { * crate. */ fn build_reduced_graph_for_external_crate(@mut self, root: @mut Module) { - let mut modules = LinearMap::new(); + let mut modules = HashMap::new(); // Create all the items reachable by paths. for each_path(self.session.cstore, root.def_id.get().crate) @@ -2363,7 +2375,7 @@ pub impl Resolver { // Add all resolved imports from the containing module. for containing_module.import_resolutions.each - |&(ident, target_import_resolution)| { + |ident, target_import_resolution| { debug!("(resolving glob import) writing module resolution \ %? into `%s`", @@ -2451,13 +2463,13 @@ pub impl Resolver { }; // Add all children from the containing module. - for containing_module.children.each |&(ident, name_bindings)| { + for containing_module.children.each |ident, name_bindings| { merge_import_resolution(ident, *name_bindings); } // Add external module children from the containing module. for containing_module.external_module_children.each - |&(ident, module)| { + |ident, module| { let name_bindings = @mut Resolver::create_name_bindings_from_module(*module); merge_import_resolution(ident, name_bindings); @@ -3105,7 +3117,7 @@ pub impl Resolver { fn add_exports_for_module(@mut self, exports2: &mut ~[Export2], module_: @mut Module) { - for module_.children.each |&(ident, namebindings)| { + for module_.children.each |ident, namebindings| { debug!("(computing exports) maybe export '%s'", *self.session.str_of(*ident)); self.add_exports_of_namebindings(&mut *exports2, @@ -3120,7 +3132,7 @@ pub impl Resolver { false); } - for module_.import_resolutions.each |&(ident, importresolution)| { + for module_.import_resolutions.each |ident, importresolution| { if importresolution.privacy != Public { debug!("(computing exports) not reexporting private `%s`", *self.session.str_of(*ident)); @@ -3409,7 +3421,6 @@ pub impl Resolver { self_type, ref methods) => { self.resolve_implementation(item.id, - item.span, generics, implemented_traits, self_type, @@ -3533,6 +3544,7 @@ pub impl Resolver { item_fn(ref fn_decl, _, _, ref generics, ref block) => { // If this is the main function, we must record it in the // session. + // FIXME #4404 android JNI hacks if !*self.session.building_library || self.session.targ_cfg.os == session::os_android { @@ -3552,6 +3564,16 @@ pub impl Resolver { ~"multiple 'main' functions"); } } + + if attrs_contains_name(item.attrs, ~"start") { + if self.start_fn.is_none() { + self.start_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + ~"multiple 'start' functions"); + } + } } self.resolve_function(OpaqueFunctionRibKind, @@ -3718,13 +3740,30 @@ pub impl Resolver { for type_parameters.each |type_parameter| { for type_parameter.bounds.each |&bound| { match bound { - TraitTyParamBound(ty) => self.resolve_type(ty, visitor), + TraitTyParamBound(tref) => { + self.resolve_trait_reference(tref, visitor) + } RegionTyParamBound => {} } } } } + fn resolve_trait_reference(@mut self, + trait_reference: &trait_ref, + visitor: ResolveVisitor) { + match self.resolve_path(trait_reference.path, TypeNS, true, visitor) { + None => { + self.session.span_err(trait_reference.path.span, + ~"attempt to implement an \ + unknown trait"); + } + Some(def) => { + self.record_def(trait_reference.ref_id, def); + } + } + } + fn resolve_struct(@mut self, id: node_id, generics: &Generics, @@ -3792,7 +3831,6 @@ pub impl Resolver { fn resolve_implementation(@mut self, id: node_id, - span: span, generics: &Generics, opt_trait_reference: Option<@trait_ref>, self_type: @Ty, @@ -3811,25 +3849,16 @@ pub impl Resolver { let original_trait_refs; match opt_trait_reference { Some(trait_reference) => { - let mut new_trait_refs = ~[]; - match self.resolve_path( - trait_reference.path, TypeNS, true, visitor) { - None => { - self.session.span_err(span, - ~"attempt to implement an \ - unknown trait"); - } - Some(def) => { - self.record_def(trait_reference.ref_id, def); + self.resolve_trait_reference(trait_reference, visitor); - // Record the current trait reference. - new_trait_refs.push(def_id_of_def(def)); - } - } // Record the current set of trait references. - let mut old = Some(new_trait_refs); - self.current_trait_refs <-> old; - original_trait_refs = Some(old); + let mut new_trait_refs = ~[]; + for self.def_map.find(&trait_reference.ref_id).each |&def| { + new_trait_refs.push(def_id_of_def(*def)); + } + original_trait_refs = Some(util::replace( + &mut self.current_trait_refs, + Some(new_trait_refs))); } None => { original_trait_refs = None; @@ -3906,7 +3935,7 @@ pub impl Resolver { } fn binding_mode_map(@mut self, pat: @pat) -> BindingMap { - let mut result = LinearMap::new(); + let mut result = HashMap::new(); do pat_bindings(self.def_map, pat) |binding_mode, _id, sp, path| { let ident = path_to_ident(path); result.insert(ident, @@ -3922,7 +3951,7 @@ pub impl Resolver { for arm.pats.eachi() |i, p| { let map_i = self.binding_mode_map(*p); - for map_0.each |&(&key, &binding_0)| { + for map_0.each |&key, &binding_0| { match map_i.find(&key) { None => { self.session.span_err( @@ -3943,7 +3972,7 @@ pub impl Resolver { } } - for map_i.each |&(&key, &binding)| { + for map_i.each |&key, &binding| { if !map_0.contains_key(&key) { self.session.span_err( binding.span, @@ -3958,7 +3987,7 @@ pub impl Resolver { fn resolve_arm(@mut self, arm: &arm, visitor: ResolveVisitor) { self.value_ribs.push(@Rib(NormalRibKind)); - let bindings_list = @mut LinearMap::new(); + let bindings_list = @mut HashMap::new(); for arm.pats.each |pattern| { self.resolve_pattern(*pattern, RefutableMode, Immutable, Some(bindings_list), visitor); @@ -4078,7 +4107,7 @@ pub impl Resolver { mutability: Mutability, // Maps idents to the node ID for the (outermost) // pattern that binds them - bindings_list: Option<@mut LinearMap>, + bindings_list: Option<@mut HashMap>, visitor: ResolveVisitor) { let pat_id = pattern.id; do walk_pat(pattern) |pattern| { @@ -4282,7 +4311,7 @@ pub impl Resolver { } pat_struct(path, _, _) => { - let structs: &mut LinearSet = &mut self.structs; + let structs: &mut HashSet = &mut self.structs; match self.resolve_path(path, TypeNS, false, visitor) { Some(def_ty(class_id)) if structs.contains(&class_id) => { @@ -4356,7 +4385,7 @@ pub impl Resolver { /// If `check_ribs` is true, checks the local definitions first; i.e. /// doesn't skip straight to the containing module. fn resolve_path(@mut self, - path: @path, + path: @Path, namespace: Namespace, check_ribs: bool, visitor: ResolveVisitor) @@ -4481,7 +4510,7 @@ pub impl Resolver { return NoNameDefinition; } - fn intern_module_part_of_path(@mut self, path: @path) -> ~[ident] { + fn intern_module_part_of_path(@mut self, path: @Path) -> ~[ident] { let mut module_path_idents = ~[]; for path.idents.eachi |index, ident| { if index == path.idents.len() - 1 { @@ -4495,7 +4524,7 @@ pub impl Resolver { } fn resolve_module_relative_path(@mut self, - path: @path, + path: @Path, +xray: XrayFlag, namespace: Namespace) -> Option { @@ -4541,7 +4570,7 @@ pub impl Resolver { /// Invariant: This must be called only during main resolution, not during /// import resolution. fn resolve_crate_relative_path(@mut self, - path: @path, + path: @Path, +xray: XrayFlag, namespace: Namespace) -> Option { @@ -4791,7 +4820,7 @@ pub impl Resolver { expr_struct(path, _, _) => { // Resolve the path to the structure it goes to. - let structs: &mut LinearSet = &mut self.structs; + let structs: &mut HashSet = &mut self.structs; match self.resolve_path(path, TypeNS, false, visitor) { Some(def_ty(class_id)) | Some(def_struct(class_id)) if structs.contains(&class_id) => { @@ -4952,7 +4981,7 @@ pub impl Resolver { match child_name_bindings.def_for_namespace(TypeNS) { Some(def) => { match def { - def_ty(trait_def_id) => { + def_trait(trait_def_id) => { self.add_trait_info_if_containing_method( &mut found_traits, trait_def_id, name); } @@ -4979,7 +5008,7 @@ pub impl Resolver { match target.bindings.def_for_namespace(TypeNS) { Some(def) => { match def { - def_ty(trait_def_id) => { + def_trait(trait_def_id) => { let added = self. add_trait_info_if_containing_method( &mut found_traits, @@ -5084,7 +5113,7 @@ pub impl Resolver { // fn check_duplicate_main(@mut self) { let this = &mut *self; - if this.attr_main_fn.is_none() { + if this.attr_main_fn.is_none() && this.start_fn.is_none() { if this.main_fns.len() >= 1u { let mut i = 1u; while i < this.main_fns.len() { @@ -5094,10 +5123,15 @@ pub impl Resolver { ~"multiple 'main' functions"); i += 1; } - *this.session.main_fn = this.main_fns[0]; + *this.session.entry_fn = this.main_fns[0]; + *this.session.entry_type = Some(session::EntryMain); } + } else if !this.start_fn.is_none() { + *this.session.entry_fn = this.start_fn; + *this.session.entry_type = Some(session::EntryStart); } else { - *this.session.main_fn = this.attr_main_fn; + *this.session.entry_fn = this.attr_main_fn; + *this.session.entry_type = Some(session::EntryMain); } } @@ -5178,17 +5212,11 @@ pub impl Resolver { import_resolution.span != dummy_sp() && import_resolution.privacy != Public { import_resolution.state.warned = true; - match self.unused_import_lint_level(module_) { - warn => { - self.session.span_warn(copy import_resolution.span, - ~"unused import"); - } - deny | forbid => { - self.session.span_err(copy import_resolution.span, - ~"unused import"); - } - allow => () - } + let span = import_resolution.span; + self.session.span_lint_level( + self.unused_import_lint_level(module_), + span, + ~"unused import"); } } } @@ -5236,7 +5264,7 @@ pub impl Resolver { } debug!("Import resolutions:"); - for module_.import_resolutions.each |&(name, import_resolution)| { + for module_.import_resolutions.each |name, import_resolution| { let mut value_repr; match import_resolution.target_for_namespace(ValueNS) { None => { value_repr = ~""; } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs new file mode 100644 index 0000000000000..35257f9574c36 --- /dev/null +++ b/src/librustc/middle/subst.rs @@ -0,0 +1,190 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Type substitutions. + +use core::prelude::*; +use middle::ty; +use util::ppaux::Repr; + +/////////////////////////////////////////////////////////////////////////// +// Public trait `Subst` +// +// Just call `foo.subst(tcx, substs)` to perform a substitution across +// `foo`. + +pub trait Subst { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Self; +} + +/////////////////////////////////////////////////////////////////////////// +// Substitution over types +// +// Because this is so common, we make a special optimization to avoid +// doing anything if `substs` is a no-op. I tried to generalize these +// to all subst methods but ran into trouble due to the limitations of +// our current method/trait matching algorithm. - Niko + +trait EffectfulSubst { + fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Self; +} + +impl Subst for ty::t { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t { + if ty::substs_is_noop(substs) { + return *self; + } else { + return self.effectfulSubst(tcx, substs); + } + } +} + +impl EffectfulSubst for ty::t { + fn effectfulSubst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::t { + if !ty::type_needs_subst(*self) { + return *self; + } + + match ty::get(*self).sty { + ty::ty_param(p) => { + substs.tps[p.idx] + } + ty::ty_self(_) => { + substs.self_ty.expect("ty_self not found in substs") + } + _ => { + ty::fold_regions_and_ty( + tcx, *self, + |r| r.subst(tcx, substs), + |t| t.effectfulSubst(tcx, substs), + |t| t.effectfulSubst(tcx, substs)) + } + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Other types + +impl Subst for ~[T] { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ~[T] { + self.map(|t| t.subst(tcx, substs)) + } +} + +impl Subst for @~[T] { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> @~[T] { + @(**self).subst(tcx, substs) + } +} + +impl Subst for Option { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> Option { + self.map(|t| t.subst(tcx, substs)) + } +} + +impl Subst for ty::TraitRef { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::TraitRef { + ty::TraitRef { + def_id: self.def_id, + substs: self.substs.subst(tcx, substs) + } + } +} + +impl Subst for ty::substs { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::substs { + ty::substs { + self_r: self.self_r.subst(tcx, substs), + self_ty: self.self_ty.map(|typ| typ.subst(tcx, substs)), + tps: self.tps.map(|typ| typ.subst(tcx, substs)) + } + } +} + +impl Subst for ty::BareFnTy { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::BareFnTy { + ty::fold_bare_fn_ty(self, |t| t.subst(tcx, substs)) + } +} + +impl Subst for ty::param_bound { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::param_bound { + match self { + &ty::bound_copy | + &ty::bound_durable | + &ty::bound_owned | + &ty::bound_const => { + *self + } + + &ty::bound_trait(tref) => { + ty::bound_trait(@tref.subst(tcx, substs)) + } + } + } +} + +impl Subst for ty::TypeParameterDef { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::TypeParameterDef { + ty::TypeParameterDef { + def_id: self.def_id, + bounds: self.bounds.subst(tcx, substs) + } + } +} + +impl Subst for ty::Generics { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Generics { + ty::Generics { + type_param_defs: self.type_param_defs.subst(tcx, substs), + region_param: self.region_param + } + } +} + +impl Subst for ty::Region { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::Region { + // Note: This routine only handles the self region, because it + // is only concerned with substitutions of regions that appear + // in types. Region substitution of the bound regions that + // appear in a function signature is done using the + // specialized routine + // `middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig()`. + // As we transition to the new region syntax this distinction + // will most likely disappear. + match self { + &ty::re_bound(ty::br_self) => { + match substs.self_r { + None => { + tcx.sess.bug( + fmt!("ty::Region#subst(): \ + Reference to self region when \ + given substs with no self region: %s", + substs.repr(tcx))); + } + Some(self_r) => self_r + } + } + _ => *self + } + } +} + +impl Subst for ty::ty_param_bounds_and_ty { + fn subst(&self, tcx: ty::ctxt, substs: &ty::substs) -> ty::ty_param_bounds_and_ty { + ty::ty_param_bounds_and_ty { + generics: self.generics.subst(tcx, substs), + ty: self.ty.subst(tcx, substs) + } + } +} + diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 12eaeb77d1103..32c9189ad2d7d 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -167,7 +167,7 @@ use middle::trans::type_of; use middle::ty; use util::common::indenter; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use syntax::ast; use syntax::ast::ident; use syntax::ast_util::path_to_ident; @@ -323,7 +323,7 @@ pub struct BindingInfo { ty: ty::t, } -pub type BindingsMap = LinearMap; +pub type BindingsMap = HashMap; pub struct ArmData<'self> { bodycx: block, @@ -1620,7 +1620,7 @@ pub fn trans_match_inner(scope_cx: block, // to an alloca() that will be the value for that local variable. // Note that we use the names because each binding will have many ids // from the various alternatives. - let mut bindings_map = LinearMap::new(); + let mut bindings_map = HashMap::new(); do pat_bindings(tcx.def_map, arm.pats[0]) |bm, p_id, _s, path| { let ident = path_to_ident(path); let variable_ty = node_id_type(bcx, p_id); diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index b854addf0b1a2..36958fa706ed5 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -88,6 +88,7 @@ pub enum Repr { struct Struct { size: u64, align: u64, + packed: bool, fields: ~[ty::t] } @@ -109,17 +110,18 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { } let repr = @match ty::get(t).sty { ty::ty_tup(ref elems) => { - Univariant(mk_struct(cx, *elems), false) + Univariant(mk_struct(cx, *elems, false), false) } ty::ty_struct(def_id, ref substs) => { let fields = ty::lookup_struct_fields(cx.tcx, def_id); let ftys = do fields.map |field| { ty::lookup_field_type(cx.tcx, def_id, field.id, substs) }; + let packed = ty::lookup_packed(cx.tcx, def_id); let dtor = ty::ty_dtor(cx.tcx, def_id).is_present(); let ftys = if dtor { ftys + [ty::mk_bool(cx.tcx)] } else { ftys }; - Univariant(mk_struct(cx, ftys), dtor) + Univariant(mk_struct(cx, ftys, packed), dtor) } ty::ty_enum(def_id, ref substs) => { struct Case { discr: int, tys: ~[ty::t] }; @@ -132,7 +134,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { }; if cases.len() == 0 { // Uninhabitable; represent as unit - Univariant(mk_struct(cx, ~[]), false) + Univariant(mk_struct(cx, ~[], false), false) } else if cases.all(|c| c.tys.len() == 0) { // All bodies empty -> intlike let discrs = cases.map(|c| c.discr); @@ -140,7 +142,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { } else if cases.len() == 1 { // Equivalent to a struct/tuple/newtype. assert!(cases[0].discr == 0); - Univariant(mk_struct(cx, cases[0].tys), false) + Univariant(mk_struct(cx, cases[0].tys, false), false) } else { // The general case. Since there's at least one // non-empty body, explicit discriminants should have @@ -151,7 +153,7 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { ty::item_path_str(cx.tcx, def_id))) } let discr = ~[ty::mk_int(cx.tcx)]; - General(cases.map(|c| mk_struct(cx, discr + c.tys))) + General(cases.map(|c| mk_struct(cx, discr + c.tys, false))) } } _ => cx.sess.bug(~"adt::represent_type called on non-ADT type") @@ -160,12 +162,13 @@ pub fn represent_type(cx: @CrateContext, t: ty::t) -> @Repr { return repr; } -fn mk_struct(cx: @CrateContext, tys: &[ty::t]) -> Struct { +fn mk_struct(cx: @CrateContext, tys: &[ty::t], packed: bool) -> Struct { let lltys = tys.map(|&ty| type_of::sizing_type_of(cx, ty)); - let llty_rec = T_struct(lltys); + let llty_rec = T_struct(lltys, packed); Struct { size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64, align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64, + packed: packed, fields: vec::from_slice(tys) } } @@ -358,7 +361,8 @@ fn struct_field_ptr(bcx: block, st: &Struct, val: ValueRef, ix: uint, let val = if needs_cast { let real_llty = T_struct(st.fields.map( - |&ty| type_of::type_of(ccx, ty))); + |&ty| type_of::type_of(ccx, ty)), + st.packed); PointerCast(bcx, val, T_ptr(real_llty)) } else { val diff --git a/src/librustc/middle/trans/asm.rs b/src/librustc/middle/trans/asm.rs index b3b23a8730d1a..cbcefdd5fdb77 100644 --- a/src/librustc/middle/trans/asm.rs +++ b/src/librustc/middle/trans/asm.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -108,7 +108,7 @@ pub fn trans_inline_asm(bcx: block, ia: &ast::inline_asm) -> block { } else if numOutputs == 1 { val_ty(outputs[0]) } else { - T_struct(outputs.map(|o| val_ty(*o))) + T_struct(outputs.map(|o| val_ty(*o)), false) }; let dialect = match ia.dialect { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 15238f168944d..cd6b23aadadd5 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -63,11 +63,11 @@ use middle::trans::type_of; use middle::trans::type_of::*; use middle::ty; use util::common::indenter; -use util::ppaux::ty_to_str; +use util::ppaux::{Repr, ty_to_str}; use util::ppaux; use core::hash; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::int; use core::io; use core::libc::{c_uint, c_ulonglong}; @@ -91,10 +91,8 @@ pub struct icx_popper { #[unsafe_destructor] impl Drop for icx_popper { fn finalize(&self) { - unsafe { - if self.ccx.sess.count_llvm_insns() { - self.ccx.stats.llvm_insn_ctxt.pop(); - } + if self.ccx.sess.count_llvm_insns() { + self.ccx.stats.llvm_insn_ctxt.pop(); } } } @@ -145,9 +143,7 @@ pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, llvm::LLVMGetOrInsertFunction(llmod, buf, llty) } }); - unsafe { - lib::llvm::SetFunctionCallConv(llfn, cc); - } + lib::llvm::SetFunctionCallConv(llfn, cc); return llfn; } @@ -472,11 +468,9 @@ pub fn set_glue_inlining(f: ValueRef, t: ty::t) { // Double-check that we never ask LLVM to declare the same symbol twice. It // silently mangles such symbols, breaking our linkage model. -pub fn note_unique_llvm_symbol(ccx: @CrateContext, +sym: ~str) { - // XXX: this should not be necessary - use core::container::Set; +pub fn note_unique_llvm_symbol(ccx: @CrateContext, sym: @~str) { if ccx.all_llvm_symbols.contains(&sym) { - ccx.sess.bug(~"duplicate LLVM symbol: " + sym); + ccx.sess.bug(~"duplicate LLVM symbol: " + *sym); } ccx.all_llvm_symbols.insert(sym); } @@ -730,11 +724,9 @@ pub fn cast_shift_expr_rhs(cx: block, op: ast::binop, pub fn cast_shift_const_rhs(op: ast::binop, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - unsafe { - cast_shift_rhs(op, lhs, rhs, - |a, b| unsafe { llvm::LLVMConstTrunc(a, b) }, - |a, b| unsafe { llvm::LLVMConstZExt(a, b) }) - } + cast_shift_rhs(op, lhs, rhs, + |a, b| unsafe { llvm::LLVMConstTrunc(a, b) }, + |a, b| unsafe { llvm::LLVMConstZExt(a, b) }) } pub fn cast_shift_rhs(op: ast::binop, @@ -938,7 +930,7 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { // The landing pad return type (the type being propagated). Not sure what // this represents but it's determined by the personality function and // this is what the EH proposal example uses. - let llretty = T_struct(~[T_ptr(T_i8()), T_i32()]); + let llretty = T_struct(~[T_ptr(T_i8()), T_i32()], false); // The exception handling personality function. This is the C++ // personality function __gxx_personality_v0, wrapped in our naming // convention. @@ -1592,11 +1584,11 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext, for param_substs.each |p| { p.validate(); } debug!("new_fn_ctxt_w_id(path=%s, id=%?, impl_id=%?, \ - param_substs=%s", + param_substs=%s)", path_str(ccx.sess, path), id, impl_id, - opt_param_substs_to_str(ccx.tcx, ¶m_substs)); + param_substs.repr(ccx.tcx)); let llbbs = mk_standard_basic_blocks(llfndecl); return @mut fn_ctxt_ { @@ -1609,9 +1601,9 @@ pub fn new_fn_ctxt_w_id(ccx: @CrateContext, llself: None, personality: None, loop_ret: None, - llargs: @mut LinearMap::new(), - lllocals: @mut LinearMap::new(), - llupvars: @mut LinearMap::new(), + llargs: @mut HashMap::new(), + lllocals: @mut HashMap::new(), + llupvars: @mut HashMap::new(), id: id, impl_id: impl_id, param_substs: param_substs, @@ -1788,6 +1780,9 @@ pub fn trans_closure(ccx: @CrateContext, let _icx = ccx.insn_ctxt("trans_closure"); set_uwtable(llfndecl); + debug!("trans_closure(..., param_substs=%s)", + param_substs.repr(ccx.tcx)); + // Set up arguments to the function. let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, impl_id, param_substs, Some(body.span)); @@ -1849,7 +1844,9 @@ pub fn trans_fn(ccx: @CrateContext, let do_time = ccx.sess.trans_stats(); let start = if do_time { time::get_time() } else { time::Timespec::new(0, 0) }; - debug!("trans_fn(ty_self=%?)", ty_self); + debug!("trans_fn(ty_self=%?, param_substs=%s)", + ty_self, + param_substs.repr(ccx.tcx)); let _icx = ccx.insn_ctxt("trans_fn"); ccx.stats.n_fns += 1; let the_path_str = path_str(ccx.sess, path); @@ -2197,28 +2194,32 @@ pub fn register_fn_fuller(ccx: @CrateContext, ccx.item_symbols.insert(node_id, ps); // FIXME #4404 android JNI hacks - let is_main = is_main_fn(&ccx.sess, node_id) && + let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library || (*ccx.sess.building_library && ccx.sess.targ_cfg.os == session::os_android)); - if is_main { create_main_wrapper(ccx, sp, llfn); } + if is_entry { create_entry_wrapper(ccx, sp, llfn); } llfn } -pub fn is_main_fn(sess: &Session, node_id: ast::node_id) -> bool { - match *sess.main_fn { - Some((main_id, _)) => node_id == main_id, +pub fn is_entry_fn(sess: &Session, node_id: ast::node_id) -> bool { + match *sess.entry_fn { + Some((entry_id, _)) => node_id == entry_id, None => false } } // Create a _rust_main(args: ~[str]) function which will be called from the // runtime rust_start function -pub fn create_main_wrapper(ccx: @CrateContext, +pub fn create_entry_wrapper(ccx: @CrateContext, _sp: span, main_llfn: ValueRef) { - - let llfn = create_main(ccx, main_llfn); - create_entry_fn(ccx, llfn); + let et = ccx.sess.entry_type.unwrap(); + if et == session::EntryMain { + let llfn = create_main(ccx, main_llfn); + create_entry_fn(ccx, llfn, true); + } else { + create_entry_fn(ccx, main_llfn, false); + } fn create_main(ccx: @CrateContext, main_llfn: ValueRef) -> ValueRef { let nt = ty::mk_nil(ccx.tcx); @@ -2242,18 +2243,18 @@ pub fn create_main_wrapper(ccx: @CrateContext, return llfdecl; } - fn create_entry_fn(ccx: @CrateContext, rust_main: ValueRef) { - #[cfg(windows)] - fn main_name() -> ~str { return ~"WinMain@16"; } - #[cfg(unix)] - fn main_name() -> ~str { return ~"main"; } + fn create_entry_fn(ccx: @CrateContext, rust_main: ValueRef, use_start_lang_item:bool) { let llfty = T_fn(~[ccx.int_type, T_ptr(T_ptr(T_i8()))], ccx.int_type); // FIXME #4404 android JNI hacks let llfn = if *ccx.sess.building_library { decl_cdecl_fn(ccx.llmod, ~"amain", llfty) } else { - decl_cdecl_fn(ccx.llmod, main_name(), llfty) + let main_name = match ccx.sess.targ_cfg.os { + session::os_win32 => ~"WinMain@16", + _ => ~"main", + }; + decl_cdecl_fn(ccx.llmod, main_name, llfty) }; let llbb = str::as_c_str(~"top", |buf| { unsafe { @@ -2264,36 +2265,29 @@ pub fn create_main_wrapper(ccx: @CrateContext, unsafe { llvm::LLVMPositionBuilderAtEnd(bld, llbb); } - let crate_map = ccx.crate_map; - let start_def_id = ccx.tcx.lang_items.start_fn(); - let start_fn = if start_def_id.crate == ast::local_crate { - ccx.sess.bug(~"start lang item is never in the local crate") - } else { - let start_fn_type = csearch::get_type(ccx.tcx, - start_def_id).ty; - trans_external_path(ccx, start_def_id, start_fn_type) - }; let retptr = unsafe { llvm::LLVMBuildAlloca(bld, ccx.int_type, noname()) }; - let args = unsafe { - let opaque_rust_main = llvm::LLVMBuildPointerCast( - bld, rust_main, T_ptr(T_i8()), noname()); - let opaque_crate_map = llvm::LLVMBuildPointerCast( - bld, crate_map, T_ptr(T_i8()), noname()); + let crate_map = ccx.crate_map; + let opaque_crate_map = unsafe {llvm::LLVMBuildPointerCast( + bld, crate_map, T_ptr(T_i8()), noname())}; - if *ccx.sess.building_library { - ~[ - retptr, - C_null(T_opaque_box_ptr(ccx)), - opaque_rust_main, - llvm::LLVMConstInt(T_i32(), 0u as c_ulonglong, False), - llvm::LLVMConstInt(T_i32(), 0u as c_ulonglong, False), - opaque_crate_map - ] + let (start_fn, args) = if use_start_lang_item { + let start_def_id = ccx.tcx.lang_items.start_fn(); + let start_fn = if start_def_id.crate == ast::local_crate { + ccx.sess.bug(~"start lang item is never in the local crate") } else { + let start_fn_type = csearch::get_type(ccx.tcx, + start_def_id).ty; + trans_external_path(ccx, start_def_id, start_fn_type) + }; + + let args = unsafe { + let opaque_rust_main = llvm::LLVMBuildPointerCast( + bld, rust_main, T_ptr(T_i8()), noname()); + ~[ retptr, C_null(T_opaque_box_ptr(ccx)), @@ -2301,8 +2295,21 @@ pub fn create_main_wrapper(ccx: @CrateContext, llvm::LLVMGetParam(llfn, 0 as c_uint), llvm::LLVMGetParam(llfn, 1 as c_uint), opaque_crate_map + ] + }; + (start_fn, args) + } else { + debug!("using user-defined start fn"); + let args = unsafe { + ~[ retptr, + C_null(T_opaque_box_ptr(ccx)), + llvm::LLVMGetParam(llfn, 0 as c_uint), + llvm::LLVMGetParam(llfn, 1 as c_uint), + opaque_crate_map ] - } + }; + + (rust_main, args) }; unsafe { @@ -2567,11 +2574,10 @@ pub fn trans_constant(ccx: @CrateContext, it: @ast::item) { path_name(variant.node.name), path_name(special_idents::descrim) ]); - let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); + let s = @mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx)); let disr_val = vi[i].disr_val; - // XXX: Bad copy. - note_unique_llvm_symbol(ccx, copy s); - let discrim_gvar = str::as_c_str(s, |buf| { + note_unique_llvm_symbol(ccx, s); + let discrim_gvar = str::as_c_str(*s, |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf) } @@ -2610,7 +2616,7 @@ pub fn p2i(ccx: @CrateContext, v: ValueRef) -> ValueRef { } } -pub fn declare_intrinsics(llmod: ModuleRef) -> LinearMap<~str, ValueRef> { +pub fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> { let T_memcpy32_args: ~[TypeRef] = ~[T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()]; let T_memcpy64_args: ~[TypeRef] = @@ -2743,7 +2749,7 @@ pub fn declare_intrinsics(llmod: ModuleRef) -> LinearMap<~str, ValueRef> { let bswap64 = decl_cdecl_fn(llmod, ~"llvm.bswap.i64", T_fn(~[T_i64()], T_i64())); - let mut intrinsics = LinearMap::new(); + let mut intrinsics = HashMap::new(); intrinsics.insert(~"llvm.gcroot", gcroot); intrinsics.insert(~"llvm.gcread", gcread); intrinsics.insert(~"llvm.memcpy.p0i8.p0i8.i32", memcpy32); @@ -2804,7 +2810,7 @@ pub fn declare_intrinsics(llmod: ModuleRef) -> LinearMap<~str, ValueRef> { } pub fn declare_dbg_intrinsics(llmod: ModuleRef, - intrinsics: &mut LinearMap<~str, ValueRef>) { + intrinsics: &mut HashMap<~str, ValueRef>) { let declare = decl_cdecl_fn(llmod, ~"llvm.dbg.declare", T_fn(~[T_metadata(), T_metadata()], T_void())); @@ -2843,18 +2849,16 @@ pub fn decl_gc_metadata(ccx: @CrateContext, llmod_id: &str) { } pub fn create_module_map(ccx: @CrateContext) -> ValueRef { - let elttype = T_struct(~[ccx.int_type, ccx.int_type]); + let elttype = T_struct(~[ccx.int_type, ccx.int_type], false); let maptype = T_array(elttype, ccx.module_data.len() + 1); let map = str::as_c_str(~"_rust_mod_map", |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, maptype, buf) } }); - unsafe { - lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage); - } + lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage); let mut elts: ~[ValueRef] = ~[]; - for ccx.module_data.each |&(key, &val)| { + for ccx.module_data.each |key, &val| { let elt = C_struct(~[p2i(ccx, C_cstr(ccx, @/*bad*/ copy *key)), p2i(ccx, val)]); elts.push(elt); @@ -2883,7 +2887,7 @@ pub fn decl_crate_map(sess: session::Session, mapmeta: LinkMeta, }; let sym_name = ~"_rust_crate_map_" + mapname; let arrtype = T_array(int_type, n_subcrates as uint); - let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype]); + let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype], false); let map = str::as_c_str(sym_name, |buf| { unsafe { llvm::LLVMAddGlobal(llmod, maptype, buf) @@ -3052,37 +3056,37 @@ pub fn trans_crate(sess: session::Session, llmod: llmod, td: td, tn: tn, - externs: @mut LinearMap::new(), + externs: @mut HashMap::new(), intrinsics: intrinsics, - item_vals: @mut LinearMap::new(), + item_vals: @mut HashMap::new(), exp_map2: emap2, reachable: reachable, - item_symbols: @mut LinearMap::new(), + item_symbols: @mut HashMap::new(), link_meta: link_meta, - enum_sizes: @mut LinearMap::new(), - discrims: @mut LinearMap::new(), - discrim_symbols: @mut LinearMap::new(), - tydescs: @mut LinearMap::new(), + enum_sizes: @mut HashMap::new(), + discrims: @mut HashMap::new(), + discrim_symbols: @mut HashMap::new(), + tydescs: @mut HashMap::new(), finished_tydescs: @mut false, - external: @mut LinearMap::new(), - monomorphized: @mut LinearMap::new(), - monomorphizing: @mut LinearMap::new(), - type_use_cache: @mut LinearMap::new(), - vtables: @mut LinearMap::new(), - const_cstr_cache: @mut LinearMap::new(), - const_globals: @mut LinearMap::new(), - const_values: @mut LinearMap::new(), - extern_const_values: @mut LinearMap::new(), - module_data: @mut LinearMap::new(), - lltypes: @mut LinearMap::new(), - llsizingtypes: @mut LinearMap::new(), - adt_reprs: @mut LinearMap::new(), + external: @mut HashMap::new(), + monomorphized: @mut HashMap::new(), + monomorphizing: @mut HashMap::new(), + type_use_cache: @mut HashMap::new(), + vtables: @mut HashMap::new(), + const_cstr_cache: @mut HashMap::new(), + const_globals: @mut HashMap::new(), + const_values: @mut HashMap::new(), + extern_const_values: @mut HashMap::new(), + module_data: @mut HashMap::new(), + lltypes: @mut HashMap::new(), + llsizingtypes: @mut HashMap::new(), + adt_reprs: @mut HashMap::new(), names: new_namegen(sess.parse_sess.interner), next_addrspace: new_addrspace_gen(), symbol_hasher: symbol_hasher, - type_hashcodes: @mut LinearMap::new(), - type_short_names: @mut LinearMap::new(), - all_llvm_symbols: @mut LinearSet::new(), + type_hashcodes: @mut HashMap::new(), + type_short_names: @mut HashMap::new(), + all_llvm_symbols: @mut HashSet::new(), tcx: tcx, maps: maps, stats: @mut Stats { @@ -3095,7 +3099,7 @@ pub fn trans_crate(sess: session::Session, n_inlines: 0u, n_closures: 0u, llvm_insn_ctxt: @mut ~[], - llvm_insns: @mut LinearMap::new(), + llvm_insns: @mut HashMap::new(), fn_times: @mut ~[] }, upcalls: upcall::declare_upcalls(targ_cfg, llmod), @@ -3145,7 +3149,7 @@ pub fn trans_crate(sess: session::Session, } if ccx.sess.count_llvm_insns() { - for ccx.stats.llvm_insns.each |&(&k, &v)| { + for ccx.stats.llvm_insns.each |&k, &v| { io::println(fmt!("%-7u %s", v, k)); } } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index ab0e2f38a0b94..d6c045bb1158b 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -18,7 +18,7 @@ use syntax::codemap::span; use core::prelude::*; use core::cast; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::libc::{c_uint, c_ulonglong, c_char}; use core::libc; use core::option::Some; @@ -27,9 +27,7 @@ use core::str; use core::vec; pub fn terminate(cx: block, _: &str) { - unsafe { - cx.terminated = true; - } + cx.terminated = true; } pub fn check_not_terminated(cx: block) { @@ -55,7 +53,7 @@ pub fn count_insn(cx: block, category: &str) { // Build version of path with cycles removed. // Pass 1: scan table mapping str -> rightmost pos. - let mut mm = LinearMap::new(); + let mut mm = HashMap::new(); let len = vec::len(*v); let mut i = 0u; while i < len { diff --git a/src/librustc/middle/trans/cabi_arm.rs b/src/librustc/middle/trans/cabi_arm.rs index a16b3672b7afe..1b94e990545ea 100644 --- a/src/librustc/middle/trans/cabi_arm.rs +++ b/src/librustc/middle/trans/cabi_arm.rs @@ -12,6 +12,7 @@ use lib::llvm::{llvm, Integer, Pointer, Float, Double, Struct, Array}; use lib::llvm::struct_tys; use lib::llvm::TypeRef; use lib::llvm::{Attribute, StructRetAttribute}; +use lib::llvm::True; use middle::trans::cabi::{ABIInfo, FnType, LLVMType}; use middle::trans::common::{T_i8, T_i16, T_i32, T_i64}; use middle::trans::common::{T_array, T_ptr, T_void}; @@ -39,8 +40,12 @@ fn ty_align(ty: TypeRef) -> uint { Float => 4, Double => 8, Struct => { - do vec::foldl(1, struct_tys(ty)) |a, t| { - uint::max(a, ty_align(*t)) + if llvm::LLVMIsPackedStruct(ty) == True { + 1 + } else { + do vec::foldl(1, struct_tys(ty)) |a, t| { + uint::max(a, ty_align(*t)) + } } } Array => { @@ -62,10 +67,16 @@ fn ty_size(ty: TypeRef) -> uint { Float => 4, Double => 8, Struct => { - let size = do vec::foldl(0, struct_tys(ty)) |s, t| { - align(s, *t) + ty_size(*t) - }; - align(size, ty) + if llvm::LLVMIsPackedStruct(ty) == True { + do vec::foldl(0, struct_tys(ty)) |s, t| { + s + ty_size(*t) + } + } else { + let size = do vec::foldl(0, struct_tys(ty)) |s, t| { + align(s, *t) + ty_size(*t) + }; + align(size, ty) + } } Array => { let len = llvm::LLVMGetArrayLength(ty) as uint; diff --git a/src/librustc/middle/trans/cabi_mips.rs b/src/librustc/middle/trans/cabi_mips.rs index 1e05cf258c719..ce37455560b5c 100644 --- a/src/librustc/middle/trans/cabi_mips.rs +++ b/src/librustc/middle/trans/cabi_mips.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -14,6 +14,7 @@ use core::libc::c_uint; use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double}; use lib::llvm::{Struct, Array, Attribute}; use lib::llvm::{StructRetAttribute}; +use lib::llvm::True; use middle::trans::common::*; use middle::trans::cabi::*; @@ -49,8 +50,12 @@ fn ty_align(ty: TypeRef) -> uint { Float => 4, Double => 8, Struct => { - do vec::foldl(1, struct_tys(ty)) |a, t| { - uint::max(a, ty_align(*t)) + if llvm::LLVMIsPackedStruct(ty) == True { + 1 + } else { + do vec::foldl(1, struct_tys(ty)) |a, t| { + uint::max(a, ty_align(*t)) + } } } Array => { @@ -72,10 +77,16 @@ fn ty_size(ty: TypeRef) -> uint { Float => 4, Double => 8, Struct => { - let size = do vec::foldl(0, struct_tys(ty)) |s, t| { - align(s, *t) + ty_size(*t) - }; - align(size, ty) + if llvm::LLVMIsPackedStruct(ty) == True { + do vec::foldl(0, struct_tys(ty)) |s, t| { + s + ty_size(*t) + } + } else { + let size = do vec::foldl(0, struct_tys(ty)) |s, t| { + align(s, *t) + ty_size(*t) + }; + align(size, ty) + } } Array => { let len = llvm::LLVMGetArrayLength(ty) as uint; @@ -174,7 +185,7 @@ fn struct_ty(ty: TypeRef, fields.push(ty); } - return T_struct(fields); + return T_struct(fields, false); } enum MIPS_ABIInfo { MIPS_ABIInfo } diff --git a/src/librustc/middle/trans/cabi_x86_64.rs b/src/librustc/middle/trans/cabi_x86_64.rs index 896ebd1625755..fa85588cb0f48 100644 --- a/src/librustc/middle/trans/cabi_x86_64.rs +++ b/src/librustc/middle/trans/cabi_x86_64.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -15,6 +15,7 @@ use lib::llvm::{llvm, TypeRef, Integer, Pointer, Float, Double}; use lib::llvm::{Struct, Array, Attribute}; use lib::llvm::{StructRetAttribute, ByValAttribute}; use lib::llvm::struct_tys; +use lib::llvm::True; use middle::trans::common::*; use middle::trans::cabi::*; @@ -76,8 +77,12 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { Float => 4, Double => 8, Struct => { - do vec::foldl(1, struct_tys(ty)) |a, t| { + if llvm::LLVMIsPackedStruct(ty) == True { + 1 + } else { + do vec::foldl(1, struct_tys(ty)) |a, t| { uint::max(a, ty_align(*t)) + } } } Array => { @@ -99,10 +104,16 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { Float => 4, Double => 8, Struct => { - let size = do vec::foldl(0, struct_tys(ty)) |s, t| { + if llvm::LLVMIsPackedStruct(ty) == True { + do vec::foldl(0, struct_tys(ty)) |s, t| { + s + ty_size(*t) + } + } else { + let size = do vec::foldl(0, struct_tys(ty)) |s, t| { align(s, *t) + ty_size(*t) - }; - align(size, ty) + }; + align(size, ty) + } } Array => { let len = llvm::LLVMGetArrayLength(ty) as uint; @@ -245,10 +256,10 @@ fn classify_ty(ty: TypeRef) -> ~[x86_64_reg_class] { cls[i] = sse_int_class; } else if is_sse(cls[i]) { i += 1; - while cls[i] == sseup_class { i += 1u; } + while i != e && cls[i] == sseup_class { i += 1u; } } else if cls[i] == x87_class { i += 1; - while cls[i] == x87up_class { i += 1u; } + while i != e && cls[i] == x87up_class { i += 1u; } } else { i += 1; } @@ -308,7 +319,7 @@ fn llreg_ty(cls: &[x86_64_reg_class]) -> TypeRef { } i += 1u; } - return T_struct(tys); + return T_struct(tys, false); } } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index ec67c68f93cda..20382676fed21 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -42,6 +42,7 @@ use middle::trans::type_of; use middle::ty; use middle::typeck; use util::common::indenter; +use util::ppaux::Repr; use syntax::ast; use syntax::ast_map; @@ -74,24 +75,13 @@ pub struct Callee { pub fn trans(bcx: block, expr: @ast::expr) -> Callee { let _icx = bcx.insn_ctxt("trans_callee"); + debug!("callee::trans(expr=%s)", expr.repr(bcx.tcx())); // pick out special kinds of expressions that can be called: match expr.node { ast::expr_path(_) => { return trans_def(bcx, bcx.def(expr.id), expr); } - ast::expr_field(base, _, _) => { - match bcx.ccx().maps.method_map.find(&expr.id) { - Some(origin) => { // An impl method - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - let origin = /*bad*/ copy *origin; - return meth::trans_method_callee(bcx, expr.id, - base, origin); - } - None => {} // not a method, just a field - } - } _ => {} } @@ -148,7 +138,7 @@ pub fn trans(bcx: block, expr: @ast::expr) -> Callee { ast::def_self(*) => { datum_callee(bcx, ref_expr) } - ast::def_mod(*) | ast::def_foreign_mod(*) | + ast::def_mod(*) | ast::def_foreign_mod(*) | ast::def_trait(*) | ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) | ast::def_use(*) | ast::def_typaram_binder(*) | ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) | @@ -178,11 +168,13 @@ pub fn trans_fn_ref(bcx: block, * with id `def_id` into a function pointer. This may require * monomorphization or inlining. */ - let _icx = bcx.insn_ctxt("trans_fn"); + let _icx = bcx.insn_ctxt("trans_fn_ref"); let type_params = node_id_type_params(bcx, ref_id); - let vtables = node_vtables(bcx, ref_id); + debug!("trans_fn_ref(def_id=%s, ref_id=%?, type_params=%s, vtables=%s)", + def_id.repr(bcx.tcx()), ref_id, type_params.repr(bcx.tcx()), + vtables.repr(bcx.tcx())); trans_fn_ref_with_vtables(bcx, def_id, ref_id, type_params, vtables) } @@ -224,12 +216,13 @@ pub fn trans_fn_ref_with_vtables( let ccx = bcx.ccx(); let tcx = ccx.tcx; - debug!("trans_fn_ref_with_vtables(bcx=%s, def_id=%?, ref_id=%?, \ - type_params=%?, vtables=%?)", - bcx.to_str(), def_id, ref_id, - type_params.map(|t| bcx.ty_to_str(*t)), - vtables); - let _indenter = indenter(); + debug!("trans_fn_ref_with_vtables(bcx=%s, def_id=%s, ref_id=%?, \ + type_params=%s, vtables=%s)", + bcx.to_str(), + def_id.repr(bcx.tcx()), + ref_id, + type_params.repr(bcx.tcx()), + vtables.repr(bcx.tcx())); assert!(type_params.all(|t| !ty::type_needs_infer(*t))); @@ -238,8 +231,7 @@ pub fn trans_fn_ref_with_vtables( // Modify the def_id if this is a default method; we want to be // monomorphizing the trait's code. - let (def_id, opt_impl_did) = - match tcx.provided_method_sources.find(&def_id) { + let (def_id, opt_impl_did) = match tcx.provided_method_sources.find(&def_id) { None => (def_id, None), Some(source) => (source.method_id, Some(source.impl_id)) }; @@ -336,6 +328,9 @@ pub fn trans_method_call(in_cx: block, dest: expr::Dest) -> block { let _icx = in_cx.insn_ctxt("trans_method_call"); + debug!("trans_method_call(call_ex=%s, rcvr=%s)", + call_ex.repr(in_cx.tcx()), + rcvr.repr(in_cx.tcx())); trans_call_inner( in_cx, call_ex.info(), @@ -344,9 +339,14 @@ pub fn trans_method_call(in_cx: block, |cx| { match cx.ccx().maps.method_map.find(&call_ex.id) { Some(origin) => { + debug!("origin for %s: %s", + call_ex.repr(in_cx.tcx()), + origin.repr(in_cx.tcx())); + // FIXME(#5562): removing this copy causes a segfault // before stage2 let origin = /*bad*/ copy *origin; + meth::trans_method_callee(cx, call_ex.callee_id, rcvr, @@ -642,8 +642,9 @@ pub fn trans_arg_expr(bcx: block, debug!("trans_arg_expr(formal_ty=(%?,%s), arg_expr=%s, \ ret_flag=%?)", - formal_ty.mode, bcx.ty_to_str(formal_ty.ty), - bcx.expr_to_str(arg_expr), + formal_ty.mode, + formal_ty.ty.repr(bcx.tcx()), + arg_expr.repr(bcx.tcx()), ret_flag.map(|v| bcx.val_str(*v))); let _indenter = indenter(); diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 6bb30a5d5b51b..f14096443b2b7 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -41,11 +41,11 @@ use middle::trans::type_use; use middle::ty::substs; use middle::ty; use middle::typeck; -use util::ppaux::{expr_repr, ty_to_str}; +use util::ppaux::{Repr}; use core::cast; use core::hash; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::libc::{c_uint, c_longlong, c_ulonglong}; use core::ptr; use core::str; @@ -134,7 +134,7 @@ pub struct Stats { n_inlines: uint, n_closures: uint, llvm_insn_ctxt: @mut ~[~str], - llvm_insns: @mut LinearMap<~str, uint>, + llvm_insns: @mut HashMap<~str, uint>, fn_times: @mut ~[(~str, int)] // (ident, time) } @@ -156,7 +156,7 @@ pub fn BuilderRef_res(B: BuilderRef) -> BuilderRef_res { } } -pub type ExternMap = @mut LinearMap<@str, ValueRef>; +pub type ExternMap = @mut HashMap<@str, ValueRef>; // Crate context. Every crate we compile has one of these. pub struct CrateContext { @@ -165,30 +165,30 @@ pub struct CrateContext { td: TargetData, tn: @TypeNames, externs: ExternMap, - intrinsics: LinearMap<~str, ValueRef>, - item_vals: @mut LinearMap, + intrinsics: HashMap<~str, ValueRef>, + item_vals: @mut HashMap, exp_map2: resolve::ExportMap2, reachable: reachable::map, - item_symbols: @mut LinearMap, + item_symbols: @mut HashMap, link_meta: LinkMeta, - enum_sizes: @mut LinearMap, - discrims: @mut LinearMap, - discrim_symbols: @mut LinearMap, - tydescs: @mut LinearMap, + enum_sizes: @mut HashMap, + discrims: @mut HashMap, + discrim_symbols: @mut HashMap, + tydescs: @mut HashMap, // Set when running emit_tydescs to enforce that no more tydescs are // created. finished_tydescs: @mut bool, // Track mapping of external ids to local items imported for inlining - external: @mut LinearMap>, + external: @mut HashMap>, // Cache instances of monomorphized functions - monomorphized: @mut LinearMap, - monomorphizing: @mut LinearMap, + monomorphized: @mut HashMap, + monomorphizing: @mut HashMap, // Cache computed type parameter uses (see type_use.rs) - type_use_cache: @mut LinearMap, + type_use_cache: @mut HashMap, // Cache generated vtables - vtables: @mut LinearMap, + vtables: @mut HashMap, // Cache of constant strings, - const_cstr_cache: @mut LinearMap<@~str, ValueRef>, + const_cstr_cache: @mut HashMap<@~str, ValueRef>, // Reverse-direction for const ptrs cast from globals. // Key is an int, cast from a ValueRef holding a *T, @@ -198,24 +198,24 @@ pub struct CrateContext { // when we ptrcast, and we have to ptrcast during translation // of a [T] const because we form a slice, a [*T,int] pair, not // a pointer to an LLVM array type. - const_globals: @mut LinearMap, + const_globals: @mut HashMap, // Cache of emitted const values - const_values: @mut LinearMap, + const_values: @mut HashMap, // Cache of external const values - extern_const_values: @mut LinearMap, + extern_const_values: @mut HashMap, - module_data: @mut LinearMap<~str, ValueRef>, - lltypes: @mut LinearMap, - llsizingtypes: @mut LinearMap, - adt_reprs: @mut LinearMap, + module_data: @mut HashMap<~str, ValueRef>, + lltypes: @mut HashMap, + llsizingtypes: @mut HashMap, + adt_reprs: @mut HashMap, names: namegen, next_addrspace: addrspace_gen, symbol_hasher: @hash::State, - type_hashcodes: @mut LinearMap, - type_short_names: @mut LinearMap, - all_llvm_symbols: @mut LinearSet<~str>, + type_hashcodes: @mut HashMap, + type_short_names: @mut HashMap, + all_llvm_symbols: @mut HashSet<@~str>, tcx: ty::ctxt, maps: astencode::Maps, stats: @mut Stats, @@ -250,7 +250,7 @@ pub enum local_val { local_mem(ValueRef), local_imm(ValueRef), } pub struct param_substs { tys: ~[ty::t], vtables: Option, - bounds: @~[ty::param_bounds], + type_param_defs: @~[ty::TypeParameterDef], self_ty: Option } @@ -261,16 +261,25 @@ pub impl param_substs { } } -pub fn param_substs_to_str(tcx: ty::ctxt, substs: ¶m_substs) -> ~str { - fmt!("param_substs {tys:%?, vtables:%?, bounds:%?}", - substs.tys.map(|t| ty_to_str(tcx, *t)), - substs.vtables.map(|vs| vs.map(|v| v.to_str(tcx))), - substs.bounds.map(|b| ty::param_bounds_to_str(tcx, *b))) +fn param_substs_to_str(self: ¶m_substs, + tcx: ty::ctxt) -> ~str +{ + fmt!("param_substs {tys:%s, vtables:%s, type_param_defs:%s}", + self.tys.repr(tcx), + self.vtables.repr(tcx), + self.type_param_defs.repr(tcx)) } -pub fn opt_param_substs_to_str(tcx: ty::ctxt, - substs: &Option<@param_substs>) -> ~str { - substs.map_default(~"None", |&ps| param_substs_to_str(tcx, ps)) +impl Repr for param_substs { + fn repr(&self, tcx: ty::ctxt) -> ~str { + param_substs_to_str(self, tcx) + } +} + +impl Repr for @param_substs { + fn repr(&self, tcx: ty::ctxt) -> ~str { + param_substs_to_str(*self, tcx) + } } // Function context. Every LLVM function we create will have one of @@ -314,12 +323,12 @@ pub struct fn_ctxt_ { loop_ret: Option<(ValueRef, ValueRef)>, // Maps arguments to allocas created for them in llallocas. - llargs: @mut LinearMap, + llargs: @mut HashMap, // Maps the def_ids for local variables to the allocas created for // them in llallocas. - lllocals: @mut LinearMap, + lllocals: @mut HashMap, // Same as above, but for closure upvars - llupvars: @mut LinearMap, + llupvars: @mut HashMap, // The node_id of the function, or -1 if it doesn't correspond to // a user-defined function. @@ -413,8 +422,9 @@ pub fn root_for_cleanup(bcx: block, v: ValueRef, t: ty::t) pub fn add_clean(bcx: block, val: ValueRef, t: ty::t) { if !ty::type_needs_drop(bcx.tcx(), t) { return; } debug!("add_clean(%s, %s, %s)", - bcx.to_str(), val_str(bcx.ccx().tn, val), - ty_to_str(bcx.ccx().tcx, t)); + bcx.to_str(), + val_str(bcx.ccx().tn, val), + t.repr(bcx.tcx())); let (root, rooted) = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { @@ -429,7 +439,7 @@ pub fn add_clean_temp_immediate(cx: block, val: ValueRef, ty: ty::t) { if !ty::type_needs_drop(cx.tcx(), ty) { return; } debug!("add_clean_temp_immediate(%s, %s, %s)", cx.to_str(), val_str(cx.ccx().tn, val), - ty_to_str(cx.ccx().tcx, ty)); + ty.repr(cx.tcx())); let cleanup_type = cleanup_type(cx.tcx(), ty); do in_scope_cx(cx) |scope_info| { scope_info.cleanups.push( @@ -442,7 +452,7 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { if !ty::type_needs_drop(bcx.tcx(), t) { return; } debug!("add_clean_temp_mem(%s, %s, %s)", bcx.to_str(), val_str(bcx.ccx().tn, val), - ty_to_str(bcx.ccx().tcx, t)); + t.repr(bcx.tcx())); let (root, rooted) = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { @@ -455,7 +465,7 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { pub fn add_clean_frozen_root(bcx: block, val: ValueRef, t: ty::t) { debug!("add_clean_frozen_root(%s, %s, %s)", bcx.to_str(), val_str(bcx.ccx().tn, val), - ty_to_str(bcx.ccx().tcx, t)); + t.repr(bcx.tcx())); let (root, rooted) = root_for_cleanup(bcx, val, t); let cleanup_type = cleanup_type(bcx.tcx(), t); do in_scope_cx(bcx) |scope_info| { @@ -703,7 +713,7 @@ pub impl block_ { } fn expr_to_str(@mut self, e: @ast::expr) -> ~str { - expr_repr(self.tcx(), e) + e.repr(self.tcx()) } fn expr_is_lval(@mut self, e: @ast::expr) -> bool { @@ -733,7 +743,7 @@ pub impl block_ { } fn ty_to_str(@mut self, t: ty::t) -> ~str { - ty_to_str(self.tcx(), t) + t.repr(self.tcx()) } fn to_str(@mut self) -> ~str { match self.node_info { @@ -755,7 +765,7 @@ pub fn T_void() -> TypeRef { } pub fn T_nil() -> TypeRef { - return T_struct(~[]) + return T_struct(~[], false) } pub fn T_metadata() -> TypeRef { unsafe { return llvm::LLVMMetadataType(); } } @@ -838,7 +848,7 @@ pub fn T_fn(inputs: &[TypeRef], output: TypeRef) -> TypeRef { } pub fn T_fn_pair(cx: @CrateContext, tfn: TypeRef) -> TypeRef { - return T_struct(~[T_ptr(tfn), T_opaque_cbox_ptr(cx)]); + return T_struct(~[T_ptr(tfn), T_opaque_cbox_ptr(cx)], false); } pub fn T_ptr(t: TypeRef) -> TypeRef { @@ -853,11 +863,11 @@ pub fn T_root(t: TypeRef, addrspace: addrspace) -> TypeRef { } } -pub fn T_struct(elts: &[TypeRef]) -> TypeRef { +pub fn T_struct(elts: &[TypeRef], packed: bool) -> TypeRef { unsafe { return llvm::LLVMStructType(to_ptr(elts), elts.len() as c_uint, - False); + packed as Bool); } } @@ -868,16 +878,16 @@ pub fn T_named_struct(name: &str) -> TypeRef { } } -pub fn set_struct_body(t: TypeRef, elts: &[TypeRef]) { +pub fn set_struct_body(t: TypeRef, elts: &[TypeRef], packed: bool) { unsafe { llvm::LLVMStructSetBody(t, to_ptr(elts), elts.len() as c_uint, - False); + packed as Bool); } } -pub fn T_empty_struct() -> TypeRef { return T_struct(~[]); } +pub fn T_empty_struct() -> TypeRef { return T_struct(~[], false); } // A vtable is, in reality, a vtable pointer followed by zero or more pointers // to tydescs and other vtables that it closes over. But the types and number @@ -903,7 +913,7 @@ pub fn T_task(targ_cfg: @session::config) -> TypeRef { let elems = ~[t_int, t_int, t_int, t_int, t_int, t_int, t_int, t_int]; - set_struct_body(t, elems); + set_struct_body(t, elems, false); return t; } @@ -946,7 +956,7 @@ pub fn T_tydesc(targ_cfg: @session::config) -> TypeRef { ~[int_type, int_type, glue_fn_ty, glue_fn_ty, glue_fn_ty, glue_fn_ty, T_ptr(T_i8()), T_ptr(T_i8())]; - set_struct_body(tydesc, elems); + set_struct_body(tydesc, elems, false); return tydesc; } @@ -959,8 +969,9 @@ pub fn T_array(t: TypeRef, n: uint) -> TypeRef { // Interior vector. pub fn T_vec2(targ_cfg: @session::config, t: TypeRef) -> TypeRef { return T_struct(~[T_int(targ_cfg), // fill - T_int(targ_cfg), // alloc - T_array(t, 0u)]); // elements + T_int(targ_cfg), // alloc + T_array(t, 0u)], // elements + false); } pub fn T_vec(ccx: @CrateContext, t: TypeRef) -> TypeRef { @@ -991,11 +1002,11 @@ pub fn T_box_header_fields(cx: @CrateContext) -> ~[TypeRef] { } pub fn T_box_header(cx: @CrateContext) -> TypeRef { - return T_struct(T_box_header_fields(cx)); + return T_struct(T_box_header_fields(cx), false); } pub fn T_box(cx: @CrateContext, t: TypeRef) -> TypeRef { - return T_struct(vec::append(T_box_header_fields(cx), ~[t])); + return T_struct(vec::append(T_box_header_fields(cx), ~[t]), false); } pub fn T_box_ptr(t: TypeRef) -> TypeRef { @@ -1013,7 +1024,7 @@ pub fn T_opaque_box_ptr(cx: @CrateContext) -> TypeRef { } pub fn T_unique(cx: @CrateContext, t: TypeRef) -> TypeRef { - return T_struct(vec::append(T_box_header_fields(cx), ~[t])); + return T_struct(vec::append(T_box_header_fields(cx), ~[t]), false); } pub fn T_unique_ptr(t: TypeRef) -> TypeRef { @@ -1023,12 +1034,12 @@ pub fn T_unique_ptr(t: TypeRef) -> TypeRef { } pub fn T_port(cx: @CrateContext, _t: TypeRef) -> TypeRef { - return T_struct(~[cx.int_type]); // Refcount + return T_struct(~[cx.int_type], false); // Refcount } pub fn T_chan(cx: @CrateContext, _t: TypeRef) -> TypeRef { - return T_struct(~[cx.int_type]); // Refcount + return T_struct(~[cx.int_type], false); // Refcount } @@ -1046,24 +1057,22 @@ pub fn T_enum_discrim(cx: @CrateContext) -> TypeRef { } pub fn T_captured_tydescs(cx: @CrateContext, n: uint) -> TypeRef { - return T_struct(vec::from_elem::(n, T_ptr(cx.tydesc_type))); + return T_struct(vec::from_elem::(n, T_ptr(cx.tydesc_type)), false); } pub fn T_opaque_trait(cx: @CrateContext, store: ty::TraitStore) -> TypeRef { match store { ty::BoxTraitStore => { - T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)]) + T_struct(~[T_ptr(cx.tydesc_type), T_opaque_box_ptr(cx)], false) } ty::UniqTraitStore => { T_struct(~[T_ptr(cx.tydesc_type), T_unique_ptr(T_unique(cx, T_i8())), - T_ptr(cx.tydesc_type)]) + T_ptr(cx.tydesc_type)], + false) } ty::RegionTraitStore(_) => { - T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())]) - } - ty::BareTraitStore => { - cx.sess.bug(~"can't make T_opaque_trait with bare trait store") + T_struct(~[T_ptr(cx.tydesc_type), T_ptr(T_i8())], false) } } } @@ -1448,14 +1457,14 @@ pub fn resolve_vtable_in_fn_ctxt(fcx: fn_ctxt, +vt: typeck::vtable_origin) pub fn find_vtable(tcx: ty::ctxt, ps: ¶m_substs, n_param: uint, n_bound: uint) -> typeck::vtable_origin { - debug!("find_vtable_in_fn_ctxt(n_param=%u, n_bound=%u, ps=%?)", - n_param, n_bound, param_substs_to_str(tcx, ps)); + debug!("find_vtable(n_param=%u, n_bound=%u, ps=%s)", + n_param, n_bound, ps.repr(tcx)); // Vtables are stored in a flat array, finding the right one is // somewhat awkward - let first_n_bounds = ps.bounds.slice(0, n_param); + let first_n_type_param_defs = ps.type_param_defs.slice(0, n_param); let vtables_to_skip = - ty::count_traits_and_supertraits(tcx, first_n_bounds); + ty::count_traits_and_supertraits(tcx, first_n_type_param_defs); let vtable_off = vtables_to_skip + n_bound; /*bad*/ copy ps.vtables.get()[vtable_off] } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 55e6b30439ba4..c5e708569dc25 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -25,7 +25,7 @@ use middle::trans::inline; use middle::trans::machine; use middle::trans::type_of; use middle::ty; -use util::ppaux::{expr_repr, ty_to_str}; +use util::ppaux::{Repr, ty_to_str}; use core::libc::c_uint; use syntax::{ast, ast_util, ast_map}; @@ -237,7 +237,7 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { llvm::LLVMDumpValue(C_undef(llty)); } cx.sess.bug(fmt!("const %s of type %s has size %u instead of %u", - expr_repr(cx.tcx, e), ty_to_str(cx.tcx, ety), + e.repr(cx.tcx), ty_to_str(cx.tcx, ety), csize, tsize)); } llconst diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index d290a8ffa5c94..c02417aca8b12 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -20,7 +20,7 @@ use middle::trans; use middle::ty; use util::ppaux::ty_to_str; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::libc; use core::option; use core::sys; @@ -106,7 +106,7 @@ pub struct DebugContext { pub fn mk_ctxt(+crate: ~str, intr: @ident_interner) -> DebugContext { DebugContext { - llmetadata: @mut LinearMap::new(), + llmetadata: @mut HashMap::new(), names: new_namegen(intr), crate_file: crate } @@ -151,7 +151,7 @@ struct RetvalMetadata { id: ast::node_id } -type metadata_cache = @mut LinearMap; +type metadata_cache = @mut HashMap; enum debug_metadata { file_metadata(@Metadata), @@ -172,17 +172,15 @@ fn cast_safely(val: T) -> U { } fn md_from_metadata(val: debug_metadata) -> T { - unsafe { - match val { - file_metadata(md) => cast_safely(md), - compile_unit_metadata(md) => cast_safely(md), - subprogram_metadata(md) => cast_safely(md), - local_var_metadata(md) => cast_safely(md), - tydesc_metadata(md) => cast_safely(md), - block_metadata(md) => cast_safely(md), - argument_metadata(md) => cast_safely(md), - retval_metadata(md) => cast_safely(md) - } + match val { + file_metadata(md) => cast_safely(md), + compile_unit_metadata(md) => cast_safely(md), + subprogram_metadata(md) => cast_safely(md), + local_var_metadata(md) => cast_safely(md), + tydesc_metadata(md) => cast_safely(md), + block_metadata(md) => cast_safely(md), + argument_metadata(md) => cast_safely(md), + retval_metadata(md) => cast_safely(md) } } @@ -190,56 +188,52 @@ fn cached_metadata(cache: metadata_cache, mdtag: int, eq_fn: &fn(md: T) -> bool) -> Option { - unsafe { - if cache.contains_key(&mdtag) { - let items = cache.get(&mdtag); - for items.each |item| { - let md: T = md_from_metadata::(*item); - if eq_fn(md) { - return option::Some(md); - } + if cache.contains_key(&mdtag) { + let items = cache.get(&mdtag); + for items.each |item| { + let md: T = md_from_metadata::(*item); + if eq_fn(md) { + return option::Some(md); } } - return option::None; } + return option::None; } fn create_compile_unit(cx: @CrateContext) -> @Metadata { - unsafe { - let cache = get_cache(cx); - let crate_name = /*bad*/copy (/*bad*/copy cx.dbg_cx).get().crate_file; - let tg = CompileUnitTag; - match cached_metadata::<@Metadata>(cache, tg, - |md| md.data.name == crate_name) { - option::Some(md) => return md, - option::None => () - } + let cache = get_cache(cx); + let crate_name = /*bad*/copy (/*bad*/copy cx.dbg_cx).get().crate_file; + let tg = CompileUnitTag; + match cached_metadata::<@Metadata>(cache, tg, + |md| md.data.name == crate_name) { + option::Some(md) => return md, + option::None => () + } - let (_, work_dir) = get_file_path_and_dir( - cx.sess.working_dir.to_str(), crate_name); - let unit_metadata = ~[lltag(tg), - llunused(), - lli32(DW_LANG_RUST), - llstr(crate_name), - llstr(work_dir), - llstr(env!("CFG_VERSION")), - lli1(true), // deprecated: main compile unit - lli1(cx.sess.opts.optimize != session::No), - llstr(~""), // flags (???) - lli32(0) // runtime version (???) - ]; - let unit_node = llmdnode(unit_metadata); - add_named_metadata(cx, ~"llvm.dbg.cu", unit_node); - let mdval = @Metadata { - node: unit_node, - data: CompileUnitMetadata { - name: crate_name - } - }; - update_cache(cache, tg, compile_unit_metadata(mdval)); + let (_, work_dir) = get_file_path_and_dir( + cx.sess.working_dir.to_str(), crate_name); + let unit_metadata = ~[lltag(tg), + llunused(), + lli32(DW_LANG_RUST), + llstr(crate_name), + llstr(work_dir), + llstr(env!("CFG_VERSION")), + lli1(true), // deprecated: main compile unit + lli1(cx.sess.opts.optimize != session::No), + llstr(~""), // flags (???) + lli32(0) // runtime version (???) + ]; + let unit_node = llmdnode(unit_metadata); + add_named_metadata(cx, ~"llvm.dbg.cu", unit_node); + let mdval = @Metadata { + node: unit_node, + data: CompileUnitMetadata { + name: crate_name + } + }; + update_cache(cache, tg, compile_unit_metadata(mdval)); - return mdval; - } + return mdval; } fn get_cache(cx: @CrateContext) -> metadata_cache { @@ -368,7 +362,7 @@ fn create_basic_type(cx: @CrateContext, t: ty::t, span: span) ty::ty_uint(uint_ty) => match uint_ty { ast::ty_u => (~"uint", DW_ATE_unsigned), ast::ty_u8 => (~"u8", DW_ATE_unsigned), - ast::ty_u16 => (~"i16", DW_ATE_unsigned), + ast::ty_u16 => (~"u16", DW_ATE_unsigned), ast::ty_u32 => (~"u32", DW_ATE_unsigned), ast::ty_u64 => (~"u64", DW_ATE_unsigned) }, @@ -710,113 +704,109 @@ fn create_var(type_tag: int, context: ValueRef, name: &str, file: ValueRef, pub fn create_local_var(bcx: block, local: @ast::local) -> @Metadata { - unsafe { - let cx = bcx.ccx(); - let cache = get_cache(cx); - let tg = AutoVariableTag; - match cached_metadata::<@Metadata>( - cache, tg, |md| md.data.id == local.node.id) { - option::Some(md) => return md, - option::None => () + let cx = bcx.ccx(); + let cache = get_cache(cx); + let tg = AutoVariableTag; + match cached_metadata::<@Metadata>( + cache, tg, |md| md.data.id == local.node.id) { + option::Some(md) => return md, + option::None => () + } + + let name = match local.node.pat.node { + ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth), + // FIXME this should be handled (#2533) + _ => fail!(~"no single variable name for local") + }; + let loc = cx.sess.codemap.lookup_char_pos(local.span.lo); + let ty = node_id_type(bcx, local.node.id); + let tymd = create_ty(cx, ty, local.node.ty.span); + let filemd = create_file(cx, /*bad*/copy loc.file.name); + let context = match bcx.parent { + None => create_function(bcx.fcx).node, + Some(_) => create_block(bcx).node + }; + let mdnode = create_var(tg, context, *cx.sess.str_of(name), + filemd.node, loc.line as int, tymd.node); + let mdval = @Metadata { + node: mdnode, + data: LocalVarMetadata { + id: local.node.id } + }; + update_cache(cache, AutoVariableTag, local_var_metadata(mdval)); - let name = match local.node.pat.node { - ast::pat_ident(_, pth, _) => ast_util::path_to_ident(pth), - // FIXME this should be handled (#2533) - _ => fail!(~"no single variable name for local") - }; - let loc = cx.sess.codemap.lookup_char_pos(local.span.lo); - let ty = node_id_type(bcx, local.node.id); - let tymd = create_ty(cx, ty, local.node.ty.span); - let filemd = create_file(cx, /*bad*/copy loc.file.name); - let context = match bcx.parent { - None => create_function(bcx.fcx).node, - Some(_) => create_block(bcx).node - }; - let mdnode = create_var(tg, context, *cx.sess.str_of(name), - filemd.node, loc.line as int, tymd.node); - let mdval = @Metadata { - node: mdnode, - data: LocalVarMetadata { - id: local.node.id - } - }; - update_cache(cache, AutoVariableTag, local_var_metadata(mdval)); - - let llptr = match bcx.fcx.lllocals.find(&local.node.id) { - option::Some(&local_mem(v)) => v, - option::Some(_) => { - bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ - something weird"); - } - option::None => { - match *bcx.fcx.lllocals.get(&local.node.pat.id) { - local_imm(v) => v, - _ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ - something weird") - } - } - }; - let declargs = ~[llmdnode(~[llptr]), mdnode]; - trans::build::Call(bcx, *cx.intrinsics.get(&~"llvm.dbg.declare"), - declargs); - return mdval; - } + let llptr = match bcx.fcx.lllocals.find(&local.node.id) { + option::Some(&local_mem(v)) => v, + option::Some(_) => { + bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ + something weird"); + } + option::None => { + match *bcx.fcx.lllocals.get(&local.node.pat.id) { + local_imm(v) => v, + _ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ + something weird") + } + } + }; + let declargs = ~[llmdnode(~[llptr]), mdnode]; + trans::build::Call(bcx, *cx.intrinsics.get(&~"llvm.dbg.declare"), + declargs); + return mdval; } pub fn create_arg(bcx: block, arg: ast::arg, sp: span) -> Option<@Metadata> { - unsafe { - let fcx = bcx.fcx, cx = *fcx.ccx; - let cache = get_cache(cx); - let tg = ArgVariableTag; - match cached_metadata::<@Metadata>( - cache, ArgVariableTag, |md| md.data.id == arg.id) { - option::Some(md) => return Some(md), - option::None => () - } + let fcx = bcx.fcx, cx = *fcx.ccx; + let cache = get_cache(cx); + let tg = ArgVariableTag; + match cached_metadata::<@Metadata>( + cache, ArgVariableTag, |md| md.data.id == arg.id) { + option::Some(md) => return Some(md), + option::None => () + } - let loc = cx.sess.codemap.lookup_char_pos(sp.lo); - if loc.file.name == ~"" { - return None; + let loc = cx.sess.codemap.lookup_char_pos(sp.lo); + if loc.file.name == ~"" { + return None; + } + let ty = node_id_type(bcx, arg.id); + let tymd = create_ty(cx, ty, arg.ty.span); + let filemd = create_file(cx, /*bad*/copy loc.file.name); + let context = create_function(bcx.fcx); + + match arg.pat.node { + ast::pat_ident(_, path, _) => { + // XXX: This is wrong; it should work for multiple bindings. + let mdnode = create_var( + tg, + context.node, + *cx.sess.str_of(*path.idents.last()), + filemd.node, + loc.line as int, + tymd.node + ); + + let mdval = @Metadata { + node: mdnode, + data: ArgumentMetadata { + id: arg.id + } + }; + update_cache(cache, tg, argument_metadata(mdval)); + + let llptr = match *fcx.llargs.get(&arg.id) { + local_mem(v) | local_imm(v) => v, + }; + let declargs = ~[llmdnode(~[llptr]), mdnode]; + trans::build::Call(bcx, + *cx.intrinsics.get(&~"llvm.dbg.declare"), + declargs); + return Some(mdval); } - let ty = node_id_type(bcx, arg.id); - let tymd = create_ty(cx, ty, arg.ty.span); - let filemd = create_file(cx, /*bad*/copy loc.file.name); - let context = create_function(bcx.fcx); - - match arg.pat.node { - ast::pat_ident(_, path, _) => { - // XXX: This is wrong; it should work for multiple bindings. - let mdnode = create_var( - tg, - context.node, - *cx.sess.str_of(*path.idents.last()), - filemd.node, - loc.line as int, - tymd.node - ); - - let mdval = @Metadata { - node: mdnode, - data: ArgumentMetadata { - id: arg.id - } - }; - update_cache(cache, tg, argument_metadata(mdval)); - - let llptr = match *fcx.llargs.get(&arg.id) { - local_mem(v) | local_imm(v) => v, - }; - let declargs = ~[llmdnode(~[llptr]), mdnode]; - trans::build::Call(bcx, - *cx.intrinsics.get(&~"llvm.dbg.declare"), - declargs); - return Some(mdval); - } - _ => { - return None; - } + _ => { + return None; } } } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index dc910f9f178e3..d4a1013e83c85 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -153,7 +153,7 @@ use util::common::indenter; use util::ppaux::ty_to_str; use core::cast::transmute; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use syntax::print::pprust::{expr_to_str}; use syntax::ast; use syntax::codemap; @@ -1091,7 +1091,7 @@ pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { }; fn take_local(bcx: block, - table: &LinearMap, + table: &HashMap, nid: ast::node_id) -> Datum { let (v, mode) = match table.find(&nid) { Some(&local_mem(v)) => (v, ByRef), @@ -1714,7 +1714,6 @@ fn trans_assign_op(bcx: block, return result_datum.copy_to_datum(bcx, DROP_EXISTING, dst_datum); } -// NOTE: Mode neccessary here? fn shorten(+x: ~str) -> ~str { if x.len() > 60 { x.substr(0, 60).to_owned() } else { x } } diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 7dc2e385e2cf6..387caa4d8d31f 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -106,7 +106,8 @@ fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes { }; let llsig = foreign_signature(ccx, &fn_sig); let bundle_ty = T_struct(vec::append_one(copy llsig.llarg_tys, - T_ptr(llsig.llret_ty))); + T_ptr(llsig.llret_ty)), + false); let ret_def = !ty::type_is_bot(fn_sig.output) && !ty::type_is_nil(fn_sig.output); diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 1b27d21e6f464..827f4afaf783c 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -40,7 +40,6 @@ use core::libc::c_uint; use core::str; use std::time; use syntax::ast; -use syntax::parse::token::special_idents; pub fn trans_free(cx: block, v: ValueRef) -> block { let _icx = cx.insn_ctxt("trans_free"); @@ -400,11 +399,9 @@ pub fn call_tydesc_glue(++cx: block, v: ValueRef, t: ty::t, field: uint) pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) { let _icx = bcx.insn_ctxt("make_visit_glue"); let mut bcx = bcx; - let ty_visitor_name = special_idents::ty_visitor; - assert!(bcx.ccx().tcx.intrinsic_defs.contains_key(&ty_visitor_name)); - let (trait_id, ty) = *bcx.ccx().tcx.intrinsic_defs.get(&ty_visitor_name); - let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), ty))); - bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, trait_id); + let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx()); + let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), object_ty))); + bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id); build_return(bcx); } @@ -554,8 +551,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { ty::ty_closure(_) => { closure::make_closure_glue(bcx, v0, t, drop_ty) } - ty::ty_trait(_, _, ty::BoxTraitStore) | - ty::ty_trait(_, _, ty::BareTraitStore) => { + ty::ty_trait(_, _, ty::BoxTraitStore) => { let llbox = Load(bcx, GEPi(bcx, v0, [0u, 1u])); decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx)) } @@ -621,8 +617,7 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { ty::ty_closure(_) => { closure::make_closure_glue(bcx, v, t, take_ty) } - ty::ty_trait(_, _, ty::BoxTraitStore) | - ty::ty_trait(_, _, ty::BareTraitStore) => { + ty::ty_trait(_, _, ty::BoxTraitStore) => { let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u])); incr_refcnt_of_boxed(bcx, llbox); bcx @@ -689,15 +684,14 @@ pub fn declare_tydesc(ccx: @CrateContext, t: ty::t) -> @mut tydesc_info { let llalign = llalign_of(ccx, llty); let addrspace = declare_tydesc_addrspace(ccx, t); //XXX this triggers duplicate LLVM symbols - let name = if false /*ccx.sess.opts.debuginfo*/ { + let name = @(if false /*ccx.sess.opts.debuginfo*/ { mangle_internal_name_by_type_only(ccx, t, ~"tydesc") } else { mangle_internal_name_by_seq(ccx, ~"tydesc") - }; - // XXX: Bad copy. - note_unique_llvm_symbol(ccx, copy name); - debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), name); - let gvar = str::as_c_str(name, |buf| { + }); + note_unique_llvm_symbol(ccx, name); + debug!("+++ declare_tydesc %s %s", ppaux::ty_to_str(ccx.tcx, t), *name); + let gvar = str::as_c_str(*name, |buf| { unsafe { llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf) } @@ -723,17 +717,16 @@ pub fn declare_generic_glue(ccx: @CrateContext, t: ty::t, llfnty: TypeRef, +name: ~str) -> ValueRef { let _icx = ccx.insn_ctxt("declare_generic_glue"); let name = name; - let mut fn_nm; //XXX this triggers duplicate LLVM symbols - if false /*ccx.sess.opts.debuginfo*/ { - fn_nm = mangle_internal_name_by_type_only(ccx, t, (~"glue_" + name)); + let fn_nm = @(if false /*ccx.sess.opts.debuginfo*/ { + mangle_internal_name_by_type_only(ccx, t, (~"glue_" + name)) } else { - fn_nm = mangle_internal_name_by_seq(ccx, (~"glue_" + name)); - } - debug!("%s is for type %s", fn_nm, ppaux::ty_to_str(ccx.tcx, t)); + mangle_internal_name_by_seq(ccx, (~"glue_" + name)) + }); + debug!("%s is for type %s", *fn_nm, ppaux::ty_to_str(ccx.tcx, t)); // XXX: Bad copy. - note_unique_llvm_symbol(ccx, copy fn_nm); - let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty); + note_unique_llvm_symbol(ccx, fn_nm); + let llfn = decl_cdecl_fn(ccx.llmod, *fn_nm, llfnty); set_glue_inlining(llfn, t); return llfn; } diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index cb20e5bbd32c3..15c2e8e3d9350 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -86,14 +86,11 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, csearch::found(ast::ii_method(impl_did, mth)) => { ccx.stats.n_inlines += 1; ccx.external.insert(fn_id, Some(mth.id)); - let ty::ty_param_bounds_and_ty { - bounds: impl_bnds, - region_param: _, - ty: _ - } = ty::lookup_item_type(ccx.tcx, impl_did); - if translate && - impl_bnds.len() + mth.generics.ty_params.len() == 0u - { + let impl_tpt = ty::lookup_item_type(ccx.tcx, impl_did); + let num_type_params = + impl_tpt.generics.type_param_defs.len() + + mth.generics.ty_params.len(); + if translate && num_type_params == 0 { let llfn = get_item_val(ccx, mth.id); let path = vec::append( ty::item_path(ccx.tcx, impl_did), diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 1b9f7bae0e93f..cd90f964e452e 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -142,9 +142,9 @@ pub fn static_size_of_enum(cx: @CrateContext, t: ty::t) -> uint { debug!("static_size_of_enum: variant %s type %s", *cx.tcx.sess.str_of(variant.name), - ty_str(cx.tn, T_struct(lltypes))); + ty_str(cx.tn, T_struct(lltypes, false))); - let this_size = llsize_of_real(cx, T_struct(lltypes)); + let this_size = llsize_of_real(cx, T_struct(lltypes, false)); if max_size < this_size { max_size = this_size; } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index ed9000e7418a4..c518605faf13a 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -11,7 +11,6 @@ use core::prelude::*; use back::abi; -use driver; use lib::llvm::llvm; use lib::llvm::ValueRef; use lib; @@ -31,7 +30,7 @@ use middle::ty; use middle::ty::arg; use middle::typeck; use util::common::indenter; -use util::ppaux::ty_to_str; +use util::ppaux::Repr; use syntax::ast_map::{path, path_mod, path_name}; use syntax::ast_util; @@ -62,7 +61,7 @@ pub fn trans_impl(ccx: @CrateContext, +path: path, name: ast::ident, param_substs_opt = Some(@param_substs { tys: ~[], vtables: None, - bounds: @~[], + type_param_defs: @~[], self_ty: Some(self_ty) }); } @@ -116,11 +115,8 @@ pub fn trans_method(ccx: @CrateContext, } }; debug!("calling trans_fn with base_self_ty %s, self_ty %s", - match base_self_ty { - None => ~"(none)", - Some(x) => ty_to_str(ccx.tcx, x), - }, - ty_to_str(ccx.tcx, self_ty)); + base_self_ty.repr(ccx.tcx), + self_ty.repr(ccx.tcx)); match method.self_ty.node { ast::sty_value => { impl_owned_self(self_ty) @@ -174,9 +170,11 @@ pub fn trans_method_callee(bcx: block, mentry: typeck::method_map_entry) -> Callee { let _icx = bcx.insn_ctxt("impl::trans_method_callee"); + let tcx = bcx.tcx(); - debug!("trans_method_callee(callee_id=%?, self=%s, mentry=%?)", - callee_id, bcx.expr_to_str(self), mentry); + debug!("trans_method_callee(callee_id=%?, self=%s, mentry=%s)", + callee_id, bcx.expr_to_str(self), + mentry.repr(bcx.tcx())); // Replace method_self with method_static here. let mut origin = mentry.origin; @@ -189,33 +187,33 @@ pub fn trans_method_callee(bcx: block, // Get the ID of the method we're calling. let method_name = - ty::trait_methods(bcx.tcx(), trait_id)[method_index].ident; - let method_id = method_with_name(bcx.ccx(), impl_def_id, - method_name); + ty::trait_method(tcx, trait_id, method_index).ident; + let method_id = + method_with_name(bcx.ccx(), impl_def_id, method_name); origin = typeck::method_static(method_id); } typeck::method_super(trait_id, method_index) => { // is the self type for this method call let self_ty = node_id_type(bcx, self.id); - let tcx = bcx.tcx(); // is the ID of the implementation of // trait for type let impl_id = ty::get_impl_id(tcx, trait_id, self_ty); // Get the supertrait's methods - let supertrait_methods = ty::trait_methods(tcx, trait_id); + let supertrait_method_def_ids = ty::trait_method_def_ids(tcx, trait_id); // Make sure to fail with a readable error message if // there's some internal error here - if !(method_index < supertrait_methods.len()) { + if !(method_index < supertrait_method_def_ids.len()) { tcx.sess.bug(~"trans_method_callee: supertrait method \ index is out of bounds"); } // Get the method name using the method index in the origin - let method_name = supertrait_methods[method_index].ident; + let method_name = + ty::method(tcx, supertrait_method_def_ids[method_index]).ident; // Now that we know the impl ID, we can look up the method // ID from its name origin = typeck::method_static(method_with_name(bcx.ccx(), - impl_id, - method_name)); + impl_id, + method_name)); } typeck::method_static(*) | typeck::method_param(*) | typeck::method_trait(*) => {} @@ -301,8 +299,9 @@ pub fn trans_static_method_callee(bcx: block, // found on the type parametesr T1...Tn to find the index of the // one we are interested in. let bound_index = { - let trait_polyty = ty::lookup_item_type(bcx.tcx(), trait_id); - ty::count_traits_and_supertraits(bcx.tcx(), *trait_polyty.bounds) + let trait_def = ty::lookup_trait_def(bcx.tcx(), trait_id); + ty::count_traits_and_supertraits( + bcx.tcx(), *trait_def.generics.type_param_defs) }; let mname = if method_id.crate == ast::local_crate { @@ -375,7 +374,8 @@ pub fn method_with_name(ccx: @CrateContext, impl_id: ast::def_id, } } -pub fn method_with_name_or_default(ccx: @CrateContext, impl_id: ast::def_id, +pub fn method_with_name_or_default(ccx: @CrateContext, + impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { match *ccx.tcx.items.get(&impl_id.node) { @@ -448,7 +448,7 @@ pub fn trans_monomorphized_callee(bcx: block, return match vtbl { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { let ccx = bcx.ccx(); - let mname = ty::trait_methods(ccx.tcx, trait_id)[n_method].ident; + let mname = ty::trait_method(ccx.tcx, trait_id, n_method).ident; let mth_id = method_with_name_or_default( bcx.ccx(), impl_did, mname); @@ -550,13 +550,16 @@ pub fn combine_impl_and_methods_origins(bcx: block, // rcvr + method bounds. let ccx = bcx.ccx(), tcx = bcx.tcx(); let n_m_tps = method_ty_param_count(ccx, mth_did, impl_did); - let ty::ty_param_bounds_and_ty {bounds: r_m_bounds, _} - = ty::lookup_item_type(tcx, mth_did); - let n_r_m_tps = r_m_bounds.len(); // rcvr + method tps - let m_boundss = vec::slice(*r_m_bounds, n_r_m_tps - n_m_tps, n_r_m_tps); + let ty::ty_param_bounds_and_ty { + generics: r_m_generics, + _ + } = ty::lookup_item_type(tcx, mth_did); + let n_r_m_tps = r_m_generics.type_param_defs.len(); // rcvr + method tps + let m_type_param_defs = + vec::slice(*r_m_generics.type_param_defs, n_r_m_tps - n_m_tps, n_r_m_tps); // Flatten out to find the number of vtables the method expects. - let m_vtables = ty::count_traits_and_supertraits(tcx, m_boundss); + let m_vtables = ty::count_traits_and_supertraits(tcx, m_type_param_defs); // Find the vtables we computed at type check time and monomorphize them let r_m_origins = match node_vtables(bcx, callee_id) { @@ -654,7 +657,6 @@ pub fn trans_trait_callee_from_llval(bcx: block, // payload. match store { ty::BoxTraitStore | - ty::BareTraitStore | ty::UniqTraitStore => { llself = GEPi(bcx, llbox, [0u, abi::box_field_body]); } @@ -677,7 +679,7 @@ pub fn trans_trait_callee_from_llval(bcx: block, // Pass a pointer to the box. match store { - ty::BoxTraitStore | ty::BareTraitStore => llself = llbox, + ty::BoxTraitStore => llself = llbox, _ => bcx.tcx().sess.bug(~"@self receiver with non-@Trait") } @@ -783,18 +785,15 @@ pub fn make_impl_vtable(ccx: @CrateContext, let tcx = ccx.tcx; // XXX: This should support multiple traits. - let trt_id = driver::session::expect( - tcx.sess, - ty::ty_to_def_id(ty::impl_traits(tcx, - impl_id, - ty::BoxTraitStore)[0]), - || ~"make_impl_vtable: non-trait-type implemented"); - - let has_tps = (*ty::lookup_item_type(ccx.tcx, impl_id).bounds).len() > 0u; - make_vtable(ccx, vec::map(*ty::trait_methods(tcx, trt_id), |im| { + let trt_id = ty::impl_trait_refs(tcx, impl_id)[0].def_id; + + let has_tps = + !ty::lookup_item_type(ccx.tcx, impl_id).generics.type_param_defs.is_empty(); + make_vtable(ccx, ty::trait_method_def_ids(tcx, trt_id).map(|method_def_id| { + let im = ty::method(tcx, *method_def_id); let fty = ty::subst_tps(tcx, substs, None, ty::mk_bare_fn(tcx, copy im.fty)); - if (*im.tps).len() > 0u || ty::type_has_self(fty) { + if im.generics.has_type_params() || ty::type_has_self(fty) { debug!("(making impl vtable) method has self or type params: %s", *tcx.sess.str_of(im.ident)); C_null(T_ptr(T_nil())) @@ -841,7 +840,7 @@ pub fn trans_trait_cast(bcx: block, let v_ty = expr_ty(bcx, val); match store { - ty::RegionTraitStore(_) | ty::BoxTraitStore | ty::BareTraitStore => { + ty::RegionTraitStore(_) | ty::BoxTraitStore => { let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); // Just store the pointer into the pair. llboxdest = PointerCast(bcx, diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 89617ac5eb8c3..97dc3fed780f0 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -30,7 +30,7 @@ use middle::trans::type_use; use middle::ty; use middle::ty::{FnSig}; use middle::typeck; -use util::ppaux::ty_to_str; +use util::ppaux::Repr; use core::vec; use syntax::ast; @@ -46,8 +46,21 @@ pub fn monomorphic_fn(ccx: @CrateContext, real_substs: &[ty::t], vtables: Option, impl_did_opt: Option, - ref_id: Option) -> - (ValueRef, bool) { + ref_id: Option) + -> (ValueRef, bool) +{ + debug!("monomorphic_fn(\ + fn_id=%s, \ + real_substs=%s, \ + vtables=%s, \ + impl_did_opt=%s, \ + ref_id=%?)", + fn_id.repr(ccx.tcx), + real_substs.repr(ccx.tcx), + vtables.repr(ccx.tcx), + impl_did_opt.repr(ccx.tcx), + ref_id); + assert!(real_substs.all(|t| !ty::type_needs_infer(*t))); let _icx = ccx.insn_ctxt("monomorphic_fn"); let mut must_cast = false; @@ -69,13 +82,15 @@ pub fn monomorphic_fn(ccx: @CrateContext, must_cast = true; } - debug!("monomorphic_fn(fn_id=%? (%s), vtables=%?, \ - real_substs=%?, substs=%?, \ - hash_id = %?", - fn_id, ty::item_path_str(ccx.tcx, fn_id), - vtables, - real_substs.map(|s| ty_to_str(ccx.tcx, *s)), - substs.map(|s| ty_to_str(ccx.tcx, *s)), hash_id); + debug!("monomorphic_fn(\ + fn_id=%s, \ + vtables=%s, \ + substs=%s, \ + hash_id=%?)", + fn_id.repr(ccx.tcx), + vtables.repr(ccx.tcx), + substs.repr(ccx.tcx), + hash_id); match ccx.monomorphized.find(&hash_id) { Some(&val) => { @@ -169,7 +184,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, let psubsts = Some(@param_substs { tys: substs, vtables: vtables, - bounds: tpt.bounds, + type_param_defs: tpt.generics.type_param_defs, self_ty: impl_ty_opt }); @@ -291,7 +306,7 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt, ty::ty_trait(_, _, ref store) => { let sigil = match *store { ty::UniqTraitStore => ast::OwnedSigil, - ty::BoxTraitStore | ty::BareTraitStore => ast::ManagedSigil, + ty::BoxTraitStore => ast::ManagedSigil, ty::RegionTraitStore(_) => ast::BorrowedSigil, }; @@ -322,17 +337,19 @@ pub fn normalize_for_monomorphization(tcx: ty::ctxt, } } -pub fn make_mono_id(ccx: @CrateContext, item: ast::def_id, substs: &[ty::t], +pub fn make_mono_id(ccx: @CrateContext, + item: ast::def_id, + substs: &[ty::t], vtables: Option, impl_did_opt: Option, +param_uses: Option<~[type_use::type_uses]>) -> mono_id { let precise_param_ids = match vtables { Some(vts) => { - let bounds = ty::lookup_item_type(ccx.tcx, item).bounds; + let item_ty = ty::lookup_item_type(ccx.tcx, item); let mut i = 0; - vec::map2(*bounds, substs, |bounds, subst| { + vec::map2(*item_ty.generics.type_param_defs, substs, |type_param_def, subst| { let mut v = ~[]; - for bounds.each |bound| { + for type_param_def.bounds.each |bound| { match *bound { ty::bound_trait(_) => { v.push(meth::vtable_id(ccx, /*bad*/copy vts[i])); diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 8824e0b782909..9f9323bf9f788 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -21,7 +21,7 @@ use middle::ty; use middle::typeck; use core::prelude::*; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use syntax::ast; use syntax::ast::*; use syntax::ast_util::def_id_of_def; @@ -30,18 +30,18 @@ use syntax::codemap; use syntax::print::pprust::expr_to_str; use syntax::{visit, ast_map}; -pub type map = @LinearSet; +pub type map = @HashSet; struct ctx<'self> { exp_map2: resolve::ExportMap2, tcx: ty::ctxt, method_map: typeck::method_map, - rmap: &'self mut LinearSet, + rmap: &'self mut HashSet, } pub fn find_reachable(crate_mod: &_mod, exp_map2: resolve::ExportMap2, tcx: ty::ctxt, method_map: typeck::method_map) -> map { - let mut rmap = LinearSet::new(); + let mut rmap = HashSet::new(); { let cx = ctx { exp_map2: exp_map2, @@ -96,7 +96,7 @@ fn traverse_public_mod(cx: ctx, mod_id: node_id, m: &_mod) { fn traverse_public_item(cx: ctx, item: @item) { // XXX: it shouldn't be necessary to do this - let rmap: &mut LinearSet = cx.rmap; + let rmap: &mut HashSet = cx.rmap; if rmap.contains(&item.id) { return; } rmap.insert(item.id); match item.node { @@ -154,7 +154,7 @@ fn mk_ty_visitor() -> visit::vt { fn traverse_ty<'a>(ty: @Ty, cx: ctx<'a>, v: visit::vt>) { // XXX: it shouldn't be necessary to do this - let rmap: &mut LinearSet = cx.rmap; + let rmap: &mut HashSet = cx.rmap; if rmap.contains(&ty.id) { return; } rmap.insert(ty.id); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index a9869f15875c7..596c55a68f872 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -8,8 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -use lib::llvm::{TypeRef, ValueRef}; +use back::link::mangle_internal_name_by_path_and_seq; +use lib::llvm::{TypeRef, ValueRef, llvm}; +use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; use middle::trans::callee::{ArgVals, DontAutorefArg}; @@ -24,14 +25,17 @@ use middle::trans::type_of::*; use middle::ty; use util::ppaux::ty_to_str; +use core::libc::c_uint; use core::option::None; use core::vec; use syntax::ast::def_id; use syntax::ast; +use syntax::ast_map::path_name; +use syntax::parse::token::special_idents; pub struct Reflector { visitor_val: ValueRef, - visitor_methods: @~[ty::method], + visitor_methods: @~[@ty::method], final_bcx: block, tydesc_ty: TypeRef, bcx: block @@ -266,23 +270,52 @@ pub impl Reflector { // variant? ty::ty_enum(did, ref substs) => { let bcx = self.bcx; - let tcx = bcx.ccx().tcx; - let variants = ty::substd_enum_variants(tcx, did, substs); + let ccx = bcx.ccx(); + let repr = adt::represent_type(bcx.ccx(), t); + let variants = ty::substd_enum_variants(ccx.tcx, did, substs); + let llptrty = T_ptr(type_of(ccx, t)); + let (_, opaquety) = *(ccx.tcx.intrinsic_defs.find(&ccx.sess.ident_of(~"Opaque")) + .expect("Failed to resolve intrinsic::Opaque")); + let opaqueptrty = ty::mk_ptr(ccx.tcx, ty::mt { ty: opaquety, mutbl: ast::m_imm }); + + let make_get_disr = || { + let sub_path = bcx.fcx.path + ~[path_name(special_idents::anon)]; + let sym = mangle_internal_name_by_path_and_seq(ccx, sub_path, ~"get_disr"); + let args = [ty::arg { mode: ast::expl(ast::by_copy), + ty: opaqueptrty }]; + let llfty = type_of_fn(ccx, args, ty::mk_int(ccx.tcx)); + let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty); + let arg = unsafe { + llvm::LLVMGetParam(llfdecl, first_real_arg as c_uint) + }; + let fcx = new_fn_ctxt(ccx, ~[], llfdecl, None); + let bcx = top_scope_block(fcx, None); + let arg = BitCast(bcx, arg, llptrty); + let ret = adt::trans_get_discr(bcx, repr, arg); + Store(bcx, ret, fcx.llretptr); + cleanup_and_Br(bcx, bcx, fcx.llreturn); + finish_fn(fcx, bcx.llbb); + llfdecl + }; - let extra = ~[self.c_uint(vec::len(variants))] + let enum_args = ~[self.c_uint(vec::len(variants)), make_get_disr()] + self.c_size_and_align(t); - do self.bracketed(~"enum", extra) |this| { + do self.bracketed(~"enum", enum_args) |this| { for variants.eachi |i, v| { - let extra1 = ~[this.c_uint(i), - this.c_int(v.disr_val), - this.c_uint(vec::len(v.args)), - this.c_slice( - bcx.ccx().sess.str_of(v.name))]; - do this.bracketed(~"enum_variant", extra1) |this| { + let variant_args = ~[this.c_uint(i), + this.c_int(v.disr_val), + this.c_uint(vec::len(v.args)), + this.c_slice(ccx.sess.str_of(v.name))]; + do this.bracketed(~"enum_variant", variant_args) |this| { for v.args.eachi |j, a| { - let extra = ~[this.c_uint(j), - this.c_tydesc(*a)]; - this.visit(~"enum_variant_field", extra); + let bcx = this.bcx; + let null = C_null(llptrty); + let offset = p2i(ccx, adt::trans_field_ptr(bcx, repr, null, + v.disr_val, j)); + let field_args = ~[this.c_uint(j), + offset, + this.c_tydesc(*a)]; + this.visit(~"enum_variant_field", field_args); } } } diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index a9381647b3326..1c94fe2842219 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -128,11 +128,11 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_estr(ty::vstore_slice(*)) | ty::ty_evec(_, ty::vstore_slice(*)) => { - T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]) + T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())], false) } ty::ty_bare_fn(*) => T_ptr(T_i8()), - ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())]), + ty::ty_closure(*) => T_struct(~[T_ptr(T_i8()), T_ptr(T_i8())], false), ty::ty_trait(_, _, store) => T_opaque_trait(cx, store), ty::ty_estr(ty::vstore_fixed(size)) => T_array(T_i8(), size), @@ -142,9 +142,15 @@ pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_unboxed_vec(mt) => T_vec(cx, sizing_type_of(cx, mt.ty)), - ty::ty_tup(*) | ty::ty_struct(*) | ty::ty_enum(*) => { + ty::ty_tup(*) | ty::ty_enum(*) => { let repr = adt::represent_type(cx, t); - T_struct(adt::sizing_fields_of(cx, repr)) + T_struct(adt::sizing_fields_of(cx, repr), false) + } + + ty::ty_struct(did, _) => { + let repr = adt::represent_type(cx, t); + let packed = ty::lookup_packed(cx.tcx, did); + T_struct(adt::sizing_fields_of(cx, repr), packed) } ty::ty_self(_) | ty::ty_infer(*) | ty::ty_param(*) | ty::ty_err(*) => { @@ -223,12 +229,14 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_evec(ref mt, ty::vstore_slice(_)) => { T_struct(~[T_ptr(type_of(cx, mt.ty)), - T_uint_ty(cx, ast::ty_u)]) + T_uint_ty(cx, ast::ty_u)], + false) } ty::ty_estr(ty::vstore_slice(_)) => { T_struct(~[T_ptr(T_i8()), - T_uint_ty(cx, ast::ty_u)]) + T_uint_ty(cx, ast::ty_u)], + false) } ty::ty_estr(ty::vstore_fixed(n)) => { @@ -245,7 +253,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { ty::ty_type => T_ptr(cx.tydesc_type), ty::ty_tup(*) => { let repr = adt::represent_type(cx, t); - T_struct(adt::fields_of(cx, repr)) + T_struct(adt::fields_of(cx, repr), false) } ty::ty_opaque_closure_ptr(_) => T_opaque_box_ptr(cx), ty::ty_struct(did, ref substs) => { @@ -268,9 +276,17 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { // If this was an enum or struct, fill in the type now. match ty::get(t).sty { - ty::ty_enum(*) | ty::ty_struct(*) => { + ty::ty_enum(*) => { let repr = adt::represent_type(cx, t); - common::set_struct_body(llty, adt::fields_of(cx, repr)); + common::set_struct_body(llty, adt::fields_of(cx, repr), + false); + } + + ty::ty_struct(did, _) => { + let repr = adt::represent_type(cx, t); + let packed = ty::lookup_packed(cx.tcx, did); + common::set_struct_body(llty, adt::fields_of(cx, repr), + packed); } _ => () } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index fddcce523f447..f62e366ebdcaa 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -20,13 +20,15 @@ use middle::lint; use middle::resolve::{Impl, MethodInfo}; use middle::resolve; use middle::ty; +use middle::subst::Subst; use middle::typeck; use middle; use util::ppaux::{note_and_explain_region, bound_region_to_str}; -use util::ppaux::{region_to_str, vstore_to_str}; -use util::ppaux::{trait_store_to_str, ty_to_str, tys_to_str}; +use util::ppaux::{trait_store_to_str, ty_to_str, vstore_to_str}; +use util::ppaux::Repr; use util::common::{indenter}; +use core; use core::cast; use core::cmp; use core::ops; @@ -36,14 +38,16 @@ use core::result; use core::to_bytes; use core::uint; use core::vec; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use std::smallintmap::SmallIntMap; use syntax::ast::*; use syntax::ast_util::{is_local, local_def}; use syntax::ast_util; +use syntax::attr; use syntax::codemap::span; use syntax::codemap; use syntax::print::pprust; +use syntax::parse::token::special_idents; use syntax::{ast, ast_map}; use syntax::opt_vec::OptVec; use syntax::opt_vec; @@ -70,7 +74,8 @@ pub type param_bounds = @~[param_bound]; pub struct method { ident: ast::ident, - tps: @~[param_bounds], + generics: ty::Generics, + transformed_self_ty: Option, fty: BareFnTy, self_ty: ast::self_ty_, vis: ast::visibility, @@ -95,9 +100,8 @@ pub enum vstore { #[auto_encode] #[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum TraitStore { - BareTraitStore, // a plain trait without a sigil BoxTraitStore, // @Trait UniqTraitStore, // ~Trait RegionTraitStore(Region), // &Trait @@ -119,7 +123,7 @@ pub struct creader_cache_key { len: uint } -type creader_cache = @mut LinearMap; +type creader_cache = @mut HashMap; impl to_bytes::IterBytes for creader_cache_key { fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { @@ -194,13 +198,13 @@ pub enum AutoRefKind { /// Convert from T to &T AutoPtr, - /// Convert from @[]/~[] to &[] (or str) + /// Convert from @[]/~[]/&[] to &[] (or str) AutoBorrowVec, - /// Convert from @[]/~[] to &&[] (or str) + /// Convert from @[]/~[]/&[] to &&[] (or str) AutoBorrowVecRef, - /// Convert from @fn()/~fn() to &fn() + /// Convert from @fn()/~fn()/&fn() to &fn() AutoBorrowFn } @@ -210,7 +214,7 @@ pub enum AutoRefKind { // This is a map from ID of each implementation to the method info and trait // method ID of each of the default methods belonging to the trait that that // implementation implements. -pub type ProvidedMethodsMap = @mut LinearMap; +pub type ProvidedMethodsMap = @mut HashMap; // Stores the method info and definition ID of the associated trait method for // each instantiation of each provided method. @@ -224,16 +228,11 @@ pub struct ProvidedMethodSource { impl_id: ast::def_id } -pub struct InstantiatedTraitRef { - def_id: ast::def_id, - tpt: ty_param_substs_and_ty -} - pub type ctxt = @ctxt_; struct ctxt_ { diag: @syntax::diagnostic::span_handler, - interner: @mut LinearMap, + interner: @mut HashMap, next_id: @mut uint, vecs_implicitly_copyable: bool, legacy_modes: bool, @@ -241,7 +240,7 @@ struct ctxt_ { sess: session::Session, def_map: resolve::DefMap, - region_map: middle::region::region_map, + region_maps: @mut middle::region::RegionMaps, region_paramd_items: middle::region::region_paramd_items, // Stores the types for various nodes in the AST. Note that this table @@ -253,43 +252,59 @@ struct ctxt_ { // of this node. This only applies to nodes that refer to entities // parameterized by type parameters, such as generic fns, types, or // other items. - node_type_substs: @mut LinearMap, + node_type_substs: @mut HashMap, + + // Maps from a method to the method "descriptor" + methods: @mut HashMap, + + // Maps from a trait def-id to a list of the def-ids of its methods + trait_method_def_ids: @mut HashMap, + + // A cache for the trait_methods() routine + trait_methods_cache: @mut HashMap, + + trait_refs: @mut HashMap, + trait_defs: @mut HashMap, items: ast_map::map, - intrinsic_defs: @mut LinearMap, + intrinsic_defs: @mut HashMap, + intrinsic_traits: @mut HashMap, freevars: freevars::freevar_map, tcache: type_cache, rcache: creader_cache, ccache: constness_cache, - short_names_cache: @mut LinearMap, - needs_unwind_cleanup_cache: @mut LinearMap, - tc_cache: @mut LinearMap, - ast_ty_to_ty_cache: @mut LinearMap, - enum_var_cache: @mut LinearMap, - trait_method_cache: @mut LinearMap, - ty_param_bounds: @mut LinearMap, - inferred_modes: @mut LinearMap, - adjustments: @mut LinearMap, - normalized_cache: @mut LinearMap, + short_names_cache: @mut HashMap, + needs_unwind_cleanup_cache: @mut HashMap, + tc_cache: @mut HashMap, + ast_ty_to_ty_cache: @mut HashMap, + enum_var_cache: @mut HashMap, + ty_param_defs: @mut HashMap, + inferred_modes: @mut HashMap, + adjustments: @mut HashMap, + normalized_cache: @mut HashMap, lang_items: middle::lang_items::LanguageItems, // A mapping from an implementation ID to the method info and trait // method ID of the provided (a.k.a. default) methods in the traits that // that implementation implements. provided_methods: ProvidedMethodsMap, - provided_method_sources: @mut LinearMap, - supertraits: @mut LinearMap, + provided_method_sources: @mut HashMap, + supertraits: @mut HashMap, // A mapping from the def ID of an enum or struct type to the def ID // of the method that implements its destructor. If the type is not // present in this map, it does not have a destructor. This map is // populated during the coherence phase of typechecking. - destructor_for_type: @mut LinearMap, + destructor_for_type: @mut HashMap, // A method will be in this list if and only if it is a destructor. - destructors: @mut LinearSet, + destructors: @mut HashSet, // Maps a trait onto a mapping from self-ty to impl - trait_impls: @mut LinearMap> + trait_impls: @mut HashMap>, + + // Set of used unsafe nodes (functions or blocks). Unsafe nodes not + // present in this set can be warned about. + used_unsafe: @mut HashSet, } enum tbox_flag { @@ -390,23 +405,16 @@ impl to_bytes::IterBytes for ClosureTy { } } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct param_ty { idx: uint, def_id: def_id } -impl to_bytes::IterBytes for param_ty { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - to_bytes::iter_bytes_2(&self.idx, &self.def_id, lsb0, f) - } -} - - /// Representation of regions: #[auto_encode] #[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum Region { /// Bound regions are found (primarily) in function types. They indicate /// region parameters that have yet to be replaced with actual regions @@ -422,7 +430,7 @@ pub enum Region { /// When checking a function body, the types of all arguments and so forth /// that refer to bound region parameters are modified to refer to free /// region parameters. - re_free(node_id, bound_region), + re_free(FreeRegion), /// A concrete region naming some expression within the current function. re_scope(node_id), @@ -434,9 +442,26 @@ pub enum Region { re_infer(InferRegion) } +pub impl Region { + fn is_bound(&self) -> bool { + match self { + &re_bound(*) => true, + _ => false + } + } +} + #[auto_encode] #[auto_decode] -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] +pub struct FreeRegion { + scope_id: node_id, + bound_region: bound_region +} + +#[auto_encode] +#[auto_decode] +#[deriving(Eq, IterBytes)] pub enum bound_region { /// The self region for structs, impls (&T in a type defn or &'self T) br_self, @@ -527,6 +552,12 @@ pub enum sty { ty_unboxed_vec(mt), } +#[deriving(Eq, IterBytes)] +pub struct TraitRef { + def_id: def_id, + substs: substs +} + #[deriving(Eq)] pub enum IntVarValue { IntType(ast::int_ty), @@ -573,16 +604,17 @@ pub enum type_err { terr_self_substs, terr_integer_as_char, terr_int_mismatch(expected_found), - terr_float_mismatch(expected_found) + terr_float_mismatch(expected_found), + terr_traits(expected_found), } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub enum param_bound { bound_copy, bound_durable, bound_owned, bound_const, - bound_trait(t), + bound_trait(@TraitRef), } #[deriving(Eq)] @@ -651,19 +683,6 @@ impl cmp::Eq for InferRegion { } } -impl to_bytes::IterBytes for param_bound { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - match *self { - bound_copy => 0u8.iter_bytes(lsb0, f), - bound_durable => 1u8.iter_bytes(lsb0, f), - bound_owned => 2u8.iter_bytes(lsb0, f), - bound_const => 3u8.iter_bytes(lsb0, f), - bound_trait(ref t) => - to_bytes::iter_bytes_2(&4u8, t, lsb0, f) - } - } -} - pub trait Vid { fn to_uint(&self) -> uint; } @@ -750,6 +769,24 @@ impl to_bytes::IterBytes for RegionVid { } } +pub struct TypeParameterDef { + def_id: ast::def_id, + bounds: param_bounds +} + +/// Information about the type/lifetime parametesr associated with an item. +/// Analogous to ast::Generics. +pub struct Generics { + type_param_defs: @~[TypeParameterDef], + region_param: Option, +} + +pub impl Generics { + fn has_type_params(&self) -> bool { + !self.type_param_defs.is_empty() + } +} + /// A polytype. /// /// - `bounds`: The list of bounds for each type parameter. The length of the @@ -761,35 +798,40 @@ impl to_bytes::IterBytes for RegionVid { /// - `ty`: the base type. May have reference to the (unsubstituted) bound /// region `&self` or to (unsubstituted) ty_param types pub struct ty_param_bounds_and_ty { - bounds: @~[param_bounds], - region_param: Option, + generics: Generics, ty: t } +/// As `ty_param_bounds_and_ty` but for a trait ref. +pub struct TraitDef { + generics: Generics, + trait_ref: @ty::TraitRef, +} + pub struct ty_param_substs_and_ty { substs: ty::substs, ty: ty::t } -type type_cache = @mut LinearMap; +type type_cache = @mut HashMap; -type constness_cache = @mut LinearMap; +type constness_cache = @mut HashMap; pub type node_type_table = @mut SmallIntMap; fn mk_rcache() -> creader_cache { - return @mut LinearMap::new(); + return @mut HashMap::new(); } -pub fn new_ty_hash() -> @mut LinearMap { - @mut LinearMap::new() +pub fn new_ty_hash() -> @mut HashMap { + @mut HashMap::new() } pub fn mk_ctxt(s: session::Session, dm: resolve::DefMap, amap: ast_map::map, freevars: freevars::freevar_map, - region_map: middle::region::region_map, + region_maps: @mut middle::region::RegionMaps, region_paramd_items: middle::region::region_paramd_items, +lang_items: middle::lang_items::LanguageItems, crate: @ast::crate) @@ -809,40 +851,46 @@ pub fn mk_ctxt(s: session::Session, lint::vecs_implicitly_copyable) == allow; @ctxt_ { diag: s.diagnostic(), - interner: @mut LinearMap::new(), + interner: @mut HashMap::new(), next_id: @mut 0, vecs_implicitly_copyable: vecs_implicitly_copyable, legacy_modes: legacy_modes, cstore: s.cstore, sess: s, def_map: dm, - region_map: region_map, + region_maps: region_maps, region_paramd_items: region_paramd_items, node_types: @mut SmallIntMap::new(), - node_type_substs: @mut LinearMap::new(), + node_type_substs: @mut HashMap::new(), + trait_refs: @mut HashMap::new(), + trait_defs: @mut HashMap::new(), + intrinsic_traits: @mut HashMap::new(), items: amap, - intrinsic_defs: @mut LinearMap::new(), + intrinsic_defs: @mut HashMap::new(), freevars: freevars, - tcache: @mut LinearMap::new(), + tcache: @mut HashMap::new(), rcache: mk_rcache(), - ccache: @mut LinearMap::new(), + ccache: @mut HashMap::new(), short_names_cache: new_ty_hash(), needs_unwind_cleanup_cache: new_ty_hash(), - tc_cache: @mut LinearMap::new(), - ast_ty_to_ty_cache: @mut LinearMap::new(), - enum_var_cache: @mut LinearMap::new(), - trait_method_cache: @mut LinearMap::new(), - ty_param_bounds: @mut LinearMap::new(), - inferred_modes: @mut LinearMap::new(), - adjustments: @mut LinearMap::new(), + tc_cache: @mut HashMap::new(), + ast_ty_to_ty_cache: @mut HashMap::new(), + enum_var_cache: @mut HashMap::new(), + methods: @mut HashMap::new(), + trait_method_def_ids: @mut HashMap::new(), + trait_methods_cache: @mut HashMap::new(), + ty_param_defs: @mut HashMap::new(), + inferred_modes: @mut HashMap::new(), + adjustments: @mut HashMap::new(), normalized_cache: new_ty_hash(), lang_items: lang_items, - provided_methods: @mut LinearMap::new(), - provided_method_sources: @mut LinearMap::new(), - supertraits: @mut LinearMap::new(), - destructor_for_type: @mut LinearMap::new(), - destructors: @mut LinearSet::new(), - trait_impls: @mut LinearMap::new() + provided_methods: @mut HashMap::new(), + provided_method_sources: @mut HashMap::new(), + supertraits: @mut HashMap::new(), + destructor_for_type: @mut HashMap::new(), + destructors: @mut HashSet::new(), + trait_impls: @mut HashMap::new(), + used_unsafe: @mut HashSet::new(), } } @@ -1150,15 +1198,6 @@ pub fn default_arg_mode_for_ty(tcx: ctxt, ty: ty::t) -> ast::rmode { } } -// Returns the narrowest lifetime enclosing the evaluation of the expression -// with id `id`. -pub fn encl_region(cx: ctxt, id: ast::node_id) -> ty::Region { - match cx.region_map.find(&id) { - Some(&encl_scope) => ty::re_scope(encl_scope), - None => ty::re_static - } -} - pub fn walk_ty(ty: t, f: &fn(t)) { maybe_walk_ty(ty, |t| { f(t); true }); } @@ -1206,6 +1245,12 @@ pub fn fold_sig(sig: &FnSig, fldop: &fn(t) -> t) -> FnSig { } } +pub fn fold_bare_fn_ty(fty: &BareFnTy, fldop: &fn(t) -> t) -> BareFnTy { + BareFnTy {sig: fold_sig(&fty.sig, fldop), + abis: fty.abis, + purity: fty.purity} +} + fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { fn fold_substs(substs: &substs, fldop: &fn(t) -> t) -> substs { substs {self_r: substs.self_r, @@ -1240,8 +1285,7 @@ fn fold_sty(sty: &sty, fldop: &fn(t) -> t) -> sty { ty_tup(new_ts) } ty_bare_fn(ref f) => { - let sig = fold_sig(&f.sig, fldop); - ty_bare_fn(BareFnTy {sig: sig, abis: f.abis, purity: f.purity}) + ty_bare_fn(fold_bare_fn_ty(f, fldop)) } ty_closure(ref f) => { let sig = fold_sig(&f.sig, fldop); @@ -1277,8 +1321,8 @@ pub fn walk_regions_and_ty( fold_regions_and_ty( cx, ty, |r| { walkr(r); r }, - |t| { walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t }, - |t| { walkt(t); walk_regions_and_ty(cx, t, walkr, walkt); t }); + |t| { walk_regions_and_ty(cx, t, walkr, walkt); t }, + |t| { walk_regions_and_ty(cx, t, walkr, walkt); t }); } } @@ -1388,81 +1432,22 @@ pub fn substs_is_noop(substs: &substs) -> bool { } pub fn substs_to_str(cx: ctxt, substs: &substs) -> ~str { - fmt!("substs(self_r=%s, self_ty=%s, tps=%?)", - substs.self_r.map_default(~"none", |r| region_to_str(cx, *r)), - substs.self_ty.map_default(~"none", - |t| ::util::ppaux::ty_to_str(cx, *t)), - tys_to_str(cx, substs.tps)) + substs.repr(cx) } pub fn param_bound_to_str(cx: ctxt, pb: ¶m_bound) -> ~str { - match *pb { - bound_copy => ~"copy", - bound_durable => ~"'static", - bound_owned => ~"owned", - bound_const => ~"const", - bound_trait(t) => ::util::ppaux::ty_to_str(cx, t) - } + pb.repr(cx) } pub fn param_bounds_to_str(cx: ctxt, pbs: param_bounds) -> ~str { - fmt!("%?", pbs.map(|pb| param_bound_to_str(cx, pb))) + pbs.repr(cx) } pub fn subst(cx: ctxt, substs: &substs, typ: t) -> t { - debug!("subst(substs=%s, typ=%s)", - substs_to_str(cx, substs), - ::util::ppaux::ty_to_str(cx, typ)); - - if substs_is_noop(substs) { return typ; } - let r = do_subst(cx, substs, typ); - debug!(" r = %s", ::util::ppaux::ty_to_str(cx, r)); - return r; - - fn do_subst(cx: ctxt, - substs: &substs, - typ: t) -> t { - let tb = get(typ); - if !tbox_has_flag(tb, needs_subst) { return typ; } - match tb.sty { - ty_param(p) => substs.tps[p.idx], - ty_self(_) => substs.self_ty.get(), - _ => { - fold_regions_and_ty( - cx, typ, - |r| match r { - re_bound(br_self) => { - match substs.self_r { - None => { - cx.sess.bug( - fmt!("ty::subst: \ - Reference to self region when given substs \ - with no self region, ty = %s", - ::util::ppaux::ty_to_str(cx, typ))) - } - Some(self_r) => self_r - } - } - _ => r - }, - |t| do_subst(cx, substs, t), - |t| do_subst(cx, substs, t)) - } - } - } -} - -// Performs substitutions on a set of substitutions (result = sup(sub)) to -// yield a new set of substitutions. This is used in trait inheritance. -pub fn subst_substs(cx: ctxt, sup: &substs, sub: &substs) -> substs { - substs { - self_r: sup.self_r, - self_ty: sup.self_ty.map(|typ| subst(cx, sub, *typ)), - tps: sup.tps.map(|typ| subst(cx, sub, *typ)) - } + typ.subst(cx, substs) } // Type utilities @@ -1477,6 +1462,15 @@ pub fn type_is_error(ty: t) -> bool { (get(ty).flags & (has_ty_err as uint)) != 0 } +pub fn type_needs_subst(ty: t) -> bool { + tbox_has_flag(get(ty), needs_subst) +} + +pub fn trait_ref_contains_error(tref: &ty::TraitRef) -> bool { + tref.substs.self_ty.any(|&t| type_is_error(t)) || + tref.substs.tps.any(|&t| type_is_error(t)) +} + pub fn type_is_ty_var(ty: t) -> bool { match get(ty).sty { ty_infer(TyVar(_)) => true, @@ -1620,7 +1614,7 @@ pub fn type_needs_unwind_cleanup(cx: ctxt, ty: t) -> bool { None => () } - let mut tycache = LinearSet::new(); + let mut tycache = HashSet::new(); let needs_unwind_cleanup = type_needs_unwind_cleanup_(cx, ty, &mut tycache, false); cx.needs_unwind_cleanup_cache.insert(ty, needs_unwind_cleanup); @@ -1628,7 +1622,7 @@ pub fn type_needs_unwind_cleanup(cx: ctxt, ty: t) -> bool { } fn type_needs_unwind_cleanup_(cx: ctxt, ty: t, - tycache: &mut LinearSet, + tycache: &mut HashSet, encountered_box: bool) -> bool { // Prevent infinite recursion @@ -1855,14 +1849,14 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { None => {} } - let mut cache = LinearMap::new(); + let mut cache = HashMap::new(); let result = tc_ty(cx, ty, &mut cache); cx.tc_cache.insert(ty_id, result); return result; fn tc_ty(cx: ctxt, ty: t, - cache: &mut LinearMap) -> TypeContents + cache: &mut HashMap) -> TypeContents { // Subtle: Note that we are *not* using cx.tc_cache here but rather a // private cache for this walk. This is needed in the case of cyclic @@ -1921,8 +1915,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { TC_OWNED_CLOSURE } - ty_trait(_, _, BoxTraitStore) | - ty_trait(_, _, BareTraitStore) => { + ty_trait(_, _, BoxTraitStore) => { TC_MANAGED } @@ -2008,8 +2001,8 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { // def-id. assert!(p.def_id.crate == ast::local_crate); - param_bounds_to_contents( - cx, *cx.ty_param_bounds.get(&p.def_id.node)) + type_param_def_to_contents( + cx, cx.ty_param_defs.get(&p.def_id.node)) } ty_self(_) => { @@ -2054,7 +2047,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { fn tc_mt(cx: ctxt, mt: mt, - cache: &mut LinearMap) -> TypeContents + cache: &mut HashMap) -> TypeContents { let mc = if mt.mutbl == m_mutbl {TC_MUTABLE} else {TC_NONE}; mc + tc_ty(cx, mt.ty, cache) @@ -2103,13 +2096,13 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { st + rt + ot } - fn param_bounds_to_contents(cx: ctxt, - bounds: param_bounds) -> TypeContents + fn type_param_def_to_contents(cx: ctxt, + type_param_def: &TypeParameterDef) -> TypeContents { - debug!("param_bounds_to_contents()"); + debug!("type_param_def_to_contents(%s)", type_param_def.repr(cx)); let _i = indenter(); - let r = bounds.foldl(TC_ALL, |tc, bound| { + let r = type_param_def.bounds.foldl(TC_ALL, |tc, bound| { debug!("tc = %s, bound = %?", tc.to_str(), bound); match *bound { bound_copy => tc - TypeContents::nonimplicitly_copyable(cx), @@ -2526,43 +2519,52 @@ pub fn index_sty(cx: ctxt, sty: &sty) -> Option { } } -impl to_bytes::IterBytes for bound_region { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - match *self { - ty::br_self => 0u8.iter_bytes(lsb0, f), - - ty::br_anon(ref idx) => - to_bytes::iter_bytes_2(&1u8, idx, lsb0, f), - - ty::br_named(ref ident) => - to_bytes::iter_bytes_2(&2u8, ident, lsb0, f), +/** + * Enforces an arbitrary but consistent total ordering over + * free regions. This is needed for establishing a consistent + * LUB in region_inference. */ +impl cmp::TotalOrd for FreeRegion { + fn cmp(&self, other: &FreeRegion) -> Ordering { + cmp::cmp2(&self.scope_id, &self.bound_region, + &other.scope_id, &other.bound_region) + } +} - ty::br_cap_avoid(ref id, ref br) => - to_bytes::iter_bytes_3(&3u8, id, br, lsb0, f), +impl cmp::TotalEq for FreeRegion { + fn equals(&self, other: &FreeRegion) -> bool { + *self == *other + } +} - ty::br_fresh(ref x) => - to_bytes::iter_bytes_2(&4u8, x, lsb0, f) +/** + * Enforces an arbitrary but consistent total ordering over + * bound regions. This is needed for establishing a consistent + * LUB in region_inference. */ +impl cmp::TotalOrd for bound_region { + fn cmp(&self, other: &bound_region) -> Ordering { + match (self, other) { + (&ty::br_self, &ty::br_self) => cmp::Equal, + (&ty::br_self, _) => cmp::Less, + + (&ty::br_anon(ref a1), &ty::br_anon(ref a2)) => a1.cmp(a2), + (&ty::br_anon(*), _) => cmp::Less, + + (&ty::br_named(ref a1), &ty::br_named(ref a2)) => a1.repr.cmp(&a2.repr), + (&ty::br_named(*), _) => cmp::Less, + + (&ty::br_cap_avoid(ref a1, @ref b1), + &ty::br_cap_avoid(ref a2, @ref b2)) => cmp::cmp2(a1, b1, a2, b2), + (&ty::br_cap_avoid(*), _) => cmp::Less, + + (&ty::br_fresh(ref a1), &ty::br_fresh(ref a2)) => a1.cmp(a2), + (&ty::br_fresh(*), _) => cmp::Less, } } } -impl to_bytes::IterBytes for Region { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - match *self { - re_bound(ref br) => - to_bytes::iter_bytes_2(&0u8, br, lsb0, f), - - re_free(ref id, ref br) => - to_bytes::iter_bytes_3(&1u8, id, br, lsb0, f), - - re_scope(ref id) => - to_bytes::iter_bytes_2(&2u8, id, lsb0, f), - - re_infer(ref id) => - to_bytes::iter_bytes_2(&3u8, id, lsb0, f), - - re_static => 4u8.iter_bytes(lsb0, f) - } +impl cmp::TotalEq for bound_region { + fn equals(&self, other: &bound_region) -> bool { + *self == *other } } @@ -2581,17 +2583,6 @@ impl to_bytes::IterBytes for vstore { } } -impl to_bytes::IterBytes for TraitStore { - fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { - match *self { - BareTraitStore => 0u8.iter_bytes(lsb0, f), - UniqTraitStore => 1u8.iter_bytes(lsb0, f), - BoxTraitStore => 2u8.iter_bytes(lsb0, f), - RegionTraitStore(ref r) => to_bytes::iter_bytes_2(&3u8, r, lsb0, f), - } - } -} - impl to_bytes::IterBytes for substs { fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) { to_bytes::iter_bytes_3(&self.self_r, @@ -2704,6 +2695,16 @@ impl to_bytes::IterBytes for sty { } } +pub fn node_id_to_trait_ref(cx: ctxt, id: ast::node_id) -> @ty::TraitRef { + match cx.trait_refs.find(&id) { + Some(&t) => t, + None => cx.sess.bug( + fmt!("node_id_to_trait_ref: no trait ref for node `%s`", + ast_map::node_id_to_str(cx.items, id, + cx.sess.parse_sess.interner))) + } +} + pub fn node_id_to_type(cx: ctxt, id: ast::node_id) -> t { //io::println(fmt!("%?/%?", id, cx.node_types.len())); match cx.node_types.find(&(id as uint)) { @@ -2726,6 +2727,16 @@ fn node_id_has_type_params(cx: ctxt, id: ast::node_id) -> bool { cx.node_type_substs.contains_key(&id) } +pub fn ty_fn_sig(fty: t) -> FnSig { + match get(fty).sty { + ty_bare_fn(ref f) => copy f.sig, + ty_closure(ref f) => copy f.sig, + ref s => { + fail!(fmt!("ty_fn_sig() called on non-fn type: %?", s)) + } + } +} + // Type accessors for substructures of types pub fn ty_fn_args(fty: t) -> ~[arg] { match get(fty).sty { @@ -2867,8 +2878,17 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { */ let unadjusted_ty = expr_ty(cx, expr); + adjust_ty(cx, expr.span, unadjusted_ty, cx.adjustments.find(&expr.id)) +} + +pub fn adjust_ty(cx: ctxt, + span: span, + unadjusted_ty: ty::t, + adjustment: Option<&@AutoAdjustment>) -> ty::t +{ + /*! See `expr_ty_adjusted` */ - return match cx.adjustments.find(&expr.id) { + return match adjustment { None => unadjusted_ty, Some(&@AutoAddEnv(r, s)) => { @@ -2897,7 +2917,7 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { Some(mt) => { adjusted_ty = mt.ty; } None => { cx.sess.span_bug( - expr.span, + span, fmt!("The %uth autoderef failed: %s", i, ty_to_str(cx, adjusted_ty))); @@ -2916,18 +2936,18 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { } AutoBorrowVec => { - borrow_vec(cx, expr, autoref, adjusted_ty) + borrow_vec(cx, span, autoref, adjusted_ty) } AutoBorrowVecRef => { - adjusted_ty = borrow_vec(cx, expr, autoref, + adjusted_ty = borrow_vec(cx, span, autoref, adjusted_ty); mk_rptr(cx, autoref.region, mt {ty: adjusted_ty, mutbl: ast::m_imm}) } AutoBorrowFn => { - borrow_fn(cx, expr, autoref, adjusted_ty) + borrow_fn(cx, span, autoref, adjusted_ty) } } } @@ -2935,7 +2955,7 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { } }; - fn borrow_vec(cx: ctxt, expr: @ast::expr, + fn borrow_vec(cx: ctxt, span: span, autoref: &AutoRef, ty: ty::t) -> ty::t { match get(ty).sty { ty_evec(mt, _) => { @@ -2949,14 +2969,14 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { ref s => { cx.sess.span_bug( - expr.span, + span, fmt!("borrow-vec associated with bad sty: %?", s)); } } } - fn borrow_fn(cx: ctxt, expr: @ast::expr, + fn borrow_fn(cx: ctxt, span: span, autoref: &AutoRef, ty: ty::t) -> ty::t { match get(ty).sty { ty_closure(ref fty) => { @@ -2969,7 +2989,7 @@ pub fn expr_ty_adjusted(cx: ctxt, expr: @ast::expr) -> t { ref s => { cx.sess.span_bug( - expr.span, + span, fmt!("borrow-fn associated with bad sty: %?", s)); } @@ -2995,16 +3015,18 @@ pub fn expr_has_ty_params(cx: ctxt, expr: @ast::expr) -> bool { return node_id_has_type_params(cx, expr.id); } -pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, - id: ast::node_id) - -> Option<@~[param_bounds]> { +pub fn method_call_type_param_defs( + tcx: ctxt, + method_map: typeck::method_map, + id: ast::node_id) -> Option<@~[TypeParameterDef]> +{ do method_map.find(&id).map |method| { match method.origin { typeck::method_static(did) => { // n.b.: When we encode impl methods, the bounds // that we encode include both the impl bounds // and then the method bounds themselves... - ty::lookup_item_type(tcx, did).bounds + ty::lookup_item_type(tcx, did).generics.type_param_defs } typeck::method_param(typeck::method_param { trait_id: trt_id, @@ -3015,10 +3037,11 @@ pub fn method_call_bounds(tcx: ctxt, method_map: typeck::method_map, // ...trait methods bounds, in contrast, include only the // method bounds, so we must preprend the tps from the // trait itself. This ought to be harmonized. - let trt_bounds = - ty::lookup_item_type(tcx, trt_id).bounds; - @(vec::append(/*bad*/copy *trt_bounds, - *ty::trait_methods(tcx, trt_id)[n_mth].tps)) + let trait_type_param_defs = + ty::lookup_trait_def(tcx, trt_id).generics.type_param_defs; + @vec::append( + copy *trait_type_param_defs, + *ty::trait_method(tcx, trt_id, n_mth).generics.type_param_defs) } } } @@ -3203,10 +3226,8 @@ pub fn field_idx_strict(tcx: ty::ctxt, id: ast::ident, fields: &[field]) fields.map(|f| tcx.sess.str_of(f.ident)))); } -pub fn method_idx(id: ast::ident, meths: &[method]) -> Option { - let mut i = 0u; - for meths.each |m| { if m.ident == id { return Some(i); } i += 1u; } - return None; +pub fn method_idx(id: ast::ident, meths: &[@method]) -> Option { + vec::position(meths, |m| m.ident == id) } /// Returns a vector containing the indices of all type parameters that appear @@ -3258,7 +3279,7 @@ pub fn occurs_check(tcx: ctxt, sp: span, vid: TyVid, rt: t) { // Maintains a little union-set tree for inferred modes. `canon()` returns // the current head value for `m0`. -fn canon(tbl: &mut LinearMap>, +fn canon(tbl: &mut HashMap>, +m0: ast::inferable) -> ast::inferable { match m0 { ast::infer(id) => { @@ -3469,6 +3490,11 @@ pub fn type_err_to_str(cx: ctxt, err: &type_err) -> ~str { ty_sort_str(cx, values.expected), ty_sort_str(cx, values.found)) } + terr_traits(values) => { + fmt!("expected trait %s but found trait %s", + item_path_str(cx, values.expected), + item_path_str(cx, values.found)) + } terr_self_substs => { ~"inconsistent self substitution" // XXX this is more of a bug } @@ -3527,10 +3553,6 @@ pub fn def_has_ty_params(def: ast::def) -> bool { } } -pub fn store_trait_methods(cx: ctxt, id: ast::node_id, ms: @~[method]) { - cx.trait_method_cache.insert(ast_util::local_def(id), ms); -} - pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] { if is_local(id) { match cx.items.find(&id.node) { @@ -3550,11 +3572,11 @@ pub fn provided_trait_methods(cx: ctxt, id: ast::def_id) -> ~[ast::ident] { } pub fn trait_supertraits(cx: ctxt, - id: ast::def_id) - -> @~[InstantiatedTraitRef] { + id: ast::def_id) -> @~[@TraitRef] +{ // Check the cache. match cx.supertraits.find(&id) { - Some(&instantiated_trait_info) => { return instantiated_trait_info; } + Some(&trait_refs) => { return trait_refs; } None => {} // Continue. } @@ -3563,63 +3585,79 @@ pub fn trait_supertraits(cx: ctxt, assert!(!is_local(id)); // Get the supertraits out of the metadata and create the - // InstantiatedTraitRef for each. - let mut result = ~[]; - for csearch::get_supertraits(cx, id).each |trait_type| { - match get(*trait_type).sty { - ty_trait(def_id, ref substs, _) => { - result.push(InstantiatedTraitRef { - def_id: def_id, - tpt: ty_param_substs_and_ty { - substs: (/*bad*/copy *substs), - ty: *trait_type - } - }); - } - _ => cx.sess.bug(~"trait_supertraits: trait ref wasn't a trait") - } - } + // TraitRef for each. + let result = @csearch::get_supertraits(cx, id); + cx.supertraits.insert(id, result); + return result; +} - // Unwrap and return the result. - return @result; +pub fn trait_ref_supertraits(cx: ctxt, trait_ref: &ty::TraitRef) -> ~[@TraitRef] { + let supertrait_refs = trait_supertraits(cx, trait_ref.def_id); + supertrait_refs.map( + |supertrait_ref| @supertrait_ref.subst(cx, &trait_ref.substs)) } -pub fn trait_methods(cx: ctxt, id: ast::def_id) -> @~[method] { - match cx.trait_method_cache.find(&id) { - // Local traits are supposed to have been added explicitly. - Some(&ms) => ms, - _ => { - // If the lookup in trait_method_cache fails, assume that the trait - // method we're trying to look up is in a different crate, and look - // for it there. - assert!(id.crate != ast::local_crate); - let result = csearch::get_trait_methods(cx, id); +fn lookup_locally_or_in_crate_store( + descr: &str, + def_id: ast::def_id, + map: &mut HashMap, + load_external: &fn() -> V) -> V +{ + /*! + * + * Helper for looking things up in the various maps + * that are populated during typeck::collect (e.g., + * `cx.methods`, `cx.tcache`, etc). All of these share + * the pattern that if the id is local, it should have + * been loaded into the map by the `typeck::collect` phase. + * If the def-id is external, then we have to go consult + * the crate loading code (and cache the result for the future). + */ - // Store the trait method in the local trait_method_cache so that - // future lookups succeed. - cx.trait_method_cache.insert(id, result); - result - } + match map.find(&def_id) { + Some(&v) => { return v; } + None => { } } + + if def_id.crate == ast::local_crate { + fail!(fmt!("No def'n found for %? in tcx.%s", + def_id, descr)); + } + let v = load_external(); + map.insert(def_id, v); + return v; } -/* - Could this return a list of (def_id, substs) pairs? - */ -pub fn impl_traits(cx: ctxt, id: ast::def_id, store: TraitStore) -> ~[t] { - fn storeify(cx: ctxt, ty: t, store: TraitStore) -> t { - match ty::get(ty).sty { - ty::ty_trait(did, ref substs, trait_store) => { - if store == trait_store { - ty - } else { - mk_trait(cx, did, (/*bad*/copy *substs), store) - } - } - _ => cx.sess.bug(~"impl_traits: not a trait") +pub fn trait_method(cx: ctxt, trait_did: ast::def_id, idx: uint) -> @method { + let method_def_id = ty::trait_method_def_ids(cx, trait_did)[idx]; + ty::method(cx, method_def_id) +} + +pub fn trait_methods(cx: ctxt, trait_did: ast::def_id) -> @~[@method] { + match cx.trait_methods_cache.find(&trait_did) { + Some(&methods) => methods, + None => { + let def_ids = ty::trait_method_def_ids(cx, trait_did); + let methods = @def_ids.map(|d| ty::method(cx, *d)); + cx.trait_methods_cache.insert(trait_did, methods); + methods } } +} + +pub fn method(cx: ctxt, id: ast::def_id) -> @method { + lookup_locally_or_in_crate_store( + "methods", id, cx.methods, + || @csearch::get_method(cx, id)) +} + +pub fn trait_method_def_ids(cx: ctxt, id: ast::def_id) -> @~[def_id] { + lookup_locally_or_in_crate_store( + "methods", id, cx.trait_method_def_ids, + || @csearch::get_trait_method_def_ids(cx.cstore, id)) +} +pub fn impl_trait_refs(cx: ctxt, id: ast::def_id) -> ~[@TraitRef] { if id.crate == ast::local_crate { debug!("(impl_traits) searching for trait impl %?", id); match cx.items.find(&id.node) { @@ -3627,17 +3665,15 @@ pub fn impl_traits(cx: ctxt, id: ast::def_id, store: TraitStore) -> ~[t] { node: ast::item_impl(_, opt_trait, _, _), _}, _)) => { - - do opt_trait.map_default(~[]) |trait_ref| { - ~[storeify(cx, node_id_to_type(cx, trait_ref.ref_id), - store)] + match opt_trait { + Some(t) => ~[ty::node_id_to_trait_ref(cx, t.ref_id)], + None => ~[] } } _ => ~[] } } else { - vec::map(csearch::get_impl_traits(cx, id), - |x| storeify(cx, *x, store)) + csearch::get_impl_traits(cx, id) } } @@ -3906,18 +3942,47 @@ pub fn enum_variant_with_id(cx: ctxt, pub fn lookup_item_type(cx: ctxt, did: ast::def_id) -> ty_param_bounds_and_ty { - match cx.tcache.find(&did) { - Some(&tpt) => { - // The item is in this crate. The caller should have added it to the - // type cache already - return tpt; - } - None => { - assert!(did.crate != ast::local_crate); - let tyt = csearch::get_type(cx, did); - cx.tcache.insert(did, tyt); - return tyt; - } + lookup_locally_or_in_crate_store( + "tcache", did, cx.tcache, + || csearch::get_type(cx, did)) +} + +/// Given the did of a trait, returns its canonical trait ref. +pub fn lookup_trait_def(cx: ctxt, did: ast::def_id) -> @ty::TraitDef { + match cx.trait_defs.find(&did) { + Some(&trait_def) => { + // The item is in this crate. The caller should have added it to the + // type cache already + return trait_def; + } + None => { + assert!(did.crate != ast::local_crate); + let trait_def = @csearch::get_trait_def(cx, did); + cx.trait_defs.insert(did, trait_def); + return trait_def; + } + } +} + +// Determine whether an item is annotated with #[packed] or not +pub fn lookup_packed(tcx: ctxt, + did: def_id) -> bool { + if is_local(did) { + match tcx.items.find(&did.node) { + Some( + &ast_map::node_item(@ast::item { + attrs: ref attrs, + _ + }, _)) => attr::attrs_contains_name(*attrs, "packed"), + _ => tcx.sess.bug(fmt!("lookup_packed: %? is not an item", + did)) + } + } else { + let mut ret = false; + do csearch::get_item_attrs(tcx.cstore, did) |meta_items| { + ret = attr::contains_name(meta_items, "packed"); + } + ret } } @@ -4204,9 +4269,6 @@ pub fn normalize_ty(cx: ctxt, t: t) -> t { t }, - ty_trait(did, ref substs, BareTraitStore) => - mk_trait(cx, did, copy *substs, BoxTraitStore), - _ => t }; @@ -4252,16 +4314,16 @@ pub fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr) -> uint { } // Determine what purity to check a nested function under -pub fn determine_inherited_purity(parent_purity: ast::purity, - child_purity: ast::purity, - child_sigil: ast::Sigil) - -> ast::purity { +pub fn determine_inherited_purity(parent: (ast::purity, ast::node_id), + child: (ast::purity, ast::node_id), + child_sigil: ast::Sigil) + -> (ast::purity, ast::node_id) { // If the closure is a stack closure and hasn't had some non-standard // purity inferred for it, then check it under its parent's purity. // Otherwise, use its own match child_sigil { - ast::BorrowedSigil if child_purity == ast::impure_fn => parent_purity, - _ => child_purity + ast::BorrowedSigil if child.first() == ast::impure_fn => parent, + _ => child } } @@ -4270,14 +4332,11 @@ pub fn determine_inherited_purity(parent_purity: ast::purity, // Here, the supertraits are the transitive closure of the supertrait // relation on the supertraits from each bounded trait's constraint // list. -pub fn iter_bound_traits_and_supertraits(tcx: ctxt, +pub fn each_bound_trait_and_supertraits(tcx: ctxt, bounds: param_bounds, - f: &fn(t) -> bool) { - let mut fin = false; - + f: &fn(&TraitRef) -> bool) { for bounds.each |bound| { - - let bound_trait_ty = match *bound { + let bound_trait_ref = match *bound { ty::bound_trait(bound_t) => bound_t, ty::bound_copy | ty::bound_owned | @@ -4286,53 +4345,47 @@ pub fn iter_bound_traits_and_supertraits(tcx: ctxt, } }; - let mut supertrait_map = LinearMap::new(); - let mut seen_def_ids = ~[]; + let mut supertrait_set = HashMap::new(); + let mut trait_refs = ~[]; let mut i = 0; - let trait_ty_id = ty_to_def_id(bound_trait_ty).expect( - ~"iter_trait_ty_supertraits got a non-trait type"); - let mut trait_ty = bound_trait_ty; - debug!("iter_bound_traits_and_supertraits: trait_ty = %s", - ty_to_str(tcx, trait_ty)); + // Seed the worklist with the trait from the bound + supertrait_set.insert(bound_trait_ref.def_id, ()); + trait_refs.push(bound_trait_ref); // Add the given trait ty to the hash map - supertrait_map.insert(trait_ty_id, trait_ty); - seen_def_ids.push(trait_ty_id); - - if f(trait_ty) { - // Add all the supertraits to the hash map, - // executing on each of them - while i < supertrait_map.len() && !fin { - let init_trait_id = seen_def_ids[i]; - i += 1; - // Add supertraits to supertrait_map - let supertraits = trait_supertraits(tcx, init_trait_id); - for supertraits.each |supertrait| { - let super_t = supertrait.tpt.ty; - let d_id = ty_to_def_id(super_t).expect("supertrait \ - should be a trait ty"); - if !supertrait_map.contains_key(&d_id) { - supertrait_map.insert(d_id, super_t); - trait_ty = super_t; - seen_def_ids.push(d_id); - } - debug!("A super_t = %s", ty_to_str(tcx, trait_ty)); - if !f(trait_ty) { - fin = true; - } + while i < trait_refs.len() { + debug!("each_bound_trait_and_supertraits(i=%?, trait_ref=%s)", + i, trait_refs[i].repr(tcx)); + + if !f(trait_refs[i]) { + return; + } + + // Add supertraits to supertrait_set + let supertrait_refs = trait_ref_supertraits(tcx, trait_refs[i]); + for supertrait_refs.each |&supertrait_ref| { + debug!("each_bound_trait_and_supertraits(supertrait_ref=%s)", + supertrait_ref.repr(tcx)); + + let d_id = supertrait_ref.def_id; + if !supertrait_set.contains_key(&d_id) { + // FIXME(#5527) Could have same trait multiple times + supertrait_set.insert(d_id, ()); + trait_refs.push(supertrait_ref); } } - }; - fin = false; + + i += 1; + } } } pub fn count_traits_and_supertraits(tcx: ctxt, - boundses: &[param_bounds]) -> uint { + type_param_defs: &[TypeParameterDef]) -> uint { let mut total = 0; - for boundses.each |bounds| { - for iter_bound_traits_and_supertraits(tcx, *bounds) |_trait_ty| { + for type_param_defs.each |type_param_def| { + for each_bound_trait_and_supertraits(tcx, type_param_def.bounds) |_| { total += 1; } } @@ -4355,6 +4408,14 @@ pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id { } } +pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) { + let ty_visitor_name = special_idents::ty_visitor; + assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name)); + let trait_ref = *tcx.intrinsic_traits.get(&ty_visitor_name); + (trait_ref, + mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore)) +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 4b4cb8572529c..a0c12ff1a204c 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -14,14 +14,14 @@ * is parameterized by an instance of `AstConv` and a `region_scope`. * * The parameterization of `ast_ty_to_ty()` is because it behaves - * somewhat differently during the collect and check phases, particularly - * with respect to looking up the types of top-level items. In the - * collect phase, the crate context is used as the `AstConv` instance; - * in this phase, the `get_item_ty()` function triggers a recursive call - * to `ty_of_item()` (note that `ast_ty_to_ty()` will detect recursive - * types and report an error). In the check phase, when the @FnCtxt is - * used as the `AstConv`, `get_item_ty()` just looks up the item type in - * `tcx.tcache`. + * somewhat differently during the collect and check phases, + * particularly with respect to looking up the types of top-level + * items. In the collect phase, the crate context is used as the + * `AstConv` instance; in this phase, the `get_item_ty()` function + * triggers a recursive call to `ty_of_item()` (note that + * `ast_ty_to_ty()` will detect recursive types and report an error). + * In the check phase, when the @FnCtxt is used as the `AstConv`, + * `get_item_ty()` just looks up the item type in `tcx.tcache`. * * The `region_scope` trait controls how region references are * handled. It has two methods which are used to resolve anonymous @@ -76,6 +76,7 @@ use util::common::indenter; pub trait AstConv { fn tcx(&self) -> ty::ctxt; fn get_item_ty(&self, id: ast::def_id) -> ty::ty_param_bounds_and_ty; + fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef; // what type should we use when a type is omitted? fn ty_infer(&self, span: span) -> ty::t; @@ -129,67 +130,106 @@ pub fn ast_region_to_region( get_region_reporting_err(self.tcx(), span, opt_lifetime, res) } -pub fn ast_path_to_substs_and_ty( - self: &AC, - rscope: &RS, - did: ast::def_id, - path: @ast::path) - -> ty_param_substs_and_ty { - let tcx = self.tcx(); - let ty::ty_param_bounds_and_ty { - bounds: decl_bounds, - region_param: decl_rp, - ty: decl_ty - } = self.get_item_ty(did); +fn ast_path_substs( + self: &AC, + rscope: &RS, + def_id: ast::def_id, + decl_generics: &ty::Generics, + self_ty: Option, + path: @ast::Path) -> ty::substs +{ + /*! + * + * Given a path `path` that refers to an item `I` with the + * declared generics `decl_generics`, returns an appropriate + * set of substitutions for this particular reference to `I`. + */ - debug!("ast_path_to_substs_and_ty: did=%? decl_rp=%?", - did, decl_rp); + let tcx = self.tcx(); // If the type is parameterized by the self region, then replace self // region with the current anon region binding (in other words, // whatever & would get replaced with). - let self_r = match (decl_rp, path.rp) { - (None, None) => { + let self_r = match (&decl_generics.region_param, &path.rp) { + (&None, &None) => { None } - (None, Some(_)) => { + (&None, &Some(_)) => { tcx.sess.span_err( path.span, fmt!("no region bound is allowed on `%s`, \ which is not declared as containing region pointers", - ty::item_path_str(tcx, did))); + ty::item_path_str(tcx, def_id))); None } - (Some(_), None) => { + (&Some(_), &None) => { let res = rscope.anon_region(path.span); let r = get_region_reporting_err(self.tcx(), path.span, None, res); Some(r) } - (Some(_), Some(_)) => { + (&Some(_), &Some(_)) => { Some(ast_region_to_region(self, rscope, path.span, path.rp)) } }; // Convert the type parameters supplied by the user. - if !vec::same_length(*decl_bounds, path.types) { + if !vec::same_length(*decl_generics.type_param_defs, path.types) { self.tcx().sess.span_fatal( path.span, fmt!("wrong number of type arguments: expected %u but found %u", - (*decl_bounds).len(), path.types.len())); + decl_generics.type_param_defs.len(), path.types.len())); } let tps = path.types.map(|a_t| ast_ty_to_ty(self, rscope, *a_t)); - let substs = substs {self_r:self_r, self_ty:None, tps:tps}; - let ty = ty::subst(tcx, &substs, decl_ty); + substs {self_r:self_r, self_ty:self_ty, tps:tps} +} +pub fn ast_path_to_substs_and_ty( + self: &AC, + rscope: &RS, + did: ast::def_id, + path: @ast::Path) -> ty_param_substs_and_ty +{ + let tcx = self.tcx(); + let ty::ty_param_bounds_and_ty { + generics: generics, + ty: decl_ty + } = self.get_item_ty(did); + + let substs = ast_path_substs(self, rscope, did, &generics, None, path); + let ty = ty::subst(tcx, &substs, decl_ty); ty_param_substs_and_ty { substs: substs, ty: ty } } +pub fn ast_path_to_trait_ref( + self: &AC, + rscope: &RS, + trait_def_id: ast::def_id, + self_ty: Option, + path: @ast::Path) -> @ty::TraitRef +{ + let trait_def = + self.get_trait_def(trait_def_id); + let substs = + ast_path_substs( + self, + rscope, + trait_def.trait_ref.def_id, + &trait_def.generics, + self_ty, + path); + let trait_ref = + @ty::TraitRef {def_id: trait_def_id, + substs: substs}; + return trait_ref; +} + + pub fn ast_path_to_ty( self: &AC, rscope: &RS, did: ast::def_id, - path: @ast::path) + path: @ast::Path) -> ty_param_substs_and_ty { // Look up the polytype of the item and then substitute the provided types @@ -243,36 +283,29 @@ pub fn ast_ty_to_ty( check_path_args(tcx, path, NO_TPS | NO_REGIONS); return ty::mk_estr(tcx, vst); } - Some(&ast::def_ty(type_def_id)) => { - let result = ast_path_to_substs_and_ty( - self, rscope, - type_def_id, path); - match ty::get(result.ty).sty { - ty::ty_trait(trait_def_id, ref substs, _) => { - let trait_store = match vst { - ty::vstore_box => ty::BoxTraitStore, - ty::vstore_uniq => ty::UniqTraitStore, - ty::vstore_slice(r) => { - ty::RegionTraitStore(r) - } - ty::vstore_fixed(*) => { - tcx.sess.span_err( - path.span, - ~"@trait, ~trait or &trait \ - are the only supported \ - forms of casting-to-\ - trait"); - ty::BoxTraitStore - } - }; - return ty::mk_trait(tcx, - trait_def_id, - /*bad*/copy *substs, - trait_store); - + Some(&ast::def_trait(trait_def_id)) => { + let result = ast_path_to_trait_ref( + self, rscope, trait_def_id, None, path); + let trait_store = match vst { + ty::vstore_box => ty::BoxTraitStore, + ty::vstore_uniq => ty::UniqTraitStore, + ty::vstore_slice(r) => { + ty::RegionTraitStore(r) + } + ty::vstore_fixed(*) => { + tcx.sess.span_err( + path.span, + ~"@trait, ~trait or &trait \ + are the only supported \ + forms of casting-to-\ + trait"); + ty::BoxTraitStore } - _ => {} - } + }; + return ty::mk_trait(tcx, + result.def_id, + copy result.substs, + trait_store); } _ => {} } @@ -285,7 +318,7 @@ pub fn ast_ty_to_ty( } fn check_path_args(tcx: ty::ctxt, - path: @ast::path, + path: @ast::Path, flags: uint) { if (flags & NO_TPS) != 0u { if path.types.len() > 0u { @@ -372,6 +405,15 @@ pub fn ast_ty_to_ty( Some(&d) => d }; match a_def { + ast::def_trait(_) => { + let path_str = path_to_str(path, tcx.sess.intr()); + tcx.sess.span_err( + ast_ty.span, + fmt!("reference to trait `%s` where a type is expected; \ + try `@%s`, `~%s`, or `&%s`", + path_str, path_str, path_str, path_str)); + ty::mk_err(tcx) + } ast::def_ty(did) | ast::def_struct(did) => { ast_path_to_ty(self, rscope, did, path).ty } @@ -540,6 +582,29 @@ pub fn bound_lifetimes( bound_lifetime_names } +struct SelfInfo { + untransformed_self_ty: ty::t, + self_transform: ast::self_ty +} + +pub fn ty_of_method( + self: &AC, + rscope: &RS, + purity: ast::purity, + lifetimes: &OptVec, + untransformed_self_ty: ty::t, + self_transform: ast::self_ty, + decl: &ast::fn_decl) -> (Option, ty::BareFnTy) +{ + let self_info = SelfInfo { + untransformed_self_ty: untransformed_self_ty, + self_transform: self_transform + }; + let (a, b) = ty_of_method_or_bare_fn( + self, rscope, purity, AbiSet::Rust(), lifetimes, Some(&self_info), decl); + (a.get(), b) +} + pub fn ty_of_bare_fn( self: &AC, rscope: &RS, @@ -547,6 +612,20 @@ pub fn ty_of_bare_fn( abi: AbiSet, lifetimes: &OptVec, decl: &ast::fn_decl) -> ty::BareFnTy +{ + let (_, b) = ty_of_method_or_bare_fn( + self, rscope, purity, abi, lifetimes, None, decl); + b +} + +fn ty_of_method_or_bare_fn( + self: &AC, + rscope: &RS, + purity: ast::purity, + abi: AbiSet, + lifetimes: &OptVec, + opt_self_info: Option<&SelfInfo>, + decl: &ast::fn_decl) -> (Option>, ty::BareFnTy) { debug!("ty_of_bare_fn"); @@ -555,18 +634,56 @@ pub fn ty_of_bare_fn( let bound_lifetime_names = bound_lifetimes(self, lifetimes); let rb = in_binding_rscope(rscope, RegionParamNames(copy bound_lifetime_names)); + let opt_transformed_self_ty = opt_self_info.map(|&self_info| { + transform_self_ty(self, &rb, self_info) + }); + let input_tys = decl.inputs.map(|a| ty_of_arg(self, &rb, *a, None)); + let output_ty = match decl.output.node { ast::ty_infer => self.ty_infer(decl.output.span), _ => ast_ty_to_ty(self, &rb, decl.output) }; - ty::BareFnTy { - purity: purity, - abis: abi, - sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names, - inputs: input_tys, - output: output_ty} + return (opt_transformed_self_ty, + ty::BareFnTy { + purity: purity, + abis: abi, + sig: ty::FnSig {bound_lifetime_names: bound_lifetime_names, + inputs: input_tys, + output: output_ty} + }); + + fn transform_self_ty( + self: &AC, + rscope: &RS, + self_info: &SelfInfo) -> Option + { + match self_info.self_transform.node { + ast::sty_static => None, + ast::sty_value => { + Some(self_info.untransformed_self_ty) + } + ast::sty_region(lifetime, mutability) => { + let region = + ast_region_to_region(self, rscope, + self_info.self_transform.span, + lifetime); + Some(ty::mk_rptr(self.tcx(), region, + ty::mt {ty: self_info.untransformed_self_ty, + mutbl: mutability})) + } + ast::sty_box(mutability) => { + Some(ty::mk_box(self.tcx(), + ty::mt {ty: self_info.untransformed_self_ty, + mutbl: mutability})) + } + ast::sty_uniq(mutability) => { + Some(ty::mk_uniq(self.tcx(), + ty::mt {ty: self_info.untransformed_self_ty, + mutbl: mutability})) + } + } } } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index cc2cf7a23c598..e2dd0d1ed9ed2 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -18,7 +18,7 @@ use middle::typeck::check::{instantiate_path, lookup_def}; use middle::typeck::check::{structure_of, valid_range_bounds}; use middle::typeck::require_same_types; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::vec; use syntax::ast; use syntax::ast_util; @@ -99,7 +99,7 @@ pub struct pat_ctxt { block_region: ty::Region, // Region for the block of the arm } -pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, +pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::Path, subpats: &Option<~[@ast::pat]>, expected: ty::t) { // Typecheck the path. @@ -135,7 +135,9 @@ pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, ty::enum_variant_with_id(tcx, enm, var); let var_tpt = ty::lookup_item_type(tcx, var); vinfo.args.map(|t| { - if var_tpt.bounds.len() == expected_substs.tps.len() { + if var_tpt.generics.type_param_defs.len() == + expected_substs.tps.len() + { ty::subst(tcx, expected_substs, *t) } else { @@ -228,11 +230,11 @@ pub fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path, /// `class_fields` describes the type of each field of the struct. /// `class_id` is the ID of the struct. /// `substitutions` are the type substitutions applied to this struct type -/// (e.g. K,V in LinearMap). +/// (e.g. K,V in HashMap). /// `etc` is true if the pattern said '...' and false otherwise. pub fn check_struct_pat_fields(pcx: pat_ctxt, span: span, - path: @ast::path, + path: @ast::Path, fields: &[ast::field_pat], class_fields: ~[ty::field_ty], class_id: ast::def_id, @@ -241,13 +243,13 @@ pub fn check_struct_pat_fields(pcx: pat_ctxt, let tcx = pcx.fcx.ccx.tcx; // Index the class fields. - let mut field_map = LinearMap::new(); + let mut field_map = HashMap::new(); for class_fields.eachi |i, class_field| { field_map.insert(class_field.ident, i); } // Typecheck each field. - let mut found_fields = LinearSet::new(); + let mut found_fields = HashSet::new(); for fields.each |field| { match field_map.find(&field.ident) { Some(&index) => { @@ -283,7 +285,7 @@ pub fn check_struct_pat_fields(pcx: pat_ctxt, } pub fn check_struct_pat(pcx: pat_ctxt, pat_id: ast::node_id, span: span, - expected: ty::t, path: @ast::path, + expected: ty::t, path: @ast::Path, fields: &[ast::field_pat], etc: bool, class_id: ast::def_id, substitutions: &ty::substs) { let fcx = pcx.fcx; @@ -324,7 +326,7 @@ pub fn check_struct_like_enum_variant_pat(pcx: pat_ctxt, pat_id: ast::node_id, span: span, expected: ty::t, - path: @ast::path, + path: @ast::Path, fields: &[ast::field_pat], etc: bool, enum_id: ast::def_id, diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 320f0206fb871..6b09133e73a11 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -92,13 +92,14 @@ use middle::typeck::check; use middle::typeck::infer; use middle::typeck::{method_map_entry, method_origin, method_param}; use middle::typeck::{method_self, method_static, method_trait, method_super}; +use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; use util::common::indenter; -use util::ppaux::expr_repr; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use core::result; use core::uint; use core::vec; +use std::list::Nil; use syntax::ast::{def_id, sty_value, sty_region, sty_box}; use syntax::ast::{sty_uniq, sty_static, node_id, by_copy, by_ref}; use syntax::ast::{m_const, m_mutbl, m_imm}; @@ -121,7 +122,7 @@ pub fn lookup( fcx: @mut FnCtxt, // In a call `a.b::(...)`: - expr: @ast::expr, // The expression `a.b`. + expr: @ast::expr, // The expression `a.b(...)`. self_expr: @ast::expr, // The expression `a`. callee_id: node_id, // Where to store `a.b`'s type m_name: ast::ident, // The ident `b`. @@ -131,7 +132,7 @@ pub fn lookup( check_traits: CheckTraitsFlag, // Whether we check traits only. autoderef_receiver: AutoderefReceiverFlag) -> Option { - let mut impl_dups = LinearSet::new(); + let mut impl_dups = HashSet::new(); let lcx = LookupContext { fcx: fcx, expr: expr, @@ -147,8 +148,7 @@ pub fn lookup( autoderef_receiver: autoderef_receiver, }; let mme = lcx.do_lookup(self_ty); - debug!("method lookup for %s yielded %?", - expr_repr(fcx.tcx(), expr), mme); + debug!("method lookup for %s yielded %?", expr.repr(fcx.tcx()), mme); return mme; } @@ -159,7 +159,7 @@ pub struct LookupContext<'self> { callee_id: node_id, m_name: ast::ident, supplied_tps: &'self [ty::t], - impl_dups: &'self mut LinearSet, + impl_dups: &'self mut HashSet, inherent_candidates: @mut ~[Candidate], extension_candidates: @mut ~[Candidate], deref_args: check::DerefArgs, @@ -174,25 +174,10 @@ pub struct LookupContext<'self> { pub struct Candidate { rcvr_ty: ty::t, rcvr_substs: ty::substs, - explicit_self: ast::self_ty_, - - // FIXME #3446---these two fields should be easily derived from - // origin, yet are not - num_method_tps: uint, - self_mode: ast::rmode, - + method_ty: @ty::method, origin: method_origin, } -/** - * How the self type should be transformed according to the form of explicit - * self provided by the method. - */ -pub enum TransformTypeFlag { - TransformTypeNormally, - TransformTypeForObject, -} - pub impl<'self> LookupContext<'self> { fn do_lookup(&self, self_ty: ty::t) -> Option { let mut self_ty = structurally_resolved_type(self.fcx, @@ -201,9 +186,8 @@ pub impl<'self> LookupContext<'self> { debug!("do_lookup(self_ty=%s, expr=%s, self_expr=%s)", self.ty_to_str(self_ty), - expr_repr(self.tcx(), self.expr), - expr_repr(self.tcx(), self.self_expr)); - let _indenter = indenter(); + self.expr.repr(self.tcx()), + self.self_expr.repr(self.tcx())); // Prepare the list of candidates self.push_inherent_candidates(self_ty); @@ -292,13 +276,13 @@ pub impl<'self> LookupContext<'self> { fn push_inherent_candidates(&self, self_ty: ty::t) { /*! - * * Collect all inherent candidates into * `self.inherent_candidates`. See comment at the start of * the file. To find the inherent candidates, we repeatedly * deref the self-ty to find the "base-type". So, for * example, if the receiver is @@C where `C` is a struct type, - * we'll want to find the inherent impls for `C`. */ + * we'll want to find the inherent impls for `C`. + */ let mut enum_dids = ~[]; let mut self_ty = self_ty; @@ -383,122 +367,52 @@ pub impl<'self> LookupContext<'self> { let tcx = self.tcx(); let mut next_bound_idx = 0; // count only trait bounds - let bounds = tcx.ty_param_bounds.get(¶m_ty.def_id.node); - - for bounds.each |bound| { - let bound_trait_ty = match *bound { - ty::bound_trait(bound_t) => bound_t, - - ty::bound_copy | ty::bound_owned | - ty::bound_const | ty::bound_durable => { - loop; // skip non-trait bounds - } - }; - + let type_param_def = match tcx.ty_param_defs.find(¶m_ty.def_id.node) { + Some(t) => t, + None => { + tcx.sess.span_bug( + self.expr.span, + fmt!("No param def for %?", param_ty)); + } + }; - let bound_substs = match ty::get(bound_trait_ty).sty { - ty::ty_trait(_, ref substs, _) => (/*bad*/copy *substs), - _ => { - self.bug(fmt!("add_candidates_from_param: \ - non-trait bound %s", - self.ty_to_str(bound_trait_ty))); + for ty::each_bound_trait_and_supertraits(tcx, type_param_def.bounds) + |bound_trait_ref| + { + let this_bound_idx = next_bound_idx; + next_bound_idx += 1; + + let trait_methods = ty::trait_methods(tcx, bound_trait_ref.def_id); + let pos = { + match trait_methods.position(|m| { + m.self_ty != ast::sty_static && + m.ident == self.m_name }) + { + Some(pos) => pos, + None => { + debug!("trait doesn't contain method: %?", + bound_trait_ref.def_id); + loop; // check next trait or bound + } } }; - - - // Loop over the trait and all of its supertraits. - let mut worklist = ~[]; - - let init_trait_ty = bound_trait_ty; - let init_substs = bound_substs; - - // Replace any appearance of `self` with the type of the - // generic parameter itself. Note that this is the only - // case where this replacement is necessary: in all other - // cases, we are either invoking a method directly from an - // impl or class (where the self type is not permitted), - // or from a trait type (in which case methods that refer - // to self are not permitted). - let init_substs = substs { - self_ty: Some(rcvr_ty), - ..init_substs + let method = trait_methods[pos]; + + let cand = Candidate { + rcvr_ty: rcvr_ty, + rcvr_substs: copy bound_trait_ref.substs, + method_ty: method, + origin: method_param( + method_param { + trait_id: bound_trait_ref.def_id, + method_num: pos, + param_num: param_ty.idx, + bound_num: this_bound_idx, + }) }; - worklist.push((init_trait_ty, init_substs)); - - let mut i = 0; - while i < worklist.len() { - let (init_trait_ty, init_substs) = /*bad*/copy worklist[i]; - i += 1; - - let init_trait_id = ty::ty_to_def_id(init_trait_ty).get(); - - // Add all the supertraits of this trait to the worklist. - let supertraits = ty::trait_supertraits(tcx, - init_trait_id); - for supertraits.each |supertrait| { - debug!("adding supertrait: %?", - supertrait.def_id); - - let new_substs = ty::subst_substs( - tcx, - &supertrait.tpt.substs, - &init_substs); - - // Again replacing the self type - let new_substs = substs { - self_ty: Some(rcvr_ty), - ..new_substs - }; - - worklist.push((supertrait.tpt.ty, new_substs)); - } - - - let this_bound_idx = next_bound_idx; - next_bound_idx += 1; - - let trait_methods = ty::trait_methods(tcx, init_trait_id); - let pos = { - match trait_methods.position(|m| { - m.self_ty != ast::sty_static && - m.ident == self.m_name }) - { - Some(pos) => pos, - None => { - debug!("trait doesn't contain method: %?", - init_trait_id); - loop; // check next trait or bound - } - } - }; - let method = &trait_methods[pos]; - - let (rcvr_ty, rcvr_substs) = - self.create_rcvr_ty_and_substs_for_method( - method.self_ty, - rcvr_ty, - init_substs, - TransformTypeNormally); - - let cand = Candidate { - rcvr_ty: rcvr_ty, - rcvr_substs: rcvr_substs, - explicit_self: method.self_ty, - num_method_tps: method.tps.len(), - self_mode: get_mode_from_self_type(method.self_ty), - origin: method_param( - method_param { - trait_id: init_trait_id, - method_num: pos, - param_num: param_ty.idx, - bound_num: this_bound_idx, - }) - }; - - debug!("pushing inherent candidate for param: %?", cand); - self.inherent_candidates.push(cand); - } + debug!("pushing inherent candidate for param: %?", cand); + self.inherent_candidates.push(cand); } } @@ -518,9 +432,9 @@ pub impl<'self> LookupContext<'self> { Some(i) => i, None => { return; } // no method with the right name }; - let method = &ms[index]; + let method = ms[index]; - /* FIXME(#3157) we should transform the vstore in accordance + /* FIXME(#5762) we should transform the vstore in accordance with the self type match method.self_type { @@ -538,23 +452,18 @@ pub impl<'self> LookupContext<'self> { // `trait_ty` for `self` here, because it allows the compiler // to soldier on. An error will be reported should this // candidate be selected if the method refers to `self`. + // + // NB: `confirm_candidate()` also relies upon this substitution + // for Self. let rcvr_substs = substs { self_ty: Some(self_ty), ../*bad*/copy *substs }; - let (rcvr_ty, rcvr_substs) = - self.create_rcvr_ty_and_substs_for_method(method.self_ty, - self_ty, - rcvr_substs, - TransformTypeForObject); - self.inherent_candidates.push(Candidate { - rcvr_ty: rcvr_ty, + rcvr_ty: self_ty, rcvr_substs: rcvr_substs, - explicit_self: method.self_ty, - num_method_tps: method.tps.len(), - self_mode: get_mode_from_self_type(method.self_ty), + method_ty: method, origin: method_trait(did, index, store) }); } @@ -563,63 +472,59 @@ pub impl<'self> LookupContext<'self> { self_ty: ty::t, did: def_id, substs: &ty::substs) { + struct MethodInfo { + method_ty: @ty::method, + trait_def_id: ast::def_id, + index: uint + } + let tcx = self.tcx(); // First, try self methods - let mut method = None; + let mut method_info: Option = None; let methods = ty::trait_methods(tcx, did); - let mut index = None; - let mut trait_did = None; match vec::position(*methods, |m| m.ident == self.m_name) { Some(i) => { - index = Some(i); - trait_did = Some(did); - method = Some((methods[i].self_ty, methods[i].tps.len())); + method_info = Some(MethodInfo { + method_ty: methods[i], + index: i, + trait_def_id: did + }); } None => () } // No method found yet? Check each supertrait - if method.is_none() { + if method_info.is_none() { for ty::trait_supertraits(tcx, did).each() |trait_ref| { let supertrait_methods = ty::trait_methods(tcx, trait_ref.def_id); match vec::position(*supertrait_methods, |m| m.ident == self.m_name) { Some(i) => { - index = Some(i); - trait_did = Some(trait_ref.def_id); - method = Some((supertrait_methods[i].self_ty, - supertrait_methods[i].tps.len())); + method_info = Some(MethodInfo { + method_ty: supertrait_methods[i], + index: i, + trait_def_id: trait_ref.def_id + }); break; } None => () } } } - match (method, index, trait_did) { - (Some((method_self_ty, method_num_tps)), - Some(index), Some(trait_did)) => { - + match method_info { + Some(ref info) => { // We've found a method -- return it - let rcvr_substs = substs { self_ty: Some(self_ty), + let rcvr_substs = substs {self_ty: Some(self_ty), ..copy *substs }; - let (rcvr_ty, rcvr_substs) = - self.create_rcvr_ty_and_substs_for_method( - method_self_ty, - self_ty, - rcvr_substs, - TransformTypeNormally); - let origin = if trait_did == did { - method_self(trait_did, index) - } - else { - method_super(trait_did, index) + let origin = if did == info.trait_def_id { + method_self(info.trait_def_id, info.index) + } else { + method_super(info.trait_def_id, info.index) }; self.inherent_candidates.push(Candidate { - rcvr_ty: rcvr_ty, + rcvr_ty: self_ty, rcvr_substs: rcvr_substs, - explicit_self: method_self_ty, - num_method_tps: method_num_tps, - self_mode: get_mode_from_self_type(method_self_ty), + method_ty: info.method_ty, origin: origin }); } @@ -651,7 +556,7 @@ pub impl<'self> LookupContext<'self> { } }; - let method = &impl_info.methods[idx]; + let method = ty::method(self.tcx(), impl_info.methods[idx].did); // determine the `self` of the impl with fresh // variables for each parameter: @@ -665,20 +570,11 @@ pub impl<'self> LookupContext<'self> { ty: impl_ty } = impl_self_ty(&vcx, location_info, impl_info.did); - let (impl_ty, impl_substs) = - self.create_rcvr_ty_and_substs_for_method( - method.self_type, - impl_ty, - impl_substs, - TransformTypeNormally); - candidates.push(Candidate { rcvr_ty: impl_ty, rcvr_substs: impl_substs, - explicit_self: method.self_type, - num_method_tps: method.n_tps, - self_mode: get_mode_from_self_type(method.self_type), - origin: method_static(method.did) + method_ty: method, + origin: method_static(method.def_id) }); } @@ -699,78 +595,25 @@ pub impl<'self> LookupContext<'self> { debug!("(pushing candidates from provided methods) adding \ candidate"); + let method = ty::method(self.tcx(), + provided_method_info.method_info.did); + // XXX: Needs to support generics. let dummy_substs = substs { self_r: None, self_ty: None, tps: ~[] }; - let (impl_ty, impl_substs) = - self.create_rcvr_ty_and_substs_for_method( - provided_method_info.method_info.self_type, - self_ty, - dummy_substs, - TransformTypeNormally); candidates.push(Candidate { - rcvr_ty: impl_ty, - rcvr_substs: impl_substs, - explicit_self: provided_method_info.method_info.self_type, - num_method_tps: provided_method_info.method_info.n_tps, - self_mode: get_mode_from_self_type( - provided_method_info.method_info.self_type), + rcvr_ty: self_ty, + rcvr_substs: dummy_substs, + method_ty: method, origin: method_static(provided_method_info.method_info.did) }); } } - fn create_rcvr_ty_and_substs_for_method(&self, - self_decl: ast::self_ty_, - self_ty: ty::t, - +self_substs: ty::substs, - transform_type: TransformTypeFlag) - -> (ty::t, ty::substs) { - // If the self type includes a region (like &self), we need to - // ensure that the receiver substitutions have a self region. - // If the receiver type does not itself contain borrowed - // pointers, there may not be one yet. - // - // FIXME(#3446)--this awkward situation comes about because - // the regions in the receiver are substituted before (and - // differently from) those in the argument types. This - // shouldn't really have to be. - let rcvr_substs = { - match self_decl { - sty_static | sty_value | - sty_box(_) | sty_uniq(_) => { - self_substs - } - sty_region(*) if self_substs.self_r.is_some() => { - // FIXME(#4846) ignoring expl lifetime here - self_substs - } - sty_region(*) => { - // FIXME(#4846) ignoring expl lifetime here - substs { - self_r: - Some(self.infcx().next_region_var( - self.expr.span, - self.expr.id)), - ..self_substs - } - } - } - }; - - let rcvr_ty = transform_self_type_for_method(self.tcx(), - rcvr_substs.self_r, - self_ty, - self_decl, - transform_type); - - (rcvr_ty, rcvr_substs) - } - // ______________________________________________________________________ // Candidate selection (see comment at start of file) @@ -1092,46 +935,67 @@ pub impl<'self> LookupContext<'self> { fn confirm_candidate(&self, self_ty: ty::t, candidate: &Candidate) - -> method_map_entry { + -> method_map_entry + { let tcx = self.tcx(); let fty = self.fn_ty_from_origin(&candidate.origin); + debug!("confirm_candidate(expr=%s, candidate=%s, fty=%s)", + self.expr.repr(tcx), + self.cand_to_str(candidate), + self.ty_to_str(fty)); + self.enforce_trait_instance_limitations(fty, candidate); self.enforce_drop_trait_limitations(candidate); - // before we only checked whether self_ty could be a subtype - // of rcvr_ty; now we actually make it so (this may cause - // variables to unify etc). Since we checked beforehand, and - // nothing has changed in the meantime, this unification - // should never fail. - match self.fcx.mk_subty(false, self.self_expr.span, - self_ty, candidate.rcvr_ty) { - result::Ok(_) => (), - result::Err(_) => { - self.bug(fmt!("%s was assignable to %s but now is not?", - self.ty_to_str(self_ty), - self.ty_to_str(candidate.rcvr_ty))); + // static methods should never have gotten this far: + assert!(candidate.method_ty.self_ty != sty_static); + + let transformed_self_ty = match candidate.origin { + method_trait(*) => { + match candidate.method_ty.self_ty { + sty_region(*) => { + // FIXME(#5762) again, preserving existing + // behavior here which (for &self) desires + // &@Trait where @Trait is the type of the + // receiver. Here we fetch the method's + // transformed_self_ty which will be something + // like &'a Self. We then perform a + // substitution which will replace Self with + // @Trait. + let t = candidate.method_ty.transformed_self_ty.get(); + ty::subst(tcx, &candidate.rcvr_substs, t) + } + _ => { + candidate.rcvr_ty + } + } } - } + _ => { + let t = candidate.method_ty.transformed_self_ty.get(); + ty::subst(tcx, &candidate.rcvr_substs, t) + } + }; // Determine the values for the type parameters of the method. // If they were not explicitly supplied, just construct fresh // type variables. let num_supplied_tps = self.supplied_tps.len(); + let num_method_tps = candidate.method_ty.generics.type_param_defs.len(); let m_substs = { if num_supplied_tps == 0u { - self.fcx.infcx().next_ty_vars(candidate.num_method_tps) - } else if candidate.num_method_tps == 0u { + self.fcx.infcx().next_ty_vars(num_method_tps) + } else if num_method_tps == 0u { tcx.sess.span_err( self.expr.span, ~"this method does not take type parameters"); - self.fcx.infcx().next_ty_vars(candidate.num_method_tps) - } else if num_supplied_tps != candidate.num_method_tps { + self.fcx.infcx().next_ty_vars(num_method_tps) + } else if num_supplied_tps != num_method_tps { tcx.sess.span_err( self.expr.span, ~"incorrect number of type \ parameters given for this method"); - self.fcx.infcx().next_ty_vars(candidate.num_method_tps) + self.fcx.infcx().next_ty_vars(num_method_tps) } else { self.supplied_tps.to_vec() } @@ -1145,13 +1009,57 @@ pub impl<'self> LookupContext<'self> { ../*bad*/copy candidate.rcvr_substs }; - self.fcx.write_ty_substs(self.callee_id, fty, all_substs); + // Compute the method type with type parameters substituted + debug!("fty=%s all_substs=%s", + self.ty_to_str(fty), + ty::substs_to_str(tcx, &all_substs)); + let fty = ty::subst(tcx, &all_substs, fty); + debug!("after subst, fty=%s", self.ty_to_str(fty)); + + // Replace any bound regions that appear in the function + // signature with region variables + let bare_fn_ty = match ty::get(fty).sty { + ty::ty_bare_fn(ref f) => copy *f, + ref s => { + tcx.sess.span_bug( + self.expr.span, + fmt!("Invoking method with non-bare-fn ty: %?", s)); + } + }; + let (_, opt_transformed_self_ty, fn_sig) = + replace_bound_regions_in_fn_sig( + tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig, + |_br| self.fcx.infcx().next_region_var( + self.expr.span, self.expr.id)); + let transformed_self_ty = opt_transformed_self_ty.get(); + let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty}); + debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty)); + + let self_mode = get_mode_from_self_type(candidate.method_ty.self_ty); + + // before we only checked whether self_ty could be a subtype + // of rcvr_ty; now we actually make it so (this may cause + // variables to unify etc). Since we checked beforehand, and + // nothing has changed in the meantime, this unification + // should never fail. + match self.fcx.mk_subty(false, self.self_expr.span, + self_ty, transformed_self_ty) { + result::Ok(_) => (), + result::Err(_) => { + self.bug(fmt!("%s was a subtype of %s but now is not?", + self.ty_to_str(self_ty), + self.ty_to_str(transformed_self_ty))); + } + } + + self.fcx.write_ty(self.callee_id, fty); + self.fcx.write_substs(self.callee_id, all_substs); method_map_entry { self_arg: arg { - mode: ast::expl(candidate.self_mode), + mode: ast::expl(self_mode), ty: candidate.rcvr_ty, }, - explicit_self: candidate.explicit_self, + explicit_self: candidate.method_ty.self_ty, origin: candidate.origin, } } @@ -1183,7 +1091,7 @@ pub impl<'self> LookupContext<'self> { self-type through a boxed trait"); } - if candidate.num_method_tps > 0 { + if candidate.method_ty.generics.has_type_params() { self.tcx().sess.span_err( self.expr.span, ~"cannot call a generic method through a boxed trait"); @@ -1214,7 +1122,87 @@ pub impl<'self> LookupContext<'self> { debug!("is_relevant(self_ty=%s, candidate=%s)", self.ty_to_str(self_ty), self.cand_to_str(candidate)); - self.fcx.can_mk_subty(self_ty, candidate.rcvr_ty).is_ok() + // Check for calls to object methods. We resolve these differently. + // + // FIXME(#5762)---we don't check that an @self method is only called + // on an @Trait object here and so forth + match candidate.origin { + method_trait(*) => { + match candidate.method_ty.self_ty { + sty_static | sty_value => { + return false; + } + sty_region(*) => { + // just echoing current behavior here, which treats + // an &self method on an @Trait object as requiring + // an &@Trait receiver (wacky) + } + sty_box(*) | sty_uniq(*) => { + return self.fcx.can_mk_subty(self_ty, + candidate.rcvr_ty).is_ok(); + } + }; + } + _ => {} + } + + return match candidate.method_ty.self_ty { + sty_static => { + false + } + + sty_value => { + self.fcx.can_mk_subty(self_ty, candidate.rcvr_ty).is_ok() + } + + sty_region(_, m) => { + match ty::get(self_ty).sty { + ty::ty_rptr(_, mt) => { + mutability_matches(mt.mutbl, m) && + self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok() + } + + _ => false + } + } + + sty_box(m) => { + match ty::get(self_ty).sty { + ty::ty_box(mt) => { + mutability_matches(mt.mutbl, m) && + self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok() + } + + _ => false + } + } + + sty_uniq(m) => { + match ty::get(self_ty).sty { + ty::ty_uniq(mt) => { + mutability_matches(mt.mutbl, m) && + self.fcx.can_mk_subty(mt.ty, candidate.rcvr_ty).is_ok() + } + + _ => false + } + } + }; + + fn mutability_matches(self_mutbl: ast::mutability, + candidate_mutbl: ast::mutability) -> bool { + //! True if `self_mutbl <: candidate_mutbl` + + match (self_mutbl, candidate_mutbl) { + (_, m_const) => true, + (m_mutbl, m_mutbl) => true, + (m_imm, m_imm) => true, + (m_mutbl, m_imm) => false, + (m_imm, m_mutbl) => false, + (m_const, m_imm) => false, + (m_const, m_mutbl) => false, + } + } } fn fn_ty_from_origin(&self, origin: &method_origin) -> ty::t { @@ -1300,10 +1288,9 @@ pub impl<'self> LookupContext<'self> { } fn cand_to_str(&self, cand: &Candidate) -> ~str { - fmt!("Candidate(rcvr_ty=%s, rcvr_substs=%s, self_mode=%?, origin=%?)", + fmt!("Candidate(rcvr_ty=%s, rcvr_substs=%s, origin=%?)", self.ty_to_str(cand.rcvr_ty), ty::substs_to_str(self.tcx(), &cand.rcvr_substs), - cand.self_mode, cand.origin) } @@ -1316,45 +1303,6 @@ pub impl<'self> LookupContext<'self> { } } -pub fn transform_self_type_for_method(tcx: ty::ctxt, - self_region: Option, - impl_ty: ty::t, - self_type: ast::self_ty_, - flag: TransformTypeFlag) - -> ty::t { - match self_type { - sty_static => { - tcx.sess.bug(~"calling transform_self_type_for_method on \ - static method"); - } - sty_value => { - impl_ty - } - sty_region(_, mutability) => { - // FIXME(#4846) ignoring expl lifetime here - mk_rptr(tcx, - self_region.expect(~"self region missing for &self param"), - ty::mt { ty: impl_ty, mutbl: mutability }) - } - sty_box(mutability) => { - match flag { - TransformTypeNormally => { - mk_box(tcx, ty::mt { ty: impl_ty, mutbl: mutability }) - } - TransformTypeForObject => impl_ty - } - } - sty_uniq(mutability) => { - match flag { - TransformTypeNormally => { - mk_uniq(tcx, ty::mt { ty: impl_ty, mutbl: mutability }) - } - TransformTypeForObject => impl_ty - } - } - } -} - pub fn get_mode_from_self_type(self_type: ast::self_ty_) -> ast::rmode { match self_type { sty_value => by_copy, _ => by_ref } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 056ccf185995b..5ec4c233bc0d2 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -93,24 +93,23 @@ use middle::typeck::check::method::{AutoderefReceiver}; use middle::typeck::check::method::{AutoderefReceiverFlag}; use middle::typeck::check::method::{CheckTraitsAndInherentMethods}; use middle::typeck::check::method::{CheckTraitsOnly, DontAutoderefReceiver}; -use middle::typeck::check::method::{TransformTypeNormally}; use middle::typeck::check::regionmanip::replace_bound_regions_in_fn_sig; +use middle::typeck::check::regionmanip::relate_free_regions; use middle::typeck::check::vtable::{LocationInfo, VtableContext}; use middle::typeck::CrateCtxt; use middle::typeck::infer::{resolve_type, force_tvar}; use middle::typeck::infer; use middle::typeck::rscope::bound_self_region; -use middle::typeck::rscope::{RegionError, RegionParameterization}; +use middle::typeck::rscope::{RegionError}; use middle::typeck::rscope::region_scope; -use middle::typeck::rscope; use middle::typeck::{isr_alist, lookup_def_ccx}; use middle::typeck::no_params; use middle::typeck::{require_same_types, method_map, vtable_map}; use util::common::{block_query, indenter, loop_query}; -use util::ppaux::{bound_region_to_str, expr_repr, pat_repr}; +use util::ppaux::{bound_region_to_str}; use util::ppaux; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::ptr; use core::result::{Result, Ok, Err}; use core::result; @@ -158,12 +157,12 @@ pub struct SelfInfo { /// share the inherited fields. pub struct inherited { infcx: @mut infer::InferCtxt, - locals: @mut LinearMap, + locals: @mut HashMap, // Temporary tables: - node_types: @mut LinearMap, - node_type_substs: @mut LinearMap, - adjustments: @mut LinearMap, + node_types: @mut HashMap, + node_type_substs: @mut HashMap, + adjustments: @mut HashMap, method_map: method_map, vtable_map: vtable_map, } @@ -180,6 +179,11 @@ pub enum FnKind { Vanilla } +struct PurityState { + purity: ast::purity, + from: ast::node_id, +} + pub struct FnCtxt { // var_bindings, locals and next_var_id are shared // with any nested functions that capture the environment @@ -188,7 +192,7 @@ pub struct FnCtxt { ret_ty: ty::t, // Used by loop bodies that return from the outer function indirect_ret_ty: Option, - purity: ast::purity, + ps: PurityState, // Sometimes we generate region pointers where the precise region // to use is not known. For example, an expression like `&x.f` @@ -220,12 +224,12 @@ pub struct FnCtxt { pub fn blank_inherited(ccx: @mut CrateCtxt) -> @inherited { @inherited { infcx: infer::new_infer_ctxt(ccx.tcx), - locals: @mut LinearMap::new(), - node_types: @mut LinearMap::new(), - node_type_substs: @mut LinearMap::new(), - adjustments: @mut LinearMap::new(), - method_map: @mut LinearMap::new(), - vtable_map: @mut LinearMap::new(), + locals: @mut HashMap::new(), + node_types: @mut HashMap::new(), + node_type_substs: @mut HashMap::new(), + adjustments: @mut HashMap::new(), + method_map: @mut HashMap::new(), + vtable_map: @mut HashMap::new(), } } @@ -239,7 +243,7 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, @mut FnCtxt { ret_ty: rty, indirect_ret_ty: None, - purity: ast::pure_fn, + ps: PurityState { purity: ast::pure_fn, from: 0 }, region_lb: region_bnd, in_scope_regions: @Nil, fn_kind: Vanilla, @@ -266,7 +270,7 @@ pub fn check_bare_fn(ccx: @mut CrateCtxt, ty::ty_bare_fn(ref fn_ty) => { let fcx = check_fn(ccx, self_info, fn_ty.purity, - &fn_ty.sig, decl, body, Vanilla, + &fn_ty.sig, decl, id, body, Vanilla, @Nil, blank_inherited(ccx));; vtable::resolve_in_block(fcx, body); @@ -279,10 +283,11 @@ pub fn check_bare_fn(ccx: @mut CrateCtxt, } pub fn check_fn(ccx: @mut CrateCtxt, - +self_info: Option, + opt_self_info: Option, purity: ast::purity, fn_sig: &ty::FnSig, decl: &ast::fn_decl, + id: ast::node_id, body: &ast::blk, fn_kind: FnKind, inherited_isr: isr_alist, @@ -306,19 +311,28 @@ pub fn check_fn(ccx: @mut CrateCtxt, // First, we have to replace any bound regions in the fn and self // types with free ones. The free region references will be bound // the node_id of the body block. - - let (isr, self_info, fn_sig) = { - replace_bound_regions_in_fn_sig(tcx, inherited_isr, self_info, fn_sig, - |br| ty::re_free(body.node.id, br)) + let (isr, opt_self_info, fn_sig) = { + let opt_self_ty = opt_self_info.map(|i| i.self_ty); + let (isr, opt_self_ty, fn_sig) = + replace_bound_regions_in_fn_sig( + tcx, inherited_isr, opt_self_ty, fn_sig, + |br| ty::re_free(ty::FreeRegion {scope_id: body.node.id, + bound_region: br})); + let opt_self_info = + opt_self_info.map( + |si| SelfInfo {self_ty: opt_self_ty.get(), ..*si}); + (isr, opt_self_info, fn_sig) }; + relate_free_regions(tcx, opt_self_info.map(|s| s.self_ty), &fn_sig); + let arg_tys = fn_sig.inputs.map(|a| a.ty); let ret_ty = fn_sig.output; - debug!("check_fn(arg_tys=%?, ret_ty=%?, self_info.self_ty=%?)", - arg_tys.map(|a| ppaux::ty_to_str(tcx, *a)), + debug!("check_fn(arg_tys=%?, ret_ty=%?, opt_self_ty=%?)", + arg_tys.map(|&a| ppaux::ty_to_str(tcx, a)), ppaux::ty_to_str(tcx, ret_ty), - self_info.map(|s| ppaux::ty_to_str(tcx, s.self_ty))); + opt_self_info.map(|si| ppaux::ty_to_str(tcx, si.self_ty))); // ______________________________________________________________________ // Create the function context. This is either derived from scratch or, @@ -334,7 +348,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, @mut FnCtxt { ret_ty: ret_ty, indirect_ret_ty: indirect_ret_ty, - purity: purity, + ps: PurityState { purity: purity, from: id }, region_lb: body.node.id, in_scope_regions: isr, fn_kind: fn_kind, @@ -343,7 +357,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, } }; - gather_locals(fcx, decl, body, arg_tys, self_info); + gather_locals(fcx, decl, body, arg_tys, opt_self_info); check_block_with_expected(fcx, body, Some(ret_ty)); // We unify the tail expr's type with the @@ -361,7 +375,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, None => () } - for self_info.each |self_info| { + for opt_self_info.each |self_info| { fcx.write_ty(self_info.self_id, self_info.self_ty); } for vec::each2(decl.inputs, arg_tys) |input, arg| { @@ -374,7 +388,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, decl: &ast::fn_decl, body: &ast::blk, arg_tys: &[ty::t], - self_info: Option) { + opt_self_info: Option) { let tcx = fcx.ccx.tcx; let assign: @fn(ast::node_id, Option) = |nid, ty_opt| { @@ -393,7 +407,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, }; // Add the self parameter - for self_info.each |self_info| { + for opt_self_info.each |self_info| { assign(self_info.self_id, Some(self_info.self_ty)); debug!("self is assigned to %s", fcx.infcx().ty_to_str( @@ -479,32 +493,28 @@ pub fn check_fn(ccx: @mut CrateCtxt, } pub fn check_method(ccx: @mut CrateCtxt, - method: @ast::method, - self_ty: ty::t) + method: @ast::method) { - let self_info = if method.self_ty.node == ast::sty_static {None} else { - let ty = method::transform_self_type_for_method( - ccx.tcx, - Some(ty::re_bound(ty::br_self)), - self_ty, - method.self_ty.node, - TransformTypeNormally); - Some(SelfInfo {self_ty: ty, self_id: method.self_id, - span: method.self_ty.span}) - }; + let method_def_id = local_def(method.id); + let method_ty = ty::method(ccx.tcx, method_def_id); + let opt_self_info = method_ty.transformed_self_ty.map(|&ty| { + SelfInfo {self_ty: ty, + self_id: method.self_id, + span: method.self_ty.span} + }); check_bare_fn( ccx, &method.decl, &method.body, method.id, - self_info + opt_self_info ); } pub fn check_no_duplicate_fields(tcx: ty::ctxt, fields: ~[(ast::ident, span)]) { - let mut field_names = LinearMap::new(); + let mut field_names = HashMap::new(); for fields.each |p| { let (id, sp) = *p; @@ -570,15 +580,12 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { ast::item_fn(ref decl, _, _, _, ref body) => { check_bare_fn(ccx, decl, body, it.id, None); } - ast::item_impl(ref generics, _, ty, ref ms) => { + ast::item_impl(_, _, _, ref ms) => { let rp = ccx.tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); debug!("item_impl %s with id %d rp %?", *ccx.tcx.sess.str_of(it.ident), it.id, rp); - let rp = RegionParameterization::from_variance_and_generics( - rp, generics); - let self_ty = ccx.to_ty(&rscope::type_rscope(rp), ty); for ms.each |m| { - check_method(ccx, *m, self_ty); + check_method(ccx, *m); } } ast::item_trait(_, _, ref trait_methods) => { @@ -589,8 +596,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { // bodies to check. } provided(m) => { - let self_ty = ty::mk_self(ccx.tcx, local_def(it.id)); - check_method(ccx, m, self_ty); + check_method(ccx, m); } } } @@ -610,7 +616,7 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } else { for m.items.each |item| { let tpt = ty::lookup_item_type(ccx.tcx, local_def(item.id)); - if !tpt.bounds.is_empty() { + if tpt.generics.has_type_params() { ccx.tcx.sess.span_err( item.span, fmt!("foreign items may not have type parameters")); @@ -629,6 +635,10 @@ impl AstConv for FnCtxt { ty::lookup_item_type(self.tcx(), id) } + fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef { + ty::lookup_trait_def(self.tcx(), id) + } + fn ty_infer(&self, _span: span) -> ty::t { self.infcx().next_ty_var() } @@ -757,11 +767,11 @@ pub impl FnCtxt { } fn expr_to_str(&self, expr: @ast::expr) -> ~str { - expr_repr(self.tcx(), expr) + expr.repr(self.tcx()) } fn pat_to_str(&self, pat: @ast::pat) -> ~str { - pat_repr(self.tcx(), pat) + pat.repr(self.tcx()) } fn expr_ty(&self, ex: @ast::expr) -> ty::t { @@ -863,8 +873,12 @@ pub impl FnCtxt { } fn require_unsafe(&self, sp: span, op: ~str) { - match self.purity { - ast::unsafe_fn => {/*ok*/} + match self.ps.purity { + ast::unsafe_fn => { + // ok, but flag that we used the source of unsafeness + debug!("flagging %? as a used unsafe source", self.ps.from); + self.tcx().used_unsafe.insert(self.ps.from); + } _ => { self.ccx.tcx.sess.span_err( sp, @@ -1064,7 +1078,7 @@ pub fn impl_self_ty(vcx: &VtableContext, let (n_tps, region_param, raw_ty) = { let ity = ty::lookup_item_type(tcx, did); - (vec::len(*ity.bounds), ity.region_param, ity.ty) + (ity.generics.type_param_defs.len(), ity.generics.region_param, ity.ty) }; let self_r = if region_param.is_some() { @@ -1122,103 +1136,84 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, unifier: &fn()) { debug!(">> typechecking %s", fcx.expr_to_str(expr)); - // A generic function to factor out common logic from call and - // overloaded operations - fn check_call_inner( + fn check_method_argument_types( fcx: @mut FnCtxt, sp: span, - call_expr_id: ast::node_id, - in_fty: ty::t, + method_fn_ty: ty::t, callee_expr: @ast::expr, args: &[@ast::expr], sugar: ast::CallSugar, deref_args: DerefArgs) -> ty::t { - let tcx = fcx.ccx.tcx; - - // Replace all region parameters in the arguments and return - // type with fresh region variables. - - debug!("check_call_inner: before universal quant., in_fty=%s", - fcx.infcx().ty_to_str(in_fty)); - - let formal_tys; - - // FIXME(#3678) For now, do not permit calls to C abi functions. - match structure_of(fcx, sp, in_fty) { - ty::ty_bare_fn(ty::BareFnTy {abis, _}) => { - if !abis.is_rust() { - tcx.sess.span_err( + if ty::type_is_error(method_fn_ty) { + let err_inputs = err_args(fcx.tcx(), args.len()); + check_argument_types(fcx, sp, err_inputs, callee_expr, + args, sugar, deref_args); + method_fn_ty + } else { + match ty::get(method_fn_ty).sty { + ty::ty_bare_fn(ref fty) => { + check_argument_types(fcx, sp, fty.sig.inputs, callee_expr, + args, sugar, deref_args); + fty.sig.output + } + _ => { + fcx.tcx().sess.span_bug( sp, - fmt!("Calls to C ABI functions are not (yet) \ - supported; be patient, dear user")); + fmt!("Method without bare fn type")); } } - _ => {} } + } - // This is subtle: we expect `fty` to be a function type, which - // normally introduce a level of binding. In this case, we want to - // process the types bound by the function but not by any nested - // functions. Therefore, we match one level of structure. - let ret_ty = match structure_of(fcx, sp, in_fty) { - ty::ty_bare_fn(ty::BareFnTy {sig: ref sig, _}) | - ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => { - let (_, _, sig) = - replace_bound_regions_in_fn_sig( - tcx, @Nil, None, sig, - |_br| fcx.infcx().next_region_var( - sp, call_expr_id)); - - let supplied_arg_count = args.len(); - - // Grab the argument types, supplying fresh type variables - // if the wrong number of arguments were supplied - let expected_arg_count = sig.inputs.len(); - formal_tys = if expected_arg_count == supplied_arg_count { - sig.inputs.map(|a| a.ty) - } else { - let suffix = match sugar { - ast::NoSugar => "", - ast::DoSugar => " (including the closure passed by \ - the `do` keyword)", - ast::ForSugar => " (including the closure passed by \ - the `for` keyword)" - }; - let msg = fmt!("this function takes %u parameter%s but \ - %u parameter%s supplied%s", - expected_arg_count, - if expected_arg_count == 1 {""} - else {"s"}, - supplied_arg_count, - if supplied_arg_count == 1 {" was"} - else {"s were"}, - suffix); - - tcx.sess.span_err(sp, msg); - - vec::from_fn(supplied_arg_count, |_| ty::mk_err(tcx)) - }; - - sig.output - } + fn check_argument_types( + fcx: @mut FnCtxt, + sp: span, + fn_inputs: &[ty::arg], + callee_expr: @ast::expr, + args: &[@ast::expr], + sugar: ast::CallSugar, + deref_args: DerefArgs) + { + /*! + * + * Generic function that factors out common logic from + * function calls, method calls and overloaded operators. + */ - _ => { - fcx.type_error_message(sp, |actual| { - fmt!("expected function or foreign function but \ - found `%s`", actual) }, in_fty, None); + let tcx = fcx.ccx.tcx; - // check each arg against "error", in order to set up - // all the node type bindings - formal_tys = args.map(|_x| ty::mk_err(tcx)); - ty::mk_err(tcx) - } + // Grab the argument types, supplying fresh type variables + // if the wrong number of arguments were supplied + let supplied_arg_count = args.len(); + let expected_arg_count = fn_inputs.len(); + let formal_tys = if expected_arg_count == supplied_arg_count { + fn_inputs.map(|a| a.ty) + } else { + let suffix = match sugar { + ast::NoSugar => "", + ast::DoSugar => " (including the closure passed by \ + the `do` keyword)", + ast::ForSugar => " (including the closure passed by \ + the `for` keyword)" + }; + let msg = fmt!("this function takes %u parameter%s but \ + %u parameter%s supplied%s", + expected_arg_count, + if expected_arg_count == 1 {""} + else {"s"}, + supplied_arg_count, + if supplied_arg_count == 1 {" was"} + else {"s were"}, + suffix); + + tcx.sess.span_err(sp, msg); + + vec::from_elem(supplied_arg_count, ty::mk_err(tcx)) }; - debug!("check_call_inner: after universal quant., \ - formal_tys=%? ret_ty=%s", - formal_tys.map(|t| fcx.infcx().ty_to_str(*t)), - fcx.infcx().ty_to_str(ret_ty)); + debug!("check_argument_types: formal_tys=%?", + formal_tys.map(|t| fcx.infcx().ty_to_str(*t))); // Check the arguments. // We do this in a pretty awful way: first we typecheck any arguments @@ -1268,8 +1263,11 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } } + } - ret_ty + fn err_args(tcx: ty::ctxt, len: uint) -> ~[ty::arg] { + vec::from_fn(len, |_| ty::arg {mode: ast::expl(ast::by_copy), + ty: ty::mk_err(tcx)}) } // A generic function for checking assignment expressions @@ -1284,43 +1282,63 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // The callee checks for bot / err, we don't need to } - // A generic function for doing all of the checking for call or - // method expressions - fn check_call_or_method(fcx: @mut FnCtxt, - sp: span, - call_expr_id: ast::node_id, - fn_ty: ty::t, - expr: @ast::expr, - args: &[@ast::expr], - sugar: ast::CallSugar) - { - - // Call the generic checker. - let ret_ty = check_call_inner(fcx, sp, call_expr_id, - fn_ty, expr, args, sugar, - DontDerefArgs); - // Pull the return type out of the type of the function. - fcx.write_ty(call_expr_id, ret_ty); - // Callee checks for bot and err, no need for that - } - // A generic function for doing all of the checking for call expressions fn check_call(fcx: @mut FnCtxt, - sp: span, - call_expr_id: ast::node_id, + call_expr: @ast::expr, f: @ast::expr, args: &[@ast::expr], sugar: ast::CallSugar) { // Index expressions need to be handled separately, to inform them // that they appear in call position. - let mut _bot = check_expr(fcx, f); - check_call_or_method(fcx, - sp, - call_expr_id, - fcx.expr_ty(f), - f, - args, - sugar) + check_expr(fcx, f); + + + // Extract the function signature from `in_fty`. + let fn_ty = fcx.expr_ty(f); + let fn_sty = structure_of(fcx, f.span, fn_ty); + + // FIXME(#3678) For now, do not permit calls to C abi functions. + match fn_sty { + ty::ty_bare_fn(ty::BareFnTy {abis, _}) => { + if !abis.is_rust() { + fcx.tcx().sess.span_err( + call_expr.span, + fmt!("Calls to C ABI functions are not (yet) \ + supported; be patient, dear user")); + } + } + _ => {} + } + + let fn_sig = match fn_sty { + ty::ty_bare_fn(ty::BareFnTy {sig: sig, _}) | + ty::ty_closure(ty::ClosureTy {sig: sig, _}) => sig, + _ => { + fcx.type_error_message(call_expr.span, |actual| { + fmt!("expected function but \ + found `%s`", actual) }, fn_ty, None); + + // check each arg against "error", in order to set up + // all the node type bindings + FnSig {bound_lifetime_names: opt_vec::Empty, + inputs: err_args(fcx.tcx(), args.len()), + output: ty::mk_err(fcx.tcx())} + } + }; + + // Replace any bound regions that appear in the function + // signature with region variables + let (_, _, fn_sig) = + replace_bound_regions_in_fn_sig( + fcx.tcx(), @Nil, None, &fn_sig, + |_br| fcx.infcx().next_region_var(call_expr.span, call_expr.id)); + + // Call the generic checker. + check_argument_types(fcx, call_expr.span, fn_sig.inputs, f, + args, sugar, DontDerefArgs); + + // Pull the return type out of the type of the function. + fcx.write_ty(call_expr.id, fn_sig.output); } // Checks a method call. @@ -1332,6 +1350,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, tps: &[@ast::Ty], sugar: ast::CallSugar) { check_expr(fcx, rcvr); + // no need to check for bot/err -- callee does that let expr_t = structurally_resolved_type(fcx, expr.span, @@ -1369,13 +1388,14 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } - check_call_or_method(fcx, - expr.span, - expr.id, - fcx.node_ty(expr.callee_id), - expr, - args, - sugar) + // Call the generic checker. + let fn_ty = fcx.node_ty(expr.callee_id); + let ret_ty = check_method_argument_types(fcx, expr.span, + fn_ty, expr, args, sugar, + DontDerefArgs); + + // Pull the return type out of the type of the function. + fcx.write_ty(expr.id, ret_ty); } // A generic function for checking the then and else in an if @@ -1423,10 +1443,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let method_ty = fcx.node_ty(op_ex.callee_id); let method_map = fcx.inh.method_map; method_map.insert(op_ex.id, *origin); - check_call_inner(fcx, op_ex.span, - op_ex.id, method_ty, - op_ex, args, - ast::NoSugar, deref_args) + check_method_argument_types(fcx, op_ex.span, + method_ty, op_ex, args, + ast::NoSugar, deref_args) } _ => { let tcx = fcx.tcx(); @@ -1434,9 +1453,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Check the args anyway // so we get all the error messages let expected_ty = ty::mk_err(tcx); - check_call_inner(fcx, op_ex.span, op_ex.id, - expected_ty, op_ex, args, - ast::NoSugar, deref_args); + check_method_argument_types(fcx, op_ex.span, + expected_ty, op_ex, args, + ast::NoSugar, deref_args); ty::mk_err(tcx) } } @@ -1670,12 +1689,13 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_ty(expr.id, fty); - let inherited_purity = - ty::determine_inherited_purity(copy fcx.purity, purity, + let (inherited_purity, id) = + ty::determine_inherited_purity((fcx.ps.purity, fcx.ps.from), + (purity, expr.id), sigil); check_fn(fcx.ccx, None, inherited_purity, &fty_sig, - decl, body, fn_kind, fcx.in_scope_regions, fcx.inh); + decl, id, body, fn_kind, fcx.in_scope_regions, fcx.inh); } @@ -1761,7 +1781,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, check_completeness: bool) { let tcx = fcx.ccx.tcx; - let mut class_field_map = LinearMap::new(); + let mut class_field_map = HashMap::new(); let mut fields_found = 0; for field_types.each |field| { // XXX: Check visibility here. @@ -1884,8 +1904,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } else { let item_type = ty::lookup_item_type(tcx, class_id); - type_parameter_count = (*item_type.bounds).len(); - region_parameterized = item_type.region_param; + type_parameter_count = item_type.generics.type_param_defs.len(); + region_parameterized = item_type.generics.region_param; raw_type = item_type.ty; } @@ -1972,8 +1992,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } else { let item_type = ty::lookup_item_type(tcx, enum_id); - type_parameter_count = (*item_type.bounds).len(); - region_parameterized = item_type.region_param; + type_parameter_count = item_type.generics.type_param_defs.len(); + region_parameterized = item_type.generics.region_param; raw_type = item_type.ty; } @@ -2121,12 +2141,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, match expr.node { ast::expr_vstore(ev, vst) => { let typ = match ev.node { - ast::expr_lit(@codemap::spanned { node: ast::lit_str(s), _ }) => { - let tt = ast_expr_vstore_to_vstore(fcx, ev, s.len(), vst); + ast::expr_lit(@codemap::spanned { node: ast::lit_str(_), _ }) => { + let tt = ast_expr_vstore_to_vstore(fcx, ev, vst); ty::mk_estr(tcx, tt) } ast::expr_vec(ref args, mutbl) => { - let tt = ast_expr_vstore_to_vstore(fcx, ev, args.len(), vst); + let tt = ast_expr_vstore_to_vstore(fcx, ev, vst); let mutability; let mut any_error = false; let mut any_bot = false; @@ -2158,9 +2178,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } ast::expr_repeat(element, count_expr, mutbl) => { - let count = ty::eval_repeat_count(tcx, count_expr); + let _ = ty::eval_repeat_count(tcx, count_expr); check_expr_with_hint(fcx, count_expr, ty::mk_uint(tcx)); - let tt = ast_expr_vstore_to_vstore(fcx, ev, count, vst); + let tt = ast_expr_vstore_to_vstore(fcx, ev, vst); let mutability = match vst { ast::expr_vstore_mut_box | ast::expr_vstore_mut_slice => { ast::m_mutbl @@ -2546,7 +2566,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, fcx.write_ty(id, fcx.node_ty(b.node.id)); } ast::expr_call(f, ref args, sugar) => { - check_call(fcx, expr.span, expr.id, f, *args, sugar); + check_call(fcx, expr, f, *args, sugar); let f_ty = fcx.expr_ty(f); let (args_bot, args_err) = args.foldl((false, false), |&(rest_bot, rest_err), a| { @@ -2832,8 +2852,7 @@ pub fn check_decl_local(fcx: @mut FnCtxt, local: @ast::local) { _ => {} } - let region = - ty::re_scope(*tcx.region_map.get(&local.node.id)); + let region = tcx.region_maps.encl_region(local.node.id); let pcx = pat_ctxt { fcx: fcx, map: pat_id_map(tcx.def_map, local.node.pat), @@ -2915,8 +2934,11 @@ pub fn check_block_with_expected(fcx0: @mut FnCtxt, blk: &ast::blk, expected: Option) { let fcx = match blk.node.rules { - ast::unsafe_blk => @mut FnCtxt {purity: ast::unsafe_fn,.. copy *fcx0}, - ast::default_blk => fcx0 + ast::unsafe_blk => @mut FnCtxt { + ps: PurityState { purity: ast::unsafe_fn, from: blk.node.id }, + .. copy *fcx0 + }, + ast::default_blk => fcx0 }; do fcx.with_region_lb(blk.node.id) { let mut warned = false; @@ -3143,8 +3165,10 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_fn(_, ast::extern_fn) => { // extern functions are just u8 pointers return ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics { + type_param_defs: @~[], + region_param: None + }, ty: ty::mk_ptr( fcx.ccx.tcx, ty::mt { @@ -3169,7 +3193,10 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_upvar(_, inner, _, _) => { return ty_param_bounds_and_ty_for_def(fcx, sp, *inner); } - ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*)=> { + ast::def_trait(_) | + ast::def_ty(_) | + ast::def_prim_ty(_) | + ast::def_ty_param(*)=> { fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type"); } ast::def_mod(*) | ast::def_foreign_mod(*) => { @@ -3197,21 +3224,25 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, // Instantiates the given path, which must refer to an item with the given // number of type parameters and type. pub fn instantiate_path(fcx: @mut FnCtxt, - pth: @ast::path, + pth: @ast::Path, tpt: ty_param_bounds_and_ty, span: span, node_id: ast::node_id, region_lb: ty::Region) { debug!(">>> instantiate_path"); - let ty_param_count = vec::len(*tpt.bounds); + let ty_param_count = tpt.generics.type_param_defs.len(); let ty_substs_len = vec::len(pth.types); + debug!("ty_param_count=%? ty_substs_len=%?", + ty_param_count, + ty_substs_len); + // determine the region bound, using the value given by the user // (if any) and otherwise using a fresh region variable let self_r = match pth.rp { Some(_) => { // user supplied a lifetime parameter... - match tpt.region_param { + match tpt.generics.region_param { None => { // ...but the type is not lifetime parameterized! fcx.ccx.tcx.sess.span_err (span, ~"this item is not region-parameterized"); @@ -3224,7 +3255,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } None => { // no lifetime parameter supplied, insert default fcx.region_var_if_parameterized( - tpt.region_param, span, region_lb) + tpt.generics.region_param, span, region_lb) } }; @@ -3302,7 +3333,6 @@ pub fn type_is_c_like_enum(fcx: @mut FnCtxt, sp: span, typ: ty::t) -> bool { pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt, e: @ast::expr, - _n: uint, v: ast::expr_vstore) -> ty::vstore { match v { @@ -3423,28 +3453,13 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { } ~"visit_tydesc" => { let tydesc_name = special_idents::tydesc; - let ty_visitor_name = tcx.sess.ident_of(~"TyVisitor"); assert!(tcx.intrinsic_defs.contains_key(&tydesc_name)); - assert!(ccx.tcx.intrinsic_defs.contains_key(&ty_visitor_name)); let (_, tydesc_ty) = *tcx.intrinsic_defs.get(&tydesc_name); - let (_, visitor_trait) = *tcx.intrinsic_defs.get(&ty_visitor_name); - - let visitor_trait = match ty::get(visitor_trait).sty { - ty::ty_trait(trait_def_id, ref trait_substs, _) => { - ty::mk_trait(tcx, - trait_def_id, - copy *trait_substs, - ty::BoxTraitStore) - } - _ => { - tcx.sess.span_bug(it.span, ~"TyVisitor wasn't a trait?!") - } - }; - + let (_, visitor_object_ty) = ty::visitor_object_ty(tcx); let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {ty: tydesc_ty, mutbl: ast::m_imm}); (0u, ~[arg(ast::by_copy, td_ptr), - arg(ast::by_ref, visitor_trait)], ty::mk_nil(tcx)) + arg(ast::by_ref, visitor_object_ty)], ty::mk_nil(tcx)) } ~"frame_address" => { let fty = ty::mk_closure(ccx.tcx, ty::ClosureTy { @@ -3690,7 +3705,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { output: output} }); let i_ty = ty::lookup_item_type(ccx.tcx, local_def(it.id)); - let i_n_tps = (*i_ty.bounds).len(); + let i_n_tps = i_ty.generics.type_param_defs.len(); if i_n_tps != n_tps { tcx.sess.span_err(it.span, fmt!("intrinsic has wrong number \ of type parameters: found %u, \ diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index dfc5f218d67d0..5594f2a0f658b 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -31,13 +31,15 @@ use core::prelude::*; use middle::freevars::get_freevars; use middle::pat_util::pat_bindings; -use middle::ty::{encl_region, re_scope}; +use middle::ty::{re_scope}; use middle::ty; use middle::typeck::check::FnCtxt; use middle::typeck::check::lookup_def; +use middle::typeck::check::regionmanip::relate_nested_regions; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; -use util::ppaux::{note_and_explain_region, ty_to_str}; +use util::ppaux::{note_and_explain_region, ty_to_str, + region_to_str}; use core::result; use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil}; @@ -53,12 +55,13 @@ pub struct Rcx { pub type rvt = visit::vt<@mut Rcx>; -pub fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::def) -> ty::Region { +fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::def) -> ty::Region { let tcx = fcx.tcx(); match def { def_local(node_id, _) | def_arg(node_id, _, _) | - def_self(node_id, _) | def_binding(node_id, _) => - return encl_region(tcx, node_id), + def_self(node_id, _) | def_binding(node_id, _) => { + tcx.region_maps.encl_region(node_id) + } def_upvar(_, subdef, closure_id, body_id) => { match ty::ty_closure_sigil(fcx.node_ty(closure_id)) { BorrowedSigil => encl_region_of_def(fcx, *subdef), @@ -113,6 +116,24 @@ pub impl Rcx { fn resolve_node_type(@mut self, id: ast::node_id) -> ty::t { self.resolve_type(self.fcx.node_ty(id)) } + + /// Try to resolve the type for the given node. + fn resolve_expr_type_adjusted(@mut self, expr: @ast::expr) -> ty::t { + let ty_unadjusted = self.resolve_node_type(expr.id); + if ty::type_is_error(ty_unadjusted) || ty::type_is_bot(ty_unadjusted) { + ty_unadjusted + } else { + let tcx = self.fcx.tcx(); + let adjustments = self.fcx.inh.adjustments; + match adjustments.find(&expr.id) { + None => ty_unadjusted, + Some(&adjustment) => { + // FIXME(#3850) --- avoid region scoping errors + ty::adjust_ty(tcx, expr.span, ty_unadjusted, Some(&adjustment)) + } + } + } + } } pub fn regionck_expr(fcx: @mut FnCtxt, e: @ast::expr) { @@ -129,7 +150,7 @@ pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) { fcx.infcx().resolve_regions(); } -pub fn regionck_visitor() -> rvt { +fn regionck_visitor() -> rvt { visit::mk_vt(@visit::Visitor {visit_item: visit_item, visit_stmt: visit_stmt, visit_expr: visit_expr, @@ -138,11 +159,11 @@ pub fn regionck_visitor() -> rvt { .. *visit::default_visitor()}) } -pub fn visit_item(_item: @ast::item, &&_rcx: @mut Rcx, _v: rvt) { +fn visit_item(_item: @ast::item, &&_rcx: @mut Rcx, _v: rvt) { // Ignore items } -pub fn visit_local(l: @ast::local, &&rcx: @mut Rcx, v: rvt) { +fn visit_local(l: @ast::local, &&rcx: @mut Rcx, v: rvt) { // Check to make sure that the regions in all local variables are // within scope. // @@ -173,19 +194,24 @@ pub fn visit_local(l: @ast::local, &&rcx: @mut Rcx, v: rvt) { } } -pub fn visit_block(b: &ast::blk, &&rcx: @mut Rcx, v: rvt) { +fn visit_block(b: &ast::blk, &&rcx: @mut Rcx, v: rvt) { visit::visit_block(b, rcx, v); } -pub fn visit_expr(expr: @ast::expr, &&rcx: @mut Rcx, v: rvt) { - debug!("visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); +fn visit_expr(expr: @ast::expr, &&rcx: @mut Rcx, v: rvt) { + debug!("regionck::visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); for rcx.fcx.inh.adjustments.find(&expr.id).each |&adjustment| { + debug!("adjustment=%?", adjustment); match *adjustment { @ty::AutoDerefRef( - ty::AutoDerefRef { - autoderefs: autoderefs, autoref: Some(ref autoref)}) => { - guarantor::for_autoref(rcx, expr, autoderefs, autoref); + ty::AutoDerefRef {autoderefs: autoderefs, autoref: opt_autoref}) => + { + let expr_ty = rcx.resolve_node_type(expr.id); + constrain_derefs(rcx, expr, autoderefs, expr_ty); + for opt_autoref.each |autoref| { + guarantor::for_autoref(rcx, expr, autoderefs, autoref); + } } _ => {} } @@ -271,6 +297,16 @@ pub fn visit_expr(expr: @ast::expr, &&rcx: @mut Rcx, v: rvt) { } } + ast::expr_index(vec_expr, _) => { + let vec_type = rcx.resolve_expr_type_adjusted(vec_expr); + constrain_index(rcx, expr, vec_type); + } + + ast::expr_unary(ast::deref, base) => { + let base_ty = rcx.resolve_node_type(base.id); + constrain_derefs(rcx, expr, 1, base_ty); + } + ast::expr_addr_of(_, base) => { guarantor::for_addr_of(rcx, expr, base); } @@ -297,11 +333,11 @@ pub fn visit_expr(expr: @ast::expr, &&rcx: @mut Rcx, v: rvt) { visit::visit_expr(expr, rcx, v); } -pub fn visit_stmt(s: @ast::stmt, &&rcx: @mut Rcx, v: rvt) { +fn visit_stmt(s: @ast::stmt, &&rcx: @mut Rcx, v: rvt) { visit::visit_stmt(s, rcx, v); } -pub fn visit_node(id: ast::node_id, span: span, rcx: @mut Rcx) -> bool { +fn visit_node(id: ast::node_id, span: span, rcx: @mut Rcx) -> bool { /*! * * checks the type of the node `id` and reports an error if it @@ -314,13 +350,119 @@ pub fn visit_node(id: ast::node_id, span: span, rcx: @mut Rcx) -> bool { // find the region where this expr evaluation is taking place let tcx = fcx.ccx.tcx; - let encl_region = ty::encl_region(tcx, id); + let encl_region = match tcx.region_maps.opt_encl_scope(id) { + None => ty::re_static, + Some(r) => ty::re_scope(r) + }; // Otherwise, look at the type and see if it is a region pointer. constrain_regions_in_type_of_node(rcx, id, encl_region, span) } -pub fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { +fn encl_region_or_static(rcx: @mut Rcx, expr: @ast::expr) -> ty::Region { + // FIXME(#3850) --- interactions with modes compel overly large granularity + // that is, we would probably prefer to just return re_scope(expr.id) + // here but we cannot just yet. + + let tcx = rcx.fcx.tcx(); + match tcx.region_maps.opt_encl_scope(expr.id) { + Some(s) => ty::re_scope(s), + None => ty::re_static // occurs in constants + } +} + +fn constrain_derefs(rcx: @mut Rcx, + deref_expr: @ast::expr, + derefs: uint, + mut derefd_ty: ty::t) +{ + /*! + * Invoked on any dereference that occurs, whether explicitly + * or through an auto-deref. Checks that if this is a region + * pointer being derefenced, the lifetime of the pointer includes + * the deref expr. + */ + + let tcx = rcx.fcx.tcx(); + let r_deref_expr = encl_region_or_static(rcx, deref_expr); + for uint::range(0, derefs) |i| { + debug!("constrain_derefs(deref_expr=%s, derefd_ty=%s, derefs=%?/%?", + rcx.fcx.expr_to_str(deref_expr), + rcx.fcx.infcx().ty_to_str(derefd_ty), + i, derefs); + + match ty::get(derefd_ty).sty { + ty::ty_rptr(r_ptr, _) => { + match rcx.fcx.mk_subr(true, deref_expr.span, r_deref_expr, r_ptr) { + result::Ok(*) => {} + result::Err(*) => { + tcx.sess.span_err( + deref_expr.span, + fmt!("dereference of reference outside its lifetime")); + note_and_explain_region( + tcx, + "the reference is only valid for ", + r_ptr, + ""); + } + } + } + + _ => {} + } + + match ty::deref(tcx, derefd_ty, true) { + Some(mt) => derefd_ty = mt.ty, + None => { + tcx.sess.span_bug( + deref_expr.span, + fmt!("%?'th deref is of a non-deref'able type `%s`", + i, rcx.fcx.infcx().ty_to_str(derefd_ty))); + } + } + } +} + +fn constrain_index(rcx: @mut Rcx, + index_expr: @ast::expr, + indexed_ty: ty::t) +{ + /*! + * Invoked on any index expression that occurs. Checks that if + * this is a slice being indexed, the lifetime of the pointer + * includes the deref expr. + */ + + let tcx = rcx.fcx.tcx(); + + debug!("constrain_index(index_expr=%s, indexed_ty=%s", + rcx.fcx.expr_to_str(index_expr), + rcx.fcx.infcx().ty_to_str(indexed_ty)); + + let r_index_expr = encl_region_or_static(rcx, index_expr); + match ty::get(indexed_ty).sty { + ty::ty_estr(ty::vstore_slice(r_ptr)) | + ty::ty_evec(_, ty::vstore_slice(r_ptr)) => { + match rcx.fcx.mk_subr(true, index_expr.span, r_index_expr, r_ptr) { + result::Ok(*) => {} + result::Err(*) => { + tcx.sess.span_err( + index_expr.span, + fmt!("index of slice outside its lifetime")); + note_and_explain_region( + tcx, + "the slice is only valid for ", + r_ptr, + ""); + } + } + } + + _ => {} + } +} + +fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { /*! * * If `expr` is auto-ref'd (e.g., as part of a borrow), then this @@ -340,7 +482,7 @@ pub fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { }; let tcx = rcx.fcx.tcx(); - let encl_region = ty::encl_region(tcx, expr.id); + let encl_region = tcx.region_maps.encl_region(expr.id); match rcx.fcx.mk_subr(true, expr.span, encl_region, region) { result::Ok(()) => {} result::Err(_) => { @@ -366,7 +508,7 @@ pub fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { } } -pub fn constrain_free_variables( +fn constrain_free_variables( rcx: @mut Rcx, region: ty::Region, expr: @ast::expr) { @@ -402,81 +544,103 @@ pub fn constrain_free_variables( } } -pub fn constrain_regions_in_type_of_node( +fn constrain_regions_in_type_of_node( rcx: @mut Rcx, id: ast::node_id, encl_region: ty::Region, - span: span) -> bool { + span: span) -> bool +{ let tcx = rcx.fcx.tcx(); // Try to resolve the type. If we encounter an error, then typeck // is going to fail anyway, so just stop here and let typeck // report errors later on in the writeback phase. - let ty = rcx.resolve_node_type(id); + let ty0 = rcx.resolve_node_type(id); + let adjustment = rcx.fcx.inh.adjustments.find(&id); + let ty = ty::adjust_ty(tcx, span, ty0, adjustment); debug!("constrain_regions_in_type_of_node(\ - ty=%s, id=%d, encl_region=%?)", - ty_to_str(tcx, ty), id, encl_region); + ty=%s, ty0=%s, id=%d, encl_region=%?, adjustment=%?)", + ty_to_str(tcx, ty), ty_to_str(tcx, ty0), + id, encl_region, adjustment); constrain_regions_in_type(rcx, encl_region, span, ty) } -pub fn constrain_regions_in_type( +fn constrain_regions_in_type( rcx: @mut Rcx, encl_region: ty::Region, span: span, - ty: ty::t) -> bool { + ty: ty::t) -> bool +{ /*! * * Requires that any regions which appear in `ty` must be - * superregions of `encl_region`. This prevents regions from - * being used outside of the block in which they are valid. - * Recall that regions represent blocks of code or expressions: - * this requirement basically says "any place that uses or may use - * a region R must be within the block of code that R corresponds - * to." */ + * superregions of `encl_region`. Also enforces the constraint + * that given a pointer type `&'r T`, T must not contain regions + * that outlive 'r, as well as analogous constraints for other + * lifetime'd types. + * + * This check prevents regions from being used outside of the block in + * which they are valid. Recall that regions represent blocks of + * code or expressions: this requirement basically says "any place + * that uses or may use a region R must be within the block of + * code that R corresponds to." + */ let e = rcx.errors_reported; - ty::walk_regions_and_ty( - rcx.fcx.ccx.tcx, ty, - |r| constrain_region(rcx, encl_region, span, r), - |t| ty::type_has_regions(t)); - return (e == rcx.errors_reported); + let tcx = rcx.fcx.ccx.tcx; - fn constrain_region(rcx: @mut Rcx, - encl_region: ty::Region, - span: span, - region: ty::Region) { - let tcx = rcx.fcx.ccx.tcx; + debug!("constrain_regions_in_type(encl_region=%s, ty=%s)", + region_to_str(tcx, encl_region), + ty_to_str(tcx, ty)); - debug!("constrain_region(encl_region=%?, region=%?)", - encl_region, region); + do relate_nested_regions(tcx, Some(encl_region), ty) |r_sub, r_sup| { + debug!("relate(r_sub=%s, r_sup=%s)", + region_to_str(tcx, r_sub), + region_to_str(tcx, r_sup)); - match region { - ty::re_bound(_) => { + if r_sup.is_bound() || r_sub.is_bound() { // a bound region is one which appears inside an fn type. // (e.g., the `&` in `fn(&T)`). Such regions need not be // constrained by `encl_region` as they are placeholders // for regions that are as-yet-unknown. - return; - } - _ => () - } - - match rcx.fcx.mk_subr(true, span, encl_region, region) { - result::Err(_) => { - tcx.sess.span_err( - span, - fmt!("reference is not valid outside of its lifetime")); - note_and_explain_region( - tcx, - ~"the reference is only valid for ", - region, - ~""); - rcx.errors_reported += 1u; - } - result::Ok(()) => { - } + } else { + match rcx.fcx.mk_subr(true, span, r_sub, r_sup) { + result::Err(_) => { + if r_sub == encl_region { + tcx.sess.span_err( + span, + fmt!("reference is not valid outside of its lifetime")); + note_and_explain_region( + tcx, + "the reference is only valid for ", + r_sup, + ""); + } else { + tcx.sess.span_err( + span, + fmt!("in type `%s`, pointer has a longer lifetime than \ + the data it references", + rcx.fcx.infcx().ty_to_str(ty))); + note_and_explain_region( + tcx, + "the pointer is valid for ", + r_sub, + ""); + note_and_explain_region( + tcx, + "but the referenced data is only valid for ", + r_sup, + ""); + } + rcx.errors_reported += 1u; + } + result::Ok(()) => { + } + } } } + + return (e == rcx.errors_reported); } pub mod guarantor { @@ -494,8 +658,8 @@ pub mod guarantor { * inferencer would not know of this dependency and thus it might * infer the lifetime of L2 to be greater than L1 (issue #3148). * - * There are a number of troublesome scenarios in the test - * `region-dependent-addr-of.rs`, but here is one example: + * There are a number of troublesome scenarios in the tests + * `region-dependent-*.rs`, but here is one example: * * struct Foo { i: int } * struct Bar { foo: Foo } @@ -577,14 +741,43 @@ pub mod guarantor { * region pointers. */ - debug!("guarantor::for_autoref(expr=%s)", rcx.fcx.expr_to_str(expr)); + debug!("guarantor::for_autoref(expr=%s, autoref=%?)", + rcx.fcx.expr_to_str(expr), autoref); let _i = ::util::common::indenter(); let mut expr_ct = categorize_unadjusted(rcx, expr); + debug!(" unadjusted cat=%?", expr_ct.cat); expr_ct = apply_autoderefs( rcx, expr, autoderefs, expr_ct); - for expr_ct.cat.guarantor.each |g| { - infallibly_mk_subr(rcx, true, expr.span, autoref.region, *g); + + match autoref.kind { + ty::AutoPtr => { + // In this case, we are implicitly adding an `&`. + maybe_make_subregion(rcx, expr, autoref.region, + expr_ct.cat.guarantor); + } + + ty::AutoBorrowVec | + ty::AutoBorrowVecRef | + ty::AutoBorrowFn => { + // In each of these cases, what is being borrowed is + // not the (autoderef'd) expr itself but rather the + // contents of the autoderef'd expression (i.e., what + // the pointer points at). + maybe_make_subregion(rcx, expr, autoref.region, + guarantor_of_deref(&expr_ct.cat)); + } + } + + fn maybe_make_subregion( + rcx: @mut Rcx, + expr: @ast::expr, + sub_region: ty::Region, + sup_region: Option) + { + for sup_region.each |r| { + infallibly_mk_subr(rcx, true, expr.span, sub_region, *r); + } } } @@ -599,7 +792,7 @@ pub mod guarantor { * to the lifetime of its guarantor (if any). */ - debug!("opt_constrain_region(id=%?, guarantor=%?)", id, guarantor); + debug!("link(id=%?, guarantor=%?)", id, guarantor); let bound = match guarantor { None => { @@ -813,19 +1006,29 @@ pub mod guarantor { fn pointer_categorize(ty: ty::t) -> PointerCategorization { match ty::get(ty).sty { - ty::ty_rptr(r, _) | ty::ty_evec(_, ty::vstore_slice(r)) | + ty::ty_rptr(r, _) | + ty::ty_evec(_, ty::vstore_slice(r)) | ty::ty_estr(ty::vstore_slice(r)) => { BorrowedPointer(r) } - ty::ty_uniq(*) | ty::ty_estr(ty::vstore_uniq) | + ty::ty_uniq(*) | + ty::ty_estr(ty::vstore_uniq) | ty::ty_evec(_, ty::vstore_uniq) => { OwnedPointer } - ty::ty_box(*) | ty::ty_ptr(*) | + ty::ty_box(*) | + ty::ty_ptr(*) | ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => { OtherPointer } + ty::ty_closure(ref closure_ty) => { + match closure_ty.sigil { + ast::BorrowedSigil => BorrowedPointer(closure_ty.region), + ast::OwnedSigil => OwnedPointer, + ast::ManagedSigil => OtherPointer, + } + } _ => { NotPointer } @@ -933,7 +1136,6 @@ pub fn infallibly_mk_subr(rcx: @mut Rcx, a: ty::Region, b: ty::Region) { /*! - * * Constrains `a` to be a subregion of `b`. In many cases, we * know that this can never yield an error due to the way that * region inferencing works. Therefore just report a bug if we diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index abbefd1f7e6f9..1abcefeefac8c 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -13,7 +13,7 @@ use core::prelude::*; use middle::ty; -use middle::typeck::check::SelfInfo; + use middle::typeck::isr_alist; use util::common::indenter; use util::ppaux::region_to_str; @@ -26,29 +26,24 @@ use std::list::Cons; pub fn replace_bound_regions_in_fn_sig( tcx: ty::ctxt, isr: isr_alist, - self_info: Option, + opt_self_ty: Option, fn_sig: &ty::FnSig, mapf: &fn(ty::bound_region) -> ty::Region) - -> (isr_alist, Option, ty::FnSig) + -> (isr_alist, Option, ty::FnSig) { - // Take self_info apart; the self_ty part is the only one we want - // to update here. - let self_ty = self_info.map(|s| s.self_ty); - let rebuild_self_info = |t| self_info.map(|s| SelfInfo{self_ty: t, ..*s}); - let mut all_tys = ty::tys_in_fn_sig(fn_sig); - for self_info.each |self_info| { - all_tys.push(self_info.self_ty); + for opt_self_ty.each |&self_ty| { + all_tys.push(self_ty); } - for self_ty.each |t| { all_tys.push(*t) } + for opt_self_ty.each |&t| { all_tys.push(t) } - debug!("replace_bound_regions_in_fn_sig(self_info.self_ty=%?, fn_sig=%s, \ + debug!("replace_bound_regions_in_fn_sig(self_ty=%?, fn_sig=%s, \ all_tys=%?)", - self_ty.map(|t| ppaux::ty_to_str(tcx, *t)), + opt_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)), ppaux::fn_sig_to_str(tcx, fn_sig), - all_tys.map(|t| ppaux::ty_to_str(tcx, *t))); + all_tys.map(|&t| ppaux::ty_to_str(tcx, t))); let _i = indenter(); let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| { @@ -58,20 +53,15 @@ pub fn replace_bound_regions_in_fn_sig( let new_fn_sig = ty::fold_sig(fn_sig, |t| { replace_bound_regions(tcx, isr, t) }); - let t_self = self_ty.map(|t| replace_bound_regions(tcx, isr, *t)); + let new_self_ty = opt_self_ty.map(|&t| replace_bound_regions(tcx, isr, t)); - debug!("result of replace_bound_regions_in_fn_sig: self_info.self_ty=%?, \ - fn_sig=%s", - t_self.map(|t| ppaux::ty_to_str(tcx, *t)), + debug!("result of replace_bound_regions_in_fn_sig: \ + new_self_ty=%?, \ + fn_sig=%s", + new_self_ty.map(|&t| ppaux::ty_to_str(tcx, t)), ppaux::fn_sig_to_str(tcx, &new_fn_sig)); - // Glue updated self_ty back together with its original def_id. - let new_self_info: Option = match t_self { - None => None, - Some(t) => rebuild_self_info(t) - }; - - return (isr, new_self_info, new_fn_sig); + return (isr, new_self_ty, new_fn_sig); // Takes `isr`, a (possibly empty) mapping from in-scope region // names ("isr"s) to their corresponding regions; `tys`, a list of @@ -99,7 +89,7 @@ pub fn replace_bound_regions_in_fn_sig( to_r: &fn(ty::bound_region) -> ty::Region, r: ty::Region) -> isr_alist { match r { - ty::re_free(_, _) | ty::re_static | ty::re_scope(_) | + ty::re_free(*) | ty::re_static | ty::re_scope(_) | ty::re_infer(_) => { isr } @@ -167,10 +157,125 @@ pub fn replace_bound_regions_in_fn_sig( // Free regions like these just stay the same: ty::re_static | ty::re_scope(_) | - ty::re_free(_, _) | + ty::re_free(*) | ty::re_infer(_) => r }; r1 } } } + +pub fn relate_nested_regions( + tcx: ty::ctxt, + opt_region: Option, + ty: ty::t, + relate_op: &fn(ty::Region, ty::Region)) +{ + /*! + * + * This rather specialized function walks each region `r` that appear + * in `ty` and invokes `relate_op(r_encl, r)` for each one. `r_encl` + * here is the region of any enclosing `&'r T` pointer. If there is + * no enclosing pointer, and `opt_region` is Some, then `opt_region.get()` + * is used instead. Otherwise, no callback occurs at all). + * + * Here are some examples to give you an intution: + * + * - `relate_nested_regions(Some('r1), &'r2 uint)` invokes + * - `relate_op('r1, 'r2)` + * - `relate_nested_regions(Some('r1), &'r2 &'r3 uint)` invokes + * - `relate_op('r1, 'r2)` + * - `relate_op('r2, 'r3)` + * - `relate_nested_regions(None, &'r2 &'r3 uint)` invokes + * - `relate_op('r2, 'r3)` + * - `relate_nested_regions(None, &'r2 &'r3 &'r4 uint)` invokes + * - `relate_op('r2, 'r3)` + * - `relate_op('r2, 'r4)` + * - `relate_op('r3, 'r4)` + * + * This function is used in various pieces of code because we enforce the + * constraint that a region pointer cannot outlive the things it points at. + * Hence, in the second example above, `'r2` must be a subregion of `'r3`. + */ + + let mut the_stack = ~[]; + for opt_region.each |&r| { the_stack.push(r); } + walk_ty(tcx, &mut the_stack, ty, relate_op); + + fn walk_ty(tcx: ty::ctxt, + the_stack: &mut ~[ty::Region], + ty: ty::t, + relate_op: &fn(ty::Region, ty::Region)) + { + match ty::get(ty).sty { + ty::ty_rptr(r, ref mt) | + ty::ty_evec(ref mt, ty::vstore_slice(r)) => { + relate(*the_stack, r, relate_op); + the_stack.push(r); + walk_ty(tcx, the_stack, mt.ty, relate_op); + the_stack.pop(); + } + _ => { + ty::fold_regions_and_ty( + tcx, + ty, + |r| { relate(*the_stack, r, relate_op); r }, + |t| { walk_ty(tcx, the_stack, t, relate_op); t }, + |t| { walk_ty(tcx, the_stack, t, relate_op); t }); + } + } + } + + fn relate(the_stack: &[ty::Region], + r_sub: ty::Region, + relate_op: &fn(ty::Region, ty::Region)) + { + for the_stack.each |&r| { + if !r.is_bound() && !r_sub.is_bound() { + relate_op(r, r_sub); + } + } + } +} + +pub fn relate_free_regions( + tcx: ty::ctxt, + self_ty: Option, + fn_sig: &ty::FnSig) +{ + /*! + * This function populates the region map's `free_region_map`. + * It walks over the transformed self type and argument types + * for each function just before we check the body of that + * function, looking for types where you have a borrowed + * pointer to other borrowed data (e.g., `&'a &'b [uint]`. + * We do not allow borrowed pointers to outlive the things they + * point at, so we can assume that `'a <= 'b`. + * + * Tests: `src/test/compile-fail/regions-free-region-ordering-*.rs` + */ + + debug!("relate_free_regions >>"); + + let mut all_tys = ~[]; + for fn_sig.inputs.each |arg| { + all_tys.push(arg.ty); + } + for self_ty.each |&t| { + all_tys.push(t); + } + + for all_tys.each |&t| { + debug!("relate_free_regions(t=%s)", ppaux::ty_to_str(tcx, t)); + relate_nested_regions(tcx, None, t, |a, b| { + match (&a, &b) { + (&ty::re_free(free_a), &ty::re_free(free_b)) => { + tcx.region_maps.relate_free_regions(free_a, free_b); + } + _ => {} + } + }) + } + + debug!("<< relate_free_regions"); +} diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index a1eaa1f6a3394..8245dc88114c8 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -11,7 +11,7 @@ use core::prelude::*; use middle::resolve::Impl; -use middle::ty::{param_ty, substs}; +use middle::ty::{param_ty}; use middle::ty; use middle::typeck::check::{FnCtxt, impl_self_ty}; use middle::typeck::check::{structurally_resolved_type}; @@ -20,6 +20,7 @@ use middle::typeck::infer::{resolve_and_force_all_but_regions, resolve_type}; use middle::typeck::infer; use middle::typeck::{CrateCtxt, vtable_origin, vtable_param, vtable_res}; use middle::typeck::vtable_static; +use middle::subst::Subst; use util::common::indenter; use util::ppaux::tys_to_str; use util::ppaux; @@ -27,8 +28,7 @@ use util::ppaux; use core::result::{Ok, Err}; use core::result; use core::uint; -use core::vec; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use syntax::ast; use syntax::ast_util; use syntax::codemap::span; @@ -70,75 +70,73 @@ pub impl VtableContext { fn tcx(&const self) -> ty::ctxt { self.ccx.tcx } } -pub fn has_trait_bounds(tps: ~[ty::param_bounds]) -> bool { - vec::any(tps, |bs| { - bs.any(|b| { - match b { &ty::bound_trait(_) => true, _ => false } - }) - }) +fn has_trait_bounds(type_param_defs: &[ty::TypeParameterDef]) -> bool { + type_param_defs.any( + |type_param_def| type_param_def.bounds.any( + |bound| match bound { &ty::bound_trait(*) => true, _ => false })) } -pub fn lookup_vtables(vcx: &VtableContext, - location_info: &LocationInfo, - bounds: @~[ty::param_bounds], - substs: &ty::substs, - is_early: bool) -> vtable_res { - debug!("lookup_vtables(location_info=%?, - # bounds=%?, \ +fn lookup_vtables(vcx: &VtableContext, + location_info: &LocationInfo, + type_param_defs: &[ty::TypeParameterDef], + substs: &ty::substs, + is_early: bool) -> vtable_res { + debug!("lookup_vtables(location_info=%?, \ + type_param_defs=%s, \ substs=%s", location_info, - bounds.len(), - ty::substs_to_str(vcx.tcx(), substs)); + type_param_defs.repr(vcx.tcx()), + substs.repr(vcx.tcx())); let _i = indenter(); let tcx = vcx.tcx(); let mut result = ~[], i = 0u; for substs.tps.each |ty| { - for ty::iter_bound_traits_and_supertraits( - tcx, bounds[i]) |trait_ty| + // ty is the value supplied for the type parameter A... + + for ty::each_bound_trait_and_supertraits( + tcx, type_param_defs[i].bounds) |trait_ref| { - debug!("about to subst: %?, %?", - ppaux::ty_to_str(tcx, trait_ty), - ty::substs_to_str(tcx, substs)); + // ...and here trait_ref is each bound that was declared on A, + // expressed in terms of the type parameters. + + debug!("about to subst: %s, %s", trait_ref.repr(tcx), substs.repr(tcx)); - let new_substs = substs { - self_ty: Some(*ty), - ../*bad*/copy *substs - }; - let trait_ty = ty::subst(tcx, &new_substs, trait_ty); + // Substitute the values of the type parameters that may + // appear in the bound. + let trait_ref = trait_ref.subst(tcx, substs); - debug!("after subst: %?", - ppaux::ty_to_str(tcx, trait_ty)); + debug!("after subst: %s", trait_ref.repr(tcx)); - match lookup_vtable(vcx, location_info, *ty, trait_ty, is_early) { + match lookup_vtable(vcx, location_info, *ty, &trait_ref, is_early) { Some(vtable) => result.push(vtable), None => { vcx.tcx().sess.span_fatal( location_info.span, fmt!("failed to find an implementation of \ trait %s for %s", - ppaux::ty_to_str(vcx.tcx(), trait_ty), - ppaux::ty_to_str(vcx.tcx(), *ty))); + vcx.infcx.trait_ref_to_str(&trait_ref), + vcx.infcx.ty_to_str(*ty))); } } } i += 1u; } debug!("lookup_vtables result(\ - location_info=%?, - # bounds=%?, \ + location_info=%?, \ + type_param_defs=%s, \ substs=%s, \ - result=%?", + result=%s)", location_info, - bounds.len(), - ty::substs_to_str(vcx.tcx(), substs), - result); + type_param_defs.repr(vcx.tcx()), + substs.repr(vcx.tcx()), + result.repr(vcx.tcx())); @result } -pub fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, - id: ast::def_id, +substs: ty::substs, - is_early: bool) -> Option { +fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, + id: ast::def_id, +substs: ty::substs, + is_early: bool) -> Option { let tcx = vcx.tcx(); // use a dummy type just to package up the substs that need fixing up let t = ty::mk_trait(tcx, @@ -152,31 +150,58 @@ pub fn fixup_substs(vcx: &VtableContext, location_info: &LocationInfo, } } -pub fn relate_trait_tys(vcx: &VtableContext, location_info: &LocationInfo, - exp_trait_ty: ty::t, act_trait_ty: ty::t) { - demand_suptype(vcx, location_info.span, exp_trait_ty, act_trait_ty) +fn relate_trait_refs(vcx: &VtableContext, + location_info: &LocationInfo, + act_trait_ref: &ty::TraitRef, + exp_trait_ref: &ty::TraitRef) +{ + /*! + * + * Checks that an implementation of `act_trait_ref` is suitable + * for use where `exp_trait_ref` is required and reports an + * error otherwise. + */ + + match infer::mk_sub_trait_refs(vcx.infcx, false, location_info.span, + act_trait_ref, exp_trait_ref) + { + result::Ok(()) => {} // Ok. + result::Err(ref err) => { + let r_act_trait_ref = + vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(act_trait_ref); + let r_exp_trait_ref = + vcx.infcx.resolve_type_vars_in_trait_ref_if_possible(exp_trait_ref); + if !ty::trait_ref_contains_error(&r_act_trait_ref) && + !ty::trait_ref_contains_error(&r_exp_trait_ref) + { + let tcx = vcx.tcx(); + tcx.sess.span_err( + location_info.span, + fmt!("expected %s, but found %s (%s)", + ppaux::trait_ref_to_str(tcx, &r_exp_trait_ref), + ppaux::trait_ref_to_str(tcx, &r_act_trait_ref), + ty::type_err_to_str(tcx, err))); + } + } + } } // Look up the vtable to use when treating an item of type `t` as if it has // type `trait_ty` -pub fn lookup_vtable(vcx: &VtableContext, - location_info: &LocationInfo, - ty: ty::t, - trait_ty: ty::t, - is_early: bool) - -> Option { - debug!("lookup_vtable(ty=%s, trait_ty=%s)", - vcx.infcx.ty_to_str(ty), vcx.infcx.ty_to_str(trait_ty)); +fn lookup_vtable(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + trait_ref: &ty::TraitRef, + is_early: bool) + -> Option +{ + debug!("lookup_vtable(ty=%s, trait_ref=%s)", + vcx.infcx.ty_to_str(ty), + vcx.infcx.trait_ref_to_str(trait_ref)); let _i = indenter(); let tcx = vcx.tcx(); - let (trait_id, trait_substs, trait_store) = match ty::get(trait_ty).sty { - ty::ty_trait(did, ref substs, store) => - (did, (/*bad*/copy *substs), store), - _ => tcx.sess.impossible_case(location_info.span, - "lookup_vtable: \ - don't know how to handle a non-trait") - }; + let ty = match fixup_ty(vcx, location_info, ty, is_early) { Some(ty) => ty, None => { @@ -192,39 +217,21 @@ pub fn lookup_vtable(vcx: &VtableContext, match ty::get(ty).sty { ty::ty_param(param_ty {idx: n, def_id: did}) => { let mut n_bound = 0; - let bounds = *tcx.ty_param_bounds.get(&did.node); - for ty::iter_bound_traits_and_supertraits( - tcx, bounds) |ity| { - debug!("checking bounds trait %?", - vcx.infcx.ty_to_str(ity)); - - match ty::get(ity).sty { - ty::ty_trait(idid, ref isubsts, _) => { - if trait_id == idid { - debug!("(checking vtable) @0 \ - relating ty to trait \ - ty with did %?", - idid); - - // Convert `ity` so that it has the right vstore. - let ity = ty::mk_trait(vcx.tcx(), - idid, - copy *isubsts, - trait_store); - - relate_trait_tys(vcx, location_info, - trait_ty, ity); - let vtable = vtable_param(n, n_bound); - debug!("found param vtable: %?", - vtable); - return Some(vtable); - } - } - _ => tcx.sess.impossible_case( - location_info.span, - "lookup_vtable: in loop, \ - don't know how to handle a \ - non-trait ity") + let type_param_def = tcx.ty_param_defs.get(&did.node); + for ty::each_bound_trait_and_supertraits( + tcx, type_param_def.bounds) |bound_trait_ref| + { + debug!("checking bounds trait %s", bound_trait_ref.repr(vcx.tcx())); + + if bound_trait_ref.def_id == trait_ref.def_id { + relate_trait_refs(vcx, + location_info, + bound_trait_ref, + trait_ref); + let vtable = vtable_param(n, n_bound); + debug!("found param vtable: %?", + vtable); + return Some(vtable); } n_bound += 1; @@ -234,20 +241,21 @@ pub fn lookup_vtable(vcx: &VtableContext, _ => { let mut found = ~[]; - let mut impls_seen = LinearSet::new(); + let mut impls_seen = HashSet::new(); - match vcx.ccx.coherence_info.extension_methods.find(&trait_id) { + match vcx.ccx.coherence_info.extension_methods.find(&trait_ref.def_id) { None => { // Nothing found. Continue. } Some(implementations) => { let implementations: &mut ~[@Impl] = *implementations; + // implementations is the list of all impls in scope for - // trait_ty. (Usually, there's just one.) + // trait_ref. (Usually, there's just one.) for uint::range(0, implementations.len()) |i| { let im = implementations[i]; - // im is one specific impl of trait_ty. + // im is one specific impl of trait_ref. // First, ensure we haven't processed this impl yet. if impls_seen.contains(&im.did) { @@ -269,22 +277,15 @@ pub fn lookup_vtable(vcx: &VtableContext, // ~[baz, bar, quux] // // For each of the traits foo implements, if - // it's the same trait as trait_ty, we need to - // unify it with trait_ty in order to get all + // it's 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 vec::each(ty::impl_traits(tcx, - im.did, - trait_store)) |of_ty| { - match ty::get(*of_ty).sty { - ty::ty_trait(id, _, _) => { - // Not the trait we're looking for - if id != trait_id { loop; } - } - _ => { /* ok */ } - } + for ty::impl_trait_refs(tcx, im.did).each |&of_trait_ref| + { + if of_trait_ref.def_id != trait_ref.def_id { loop; } - // At this point, we know that of_ty is - // the same trait as trait_ty, but + // At this point, we know that of_trait_ref is + // the same trait as trait_ref, but // possibly applied to different substs. // // Next, we check whether the "for" ty in @@ -298,6 +299,8 @@ pub fn lookup_vtable(vcx: &VtableContext, // of the thing that we're trying to cast // to some_trait. If not, then we try the next // impl. + // + // FIXME(#5781) this should be mk_eqty not mk_subty let ty::ty_param_substs_and_ty { substs: substs, ty: for_ty @@ -318,39 +321,35 @@ pub fn lookup_vtable(vcx: &VtableContext, vcx.infcx.ty_to_str(for_ty), tys_to_str(vcx.tcx(), substs.tps)); - // Next, we unify trait_ty -- the type - // that we want to cast to -- with of_ty + // Next, we unify trait_ref -- the type + // that we want to cast to -- with of_trait_ref // -- the trait that im implements. At // this point, we require that they be // unifiable with each other -- that's - // what relate_trait_tys does. + // what relate_trait_refs does. // // For example, in the above example, - // of_ty would be some_trait, so we - // would be unifying trait_ty (for some + // of_trait_ref would be some_trait, so we + // would be unifying trait_ref (for some // value of U) with some_trait. This // would fail if T and U weren't // compatible. debug!("(checking vtable) @2 relating trait \ - ty %s to of_ty %s", - vcx.infcx.ty_to_str(trait_ty), - vcx.infcx.ty_to_str(*of_ty)); - let of_ty = ty::subst(tcx, &substs, *of_ty); - relate_trait_tys(vcx, location_info, trait_ty, - of_ty); - - // Recall that trait_ty -- the trait type - // we're casting to -- is the trait with - // id trait_id applied to the substs - // trait_substs. Now we extract out the - // types themselves from trait_substs. + ty %s to of_trait_ref %s", + vcx.infcx.trait_ref_to_str(trait_ref), + vcx.infcx.trait_ref_to_str(of_trait_ref)); - let trait_tps = /*bad*/copy trait_substs.tps; + let of_trait_ref = of_trait_ref.subst(tcx, &substs); + relate_trait_refs( + vcx, location_info, + &of_trait_ref, trait_ref); - debug!("Casting to a trait ty whose substs \ - (trait_tps) are %s", - tys_to_str(vcx.tcx(), trait_tps)); + // Recall that trait_ref -- the trait type + // we're casting to -- is the trait with + // id trait_ref.def_id applied to the substs + // trait_ref.substs. Now we extract out the + // types themselves from trait_ref.substs. // Recall that substs is the impl self // type's list of substitutions. That is, @@ -362,7 +361,7 @@ pub fn lookup_vtable(vcx: &VtableContext, let substs_f = match fixup_substs(vcx, location_info, - trait_id, + trait_ref.def_id, substs, is_early) { Some(ref substs) => (/*bad*/copy *substs), @@ -377,7 +376,7 @@ pub fn lookup_vtable(vcx: &VtableContext, they will be unified with the bounds for \ the target ty, %s", tys_to_str(vcx.tcx(), substs_f.tps), - tys_to_str(vcx.tcx(), trait_tps)); + vcx.infcx.trait_ref_to_str(trait_ref)); // Next, we unify the fixed-up // substitutions for the impl self ty with @@ -386,16 +385,16 @@ pub fn lookup_vtable(vcx: &VtableContext, // to. connect_trait_tps requires these // lists of types to unify pairwise. - let im_bs = ty::lookup_item_type(tcx, - im.did).bounds; + let im_generics = + ty::lookup_item_type(tcx, im.did).generics; connect_trait_tps(vcx, location_info, - /*bad*/copy substs_f.tps, - trait_tps, - im.did, - trait_store); + &substs_f, + trait_ref, + im.did); let subres = lookup_vtables( - vcx, location_info, im_bs, &substs_f, + vcx, location_info, + *im_generics.type_param_defs, &substs_f, is_early); // Finally, we register that we found a @@ -430,10 +429,10 @@ pub fn lookup_vtable(vcx: &VtableContext, return None; } -pub fn fixup_ty(vcx: &VtableContext, - location_info: &LocationInfo, - ty: ty::t, - is_early: bool) -> Option { +fn fixup_ty(vcx: &VtableContext, + location_info: &LocationInfo, + ty: ty::t, + is_early: bool) -> Option { let tcx = vcx.tcx(); match resolve_type(vcx.infcx, ty, resolve_and_force_all_but_regions) { Ok(new_type) => Some(new_type), @@ -450,47 +449,25 @@ pub fn fixup_ty(vcx: &VtableContext, } } -// Version of demand::suptype() that takes a vtable context instead of a -// function context. -pub fn demand_suptype(vcx: &VtableContext, sp: span, e: ty::t, a: ty::t) { - // NB: Order of actual, expected is reversed. - match infer::mk_subty(vcx.infcx, false, sp, a, e) { - result::Ok(()) => {} // Ok. - result::Err(ref err) => { - vcx.infcx.report_mismatched_types(sp, e, a, err); - } - } -} - -pub fn connect_trait_tps(vcx: &VtableContext, - location_info: &LocationInfo, - impl_tys: ~[ty::t], - trait_tys: ~[ty::t], - impl_did: ast::def_id, - store: ty::TraitStore) { +fn connect_trait_tps(vcx: &VtableContext, + location_info: &LocationInfo, + impl_substs: &ty::substs, + trait_ref: &ty::TraitRef, + impl_did: ast::def_id) +{ let tcx = vcx.tcx(); // XXX: This should work for multiple traits. - let ity = ty::impl_traits(tcx, impl_did, store)[0]; - let trait_ty = ty::subst_tps(tcx, impl_tys, None, ity); - debug!("(connect trait tps) trait type is %?, impl did is %?", - ty::get(trait_ty).sty, impl_did); - match ty::get(trait_ty).sty { - ty::ty_trait(_, ref substs, _) => { - for vec::each2((*substs).tps, trait_tys) |a, b| { - demand_suptype(vcx, location_info.span, *a, *b); - } - } - _ => tcx.sess.impossible_case(location_info.span, "connect_trait_tps: \ - don't know how to handle a non-trait ty") - } + let impl_trait_ref = ty::impl_trait_refs(tcx, impl_did)[0]; + let impl_trait_ref = impl_trait_ref.subst(tcx, impl_substs); + relate_trait_refs(vcx, location_info, &impl_trait_ref, trait_ref); } -pub fn insert_vtables(fcx: @mut FnCtxt, - callee_id: ast::node_id, - vtables: vtable_res) { +fn insert_vtables(fcx: @mut FnCtxt, + callee_id: ast::node_id, + vtables: vtable_res) { debug!("insert_vtables(callee_id=%d, vtables=%?)", - callee_id, vtables.map(|v| v.to_str(fcx.tcx()))); + callee_id, vtables.repr(fcx.tcx())); fcx.inh.vtable_map.insert(callee_id, vtables); } @@ -512,20 +489,20 @@ pub fn early_resolve_expr(ex: @ast::expr, match ex.node { ast::expr_path(*) => { for fcx.opt_node_ty_substs(ex.id) |substs| { + debug!("vtable resolution on parameter bounds for expr %s", + ex.repr(fcx.tcx())); let def = *cx.tcx.def_map.get(&ex.id); let did = ast_util::def_id_of_def(def); let item_ty = ty::lookup_item_type(cx.tcx, did); - debug!("early resolve expr: def %? %?, %?, %?", ex.id, did, def, + debug!("early resolve expr: def %? %?, %?, %s", ex.id, did, def, fcx.infcx().ty_to_str(item_ty.ty)); - if has_trait_bounds(/*bad*/copy *item_ty.bounds) { - for item_ty.bounds.each |bounds| { - debug!("early_resolve_expr: looking up vtables for bound \ - %s", - ty::param_bounds_to_str(fcx.tcx(), *bounds)); - } + if has_trait_bounds(*item_ty.generics.type_param_defs) { + debug!("early_resolve_expr: looking up vtables for type params %s", + item_ty.generics.type_param_defs.repr(fcx.tcx())); let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), - item_ty.bounds, substs, is_early); + *item_ty.generics.type_param_defs, + substs, is_early); if !is_early { insert_vtables(fcx, ex.id, vtbls); } @@ -541,9 +518,11 @@ pub fn early_resolve_expr(ex: @ast::expr, ast::expr_binary(*) | ast::expr_unary(*) | ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_method_call(*) => { - match ty::method_call_bounds(cx.tcx, fcx.inh.method_map, ex.id) { - Some(bounds) => { - if has_trait_bounds(/*bad*/copy *bounds) { + match ty::method_call_type_param_defs(cx.tcx, fcx.inh.method_map, ex.id) { + Some(type_param_defs) => { + debug!("vtable resolution on parameter bounds for method call %s", + ex.repr(fcx.tcx())); + if has_trait_bounds(*type_param_defs) { let callee_id = match ex.node { ast::expr_field(_, _, _) => ex.id, _ => ex.callee_id @@ -552,7 +531,7 @@ pub fn early_resolve_expr(ex: @ast::expr, let substs = fcx.node_ty_substs(callee_id); let vcx = VtableContext { ccx: fcx.ccx, infcx: fcx.infcx() }; let vtbls = lookup_vtables(&vcx, &location_info_for_expr(ex), - bounds, &substs, is_early); + *type_param_defs, &substs, is_early); if !is_early { insert_vtables(fcx, callee_id, vtbls); } @@ -562,9 +541,10 @@ pub fn early_resolve_expr(ex: @ast::expr, } } ast::expr_cast(src, _) => { + debug!("vtable resolution on expr %s", ex.repr(fcx.tcx())); let target_ty = fcx.expr_ty(ex); match ty::get(target_ty).sty { - ty::ty_trait(_, _, store) => { + ty::ty_trait(target_def_id, ref target_substs, store) => { // Look up vtables for the type we're casting to, // passing in the source and target type. The source // must be a pointer type suitable to the object sigil, @@ -573,7 +553,6 @@ pub fn early_resolve_expr(ex: @ast::expr, fcx.expr_ty(src)); match (&ty::get(ty).sty, store) { (&ty::ty_box(mt), ty::BoxTraitStore) | - // XXX: Bare trait store is deprecated. (&ty::ty_uniq(mt), ty::UniqTraitStore) | (&ty::ty_rptr(_, mt), ty::RegionTraitStore(*)) => { let location_info = @@ -582,11 +561,19 @@ pub fn early_resolve_expr(ex: @ast::expr, ccx: fcx.ccx, infcx: fcx.infcx() }; + let target_trait_ref = ty::TraitRef { + def_id: target_def_id, + substs: ty::substs { + tps: copy target_substs.tps, + self_r: target_substs.self_r, + self_ty: Some(mt.ty) + } + }; let vtable_opt = lookup_vtable(&vcx, location_info, mt.ty, - target_ty, + &target_trait_ref, is_early); match vtable_opt { Some(vtable) => { @@ -622,11 +609,12 @@ pub fn early_resolve_expr(ex: @ast::expr, } } - (_, ty::BareTraitStore) => { + (_, ty::UniqTraitStore) => { fcx.ccx.tcx.sess.span_err( ex.span, - ~"a sigil (`@`, `~`, or `&`) must be specified \ - when casting to a trait"); + fmt!("can only cast an ~-pointer \ + to a ~-object, not a %s", + ty::ty_sort_str(fcx.tcx(), ty))); } (_, ty::BoxTraitStore) => { @@ -637,14 +625,6 @@ pub fn early_resolve_expr(ex: @ast::expr, ty::ty_sort_str(fcx.tcx(), ty))); } - (_, ty::UniqTraitStore) => { - fcx.ccx.tcx.sess.span_err( - ex.span, - fmt!("can only cast an ~-pointer \ - to a ~-object, not a %s", - ty::ty_sort_str(fcx.tcx(), ty))); - } - (_, ty::RegionTraitStore(_)) => { fcx.ccx.tcx.sess.span_err( ex.span, @@ -661,9 +641,9 @@ pub fn early_resolve_expr(ex: @ast::expr, } } -pub fn resolve_expr(ex: @ast::expr, - &&fcx: @mut FnCtxt, - v: visit::vt<@mut FnCtxt>) { +fn resolve_expr(ex: @ast::expr, + &&fcx: @mut FnCtxt, + v: visit::vt<@mut FnCtxt>) { early_resolve_expr(ex, fcx, false); visit::visit_expr(ex, fcx, v); } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 31301db2a0a1b..3af4cb7f10cb4 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -91,7 +91,7 @@ fn resolve_vtable_map_entry(fcx: @mut FnCtxt, sp: span, id: ast::node_id) { let vtable_map = fcx.ccx.vtable_map; vtable_map.insert(id, r_origins); debug!("writeback::resolve_vtable_map_entry(id=%d, vtables=%?)", - id, r_origins.map(|v| v.to_str(fcx.tcx()))); + id, r_origins.repr(fcx.tcx())); } } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 4fc9e8d19ae1f..247b8eae2a8db 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -24,7 +24,7 @@ use metadata::cstore::{CStore, iter_crate_data}; use metadata::decoder::{dl_def, dl_field, dl_impl}; use middle::resolve::{Impl, MethodInfo}; use middle::ty::{ProvidedMethodSource, ProvidedMethodInfo, bound_copy, get}; -use middle::ty::{lookup_item_type, param_bounds, subst}; +use middle::ty::{lookup_item_type, subst}; use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err}; use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil}; use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr}; @@ -32,13 +32,14 @@ use middle::ty::{ty_rptr, ty_self, ty_struct, ty_trait, ty_tup}; use middle::ty::{ty_type, ty_uint, ty_uniq, ty_bare_fn, ty_closure}; use middle::ty::{ty_opaque_closure_ptr, ty_unboxed_vec}; use middle::ty::{type_is_ty_var}; +use middle::subst::Subst; use middle::ty; use middle::typeck::CrateCtxt; use middle::typeck::infer::combine::Combine; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::{new_infer_ctxt, resolve_ivar}; use middle::typeck::infer::{resolve_nested_tvar, resolve_type}; -use syntax::ast::{crate, def_id, def_mod, def_ty}; +use syntax::ast::{crate, def_id, def_mod, def_trait}; use syntax::ast::{item, item_impl, item_mod, local_crate, method, trait_ref}; use syntax::ast; use syntax::ast_map::node_item; @@ -53,13 +54,13 @@ use syntax::visit::{visit_mod}; use util::ppaux::ty_to_str; use core::result::Ok; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::uint; pub struct UniversalQuantificationResult { monotype: t, type_variables: ~[ty::t], - bounds: @~[param_bounds] + type_param_defs: @~[ty::TypeParameterDef] } pub fn get_base_type(inference_context: @mut InferCtxt, @@ -164,17 +165,17 @@ pub fn method_to_MethodInfo(ast_method: @method) -> @MethodInfo { pub struct CoherenceInfo { // Contains implementations of methods that are inherent to a type. // Methods in these implementations don't need to be exported. - inherent_methods: @mut LinearMap, + inherent_methods: @mut HashMap, // Contains implementations of methods associated with a trait. For these, // the associated trait must be imported at the call site. - extension_methods: @mut LinearMap, + extension_methods: @mut HashMap, } pub fn CoherenceInfo() -> CoherenceInfo { CoherenceInfo { - inherent_methods: @mut LinearMap::new(), - extension_methods: @mut LinearMap::new(), + inherent_methods: @mut HashMap::new(), + extension_methods: @mut HashMap::new(), } } @@ -183,7 +184,7 @@ pub fn CoherenceChecker(crate_context: @mut CrateCtxt) -> CoherenceChecker { crate_context: crate_context, inference_context: new_infer_ctxt(crate_context.tcx), - base_type_def_ids: @mut LinearMap::new(), + base_type_def_ids: @mut HashMap::new(), } } @@ -194,7 +195,7 @@ pub struct CoherenceChecker { // A mapping from implementations to the corresponding base type // definition ID. - base_type_def_ids: @mut LinearMap, + base_type_def_ids: @mut HashMap, } pub impl CoherenceChecker { @@ -269,17 +270,16 @@ pub impl CoherenceChecker { // We only want to generate one Impl structure. When we generate one, // we store it here so that we don't recreate it. let mut implementation_opt = None; - for associated_traits.each |associated_trait| { - let trait_did = - self.trait_ref_to_trait_def_id(*associated_trait); - debug!("(checking implementation) adding impl for trait \ - '%s', item '%s'", - ast_map::node_id_to_str( - self.crate_context.tcx.items, trait_did.node, - self.crate_context.tcx.sess.parse_sess.interner), - *self.crate_context.tcx.sess.str_of(item.ident)); - - self.instantiate_default_methods(item.id, trait_did); + for associated_traits.each |&associated_trait| { + let trait_ref = + ty::node_id_to_trait_ref( + self.crate_context.tcx, + associated_trait.ref_id); + debug!("(checking implementation) adding impl for trait '%s', item '%s'", + trait_ref.repr(self.crate_context.tcx), + *self.crate_context.tcx.sess.str_of(item.ident)); + + self.instantiate_default_methods(item.id, trait_ref); let implementation; if implementation_opt.is_none() { @@ -287,7 +287,7 @@ pub impl CoherenceChecker { implementation_opt = Some(implementation); } - self.add_trait_method(trait_did, implementation_opt.get()); + self.add_trait_method(trait_ref.def_id, implementation_opt.get()); } // Add the implementation to the mapping from implementation to base @@ -325,18 +325,50 @@ pub impl CoherenceChecker { // Creates default method IDs and performs type substitutions for an impl // and trait pair. Then, for each provided method in the trait, inserts a // `ProvidedMethodInfo` instance into the `provided_method_sources` map. - fn instantiate_default_methods(&self, impl_id: ast::node_id, - trait_did: ast::def_id) { - for self.each_provided_trait_method(trait_did) |trait_method| { + fn instantiate_default_methods(&self, + impl_id: ast::node_id, + trait_ref: &ty::TraitRef) { + let tcx = self.crate_context.tcx; + debug!("instantiate_default_methods(impl_id=%?, trait_ref=%s)", + impl_id, trait_ref.repr(tcx)); + + let impl_poly_type = ty::lookup_item_type(tcx, local_def(impl_id)); + + for self.each_provided_trait_method(trait_ref.def_id) |trait_method| { // Synthesize an ID. - let tcx = self.crate_context.tcx; let new_id = parse::next_node_id(tcx.sess.parse_sess); let new_did = local_def(new_id); - // XXX: Perform substitutions. - let new_polytype = ty::lookup_item_type(tcx, - trait_method.def_id); + debug!("new_did=%? trait_method=%s", new_did, trait_method.repr(tcx)); + + // Create substitutions for the various trait parameters. + let new_method_ty = + @subst_receiver_types_in_method_ty( + tcx, + impl_id, + trait_ref, + new_did, + trait_method); + + debug!("new_method_ty=%s", new_method_ty.repr(tcx)); + + // construct the polytype for the method based on the method_ty + let new_generics = ty::Generics { + type_param_defs: + @vec::append( + copy *impl_poly_type.generics.type_param_defs, + *new_method_ty.generics.type_param_defs), + region_param: + impl_poly_type.generics.region_param + }; + let new_polytype = ty::ty_param_bounds_and_ty { + generics: new_generics, + ty: ty::mk_bare_fn(tcx, copy new_method_ty.fty) + }; + debug!("new_polytype=%s", new_polytype.repr(tcx)); + tcx.tcache.insert(new_did, new_polytype); + tcx.methods.insert(new_did, new_method_ty); // Pair the new synthesized ID up with the // ID of the method. @@ -352,7 +384,7 @@ pub impl CoherenceChecker { @ProvidedMethodInfo { method_info: @MethodInfo { did: new_did, - n_tps: trait_method.tps.len(), + n_tps: trait_method.generics.type_param_defs.len(), ident: trait_method.ident, self_type: trait_method.self_ty }, @@ -471,7 +503,7 @@ pub impl CoherenceChecker { ty_to_str(self.crate_context.tcx, self_t)); match self.crate_context.tcx.trait_impls.find(&trait_t) { None => { - let m = @mut LinearMap::new(); + let m = @mut HashMap::new(); m.insert(self_t, the_impl); self.crate_context.tcx.trait_impls.insert(trait_t, m); } @@ -498,16 +530,16 @@ pub impl CoherenceChecker { fn each_provided_trait_method(&self, trait_did: ast::def_id, - f: &fn(x: &ty::method) -> bool) { + f: &fn(x: @ty::method) -> bool) { // Make a list of all the names of the provided methods. // XXX: This is horrible. - let mut provided_method_idents = LinearSet::new(); + let mut provided_method_idents = HashSet::new(); let tcx = self.crate_context.tcx; for ty::provided_trait_methods(tcx, trait_did).each |ident| { provided_method_idents.insert(*ident); } - for ty::trait_methods(tcx, trait_did).each |method| { + for ty::trait_methods(tcx, trait_did).each |&method| { if provided_method_idents.contains(&method.ident) { if !f(method) { break; @@ -536,12 +568,11 @@ pub impl CoherenceChecker { -> UniversalQuantificationResult { // NDM--this span is bogus. let self_region = - polytype.region_param.map( + polytype.generics.region_param.map( |_r| self.inference_context.next_region_var_nb(dummy_sp())); - let bounds_count = polytype.bounds.len(); - let type_parameters = - self.inference_context.next_ty_vars(bounds_count); + let bounds_count = polytype.generics.type_param_defs.len(); + let type_parameters = self.inference_context.next_ty_vars(bounds_count); let substitutions = substs { self_r: self_region, @@ -559,7 +590,7 @@ pub impl CoherenceChecker { UniversalQuantificationResult { monotype: monotype, type_variables: type_parameters, - bounds: polytype.bounds + type_param_defs: polytype.generics.type_param_defs } } @@ -576,13 +607,13 @@ pub impl CoherenceChecker { // Check to ensure that each parameter binding respected its // kind bounds. for [ a, b ].each |result| { - for vec::each2(result.type_variables, *result.bounds) - |ty_var, bounds| { + for vec::each2(result.type_variables, *result.type_param_defs) + |ty_var, type_param_def| { match resolve_type(self.inference_context, *ty_var, resolve_nested_tvar) { Ok(resolved_ty) => { - for bounds.each |bound| { + for type_param_def.bounds.each |bound| { match *bound { bound_copy => { if !ty::type_is_copyable( @@ -705,7 +736,7 @@ pub impl CoherenceChecker { let tcx = self.crate_context.tcx; - let mut provided_names = LinearSet::new(); + let mut provided_names = HashSet::new(); // Implemented methods for uint::range(0, all_methods.len()) |i| { provided_names.insert(all_methods[i].ident); @@ -812,7 +843,7 @@ pub impl CoherenceChecker { // External crate handling - fn add_impls_for_module(&self, impls_seen: &mut LinearSet, + fn add_impls_for_module(&self, impls_seen: &mut HashSet, crate_store: @mut CStore, module_def_id: def_id) { let implementations = get_impls_for_mod(crate_store, @@ -858,17 +889,8 @@ pub impl CoherenceChecker { } // Record all the trait methods. - for associated_traits.each |trait_type| { - match get(*trait_type).sty { - ty_trait(trait_id, _, _) => { - self.add_trait_method(trait_id, *implementation); - } - _ => { - self.crate_context.tcx.sess.bug(~"trait type \ - returned is not a \ - trait"); - } - } + for associated_traits.each |trait_ref| { + self.add_trait_method(trait_ref.def_id, *implementation); } // Add the implementation to the mapping from @@ -917,7 +939,7 @@ pub impl CoherenceChecker { @ProvidedMethodInfo { method_info: @MethodInfo { did: new_did, - n_tps: trait_method_info.ty.tps.len(), + n_tps: trait_method_info.ty.generics.type_param_defs.len(), ident: trait_method_info.ty.ident, self_type: trait_method_info.ty.self_ty }, @@ -931,7 +953,7 @@ pub impl CoherenceChecker { // Adds implementations and traits from external crates to the coherence // info. fn add_external_crates(&self) { - let mut impls_seen = LinearSet::new(); + let mut impls_seen = HashSet::new(); let crate_store = self.crate_context.tcx.sess.cstore; do iter_crate_data(crate_store) |crate_number, _crate_metadata| { @@ -947,16 +969,8 @@ pub impl CoherenceChecker { crate_store, def_id); } - dl_def(def_ty(def_id)) => { - let tcx = self.crate_context.tcx; - let polytype = csearch::get_type(tcx, def_id); - match ty::get(polytype.ty).sty { - ty::ty_trait(*) => { - self.add_default_methods_for_external_trait( - def_id); - } - _ => {} - } + dl_def(def_trait(def_id)) => { + self.add_default_methods_for_external_trait(def_id); } dl_def(_) | dl_impl(_) | dl_field => { // Skip this. @@ -1021,6 +1035,70 @@ pub impl CoherenceChecker { } } +fn subst_receiver_types_in_method_ty( + tcx: ty::ctxt, + impl_id: ast::node_id, + trait_ref: &ty::TraitRef, + new_def_id: ast::def_id, + method: &ty::method) -> ty::method +{ + /*! + * Substitutes the values for the receiver's type parameters + * that are found in method, leaving the method's type parameters + * intact. This is in fact a mildly complex operation, + * largely because of the hokey way that we concatenate the + * receiver and method generics. + */ + + // determine how many type parameters were declared on the impl + let num_impl_type_parameters = { + let impl_polytype = ty::lookup_item_type(tcx, local_def(impl_id)); + impl_polytype.generics.type_param_defs.len() + }; + + // determine how many type parameters appear on the trait + let num_trait_type_parameters = trait_ref.substs.tps.len(); + + // the current method type has the type parameters from the trait + method + let num_method_type_parameters = + num_trait_type_parameters + method.generics.type_param_defs.len(); + + // the new method type will have the type parameters from the impl + method + let combined_tps = vec::from_fn(num_method_type_parameters, |i| { + if i < num_trait_type_parameters { + // replace type parameters that come from trait with new value + trait_ref.substs.tps[i] + } else { + // replace type parameters that belong to method with another + // type parameter, this time with the index adjusted + let method_index = i - num_trait_type_parameters; + let type_param_def = &method.generics.type_param_defs[method_index]; + let new_index = num_impl_type_parameters + method_index; + ty::mk_param(tcx, new_index, type_param_def.def_id) + } + }); + + let combined_substs = ty::substs { + self_r: trait_ref.substs.self_r, + self_ty: trait_ref.substs.self_ty, + tps: combined_tps + }; + + ty::method { + ident: method.ident, + + // method tps cannot appear in the self_ty, so use `substs` from trait ref + transformed_self_ty: method.transformed_self_ty.subst(tcx, &trait_ref.substs), + + // method types *can* appear in the generic bounds or the fty + generics: method.generics.subst(tcx, &combined_substs), + fty: method.fty.subst(tcx, &combined_substs), + self_ty: method.self_ty, + vis: method.vis, + def_id: new_def_id + } +} + pub fn check_coherence(crate_context: @mut CrateCtxt, crate: @crate) { let coherence_checker = @CoherenceChecker(crate_context); coherence_checker.check_coherence(crate); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index f1d743e79e58a..59ea8ea039e1f 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -33,17 +33,16 @@ are represented as `ty_param()` instances. use core::prelude::*; use metadata::csearch; -use middle::ty::InstantiatedTraitRef; -use middle::ty::{substs, ty_param_bounds_and_ty, ty_param_substs_and_ty}; +use middle::ty::{substs, ty_param_bounds_and_ty}; use middle::ty; +use middle::subst::Subst; use middle::typeck::astconv::{AstConv, ty_of_arg}; use middle::typeck::astconv::{ast_ty_to_ty}; use middle::typeck::astconv; use middle::typeck::infer; use middle::typeck::rscope::*; use middle::typeck::rscope; -use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx, - write_tpt_to_tcx}; +use middle::typeck::{CrateCtxt, lookup_def_tcx, no_params, write_ty_to_tcx}; use util::common::{indenter, pluralize}; use util::ppaux; @@ -53,11 +52,10 @@ use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods}; -use syntax::ast_util::{trait_method_to_ty_method}; use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; -use syntax::print::pprust::path_to_str; +use syntax::print::pprust::{path_to_str, self_ty_to_str}; use syntax::visit; use syntax::opt_vec::OptVec; use syntax::opt_vec; @@ -84,12 +82,10 @@ pub fn collect_item_types(ccx: @mut CrateCtxt, crate: @ast::crate) { match intrinsic_item.node { ast::item_trait(*) => { - let ty = ty::mk_trait(ccx.tcx, - def_id, - substs, - ty::BareTraitStore); - ccx.tcx.intrinsic_defs.insert - (intrinsic_item.ident, (def_id, ty)); + let tref = @ty::TraitRef {def_id: def_id, + substs: substs}; + ccx.tcx.intrinsic_traits.insert + (intrinsic_item.ident, tref); } ast::item_enum(*) => { @@ -153,6 +149,10 @@ impl AstConv for CrateCtxt { } } + fn get_trait_def(&self, id: ast::def_id) -> @ty::TraitDef { + get_trait_def(self, id) + } + fn ty_infer(&self, span: span) -> ty::t { self.tcx.sess.span_bug(span, ~"found `ty_infer` in unexpected place"); @@ -187,8 +187,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, ast::struct_variant_kind(struct_def) => { let tpt = ty_param_bounds_and_ty { - bounds: ty_param_bounds(ccx, generics), - region_param: rp, + generics: ty_generics(ccx, rp, generics, 0), ty: enum_ty }; @@ -209,8 +208,7 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, None => {} Some(result_ty) => { let tpt = ty_param_bounds_and_ty { - bounds: ty_param_bounds(ccx, generics), - region_param: rp, + generics: ty_generics(ccx, rp, generics, 0), ty: result_ty }; tcx.tcache.insert(local_def(variant.node.id), tpt); @@ -221,94 +219,184 @@ pub fn get_enum_variant_types(ccx: &CrateCtxt, } pub fn ensure_trait_methods(ccx: &CrateCtxt, - id: ast::node_id, - trait_ty: ty::t) { - fn store_methods(ccx: &CrateCtxt, - id: ast::node_id, - stuff: &[T], - f: &fn(v: &T) -> ty::method) { - ty::store_trait_methods(ccx.tcx, id, @stuff.map(f)); + trait_id: ast::node_id) +{ + let tcx = ccx.tcx; + let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|&x| *x); + match *tcx.items.get(&trait_id) { + ast_map::node_item(@ast::item { + node: ast::item_trait(ref generics, _, ref ms), + _ + }, _) => { + let trait_ty_generics = ty_generics(ccx, region_paramd, generics, 0); + + // For each method, construct a suitable ty::method and + // store it into the `tcx.methods` table: + for ms.each |m| { + let ty_method = @match m { + &ast::required(ref m) => { + ty_method_of_trait_method( + ccx, trait_id, region_paramd, generics, + &m.id, &m.ident, &m.self_ty, + &m.generics, &m.purity, &m.decl) + } + + &ast::provided(ref m) => { + ty_method_of_trait_method( + ccx, trait_id, region_paramd, generics, + &m.id, &m.ident, &m.self_ty, + &m.generics, &m.purity, &m.decl) + } + }; + + if ty_method.self_ty == ast::sty_static { + make_static_method_ty(ccx, trait_id, ty_method, + &trait_ty_generics); + } + + tcx.methods.insert(ty_method.def_id, ty_method); + } + + // Add an entry mapping + let method_def_ids = @ms.map(|m| { + match m { + &ast::required(ref ty_method) => local_def(ty_method.id), + &ast::provided(ref method) => local_def(method.id) + } + }); + + let trait_def_id = local_def(trait_id); + tcx.trait_method_def_ids.insert(trait_def_id, method_def_ids); + } + _ => { /* Ignore things that aren't traits */ } } fn make_static_method_ty(ccx: &CrateCtxt, - am: &ast::ty_method, - rp: Option, - m: ty::method, - // Take this as an argument b/c we may check - // the impl before the trait. - trait_ty: ty::t, - trait_bounds: @~[ty::param_bounds]) { - // We need to create a typaram that replaces self. This param goes - // *in between* the typarams from the trait and those from the - // method (since its bound can depend on the trait? or - // something like that). + trait_id: ast::node_id, + m: &ty::method, + trait_ty_generics: &ty::Generics) { + // If declaration is + // + // trait { + // fn foo(...) -> Self; + // } + // + // and we will create a function like + // + // fn foo(...) -> D' {} + // + // Note that `Self` is replaced with an explicit type + // parameter D' that is sandwiched in between the trait params + // and the method params, and thus the indices of the method + // type parameters are offset by 1 (that is, the method + // parameters are mapped from D, E, F to E', F', and G'). The + // choice of this ordering is somewhat arbitrary. + // + // Also, this system is rather a hack that should be replaced + // with a more uniform treatment of Self (which is partly + // underway). // build up a subst that shifts all of the parameters over // by one and substitute in a new type param for self + let tcx = ccx.tcx; + let dummy_defid = ast::def_id {crate: 0, node: 0}; - let non_shifted_trait_tps = do vec::from_fn(trait_bounds.len()) |i| { - ty::mk_param(ccx.tcx, i, dummy_defid) + // Represents [A',B',C'] + let num_trait_bounds = trait_ty_generics.type_param_defs.len(); + let non_shifted_trait_tps = do vec::from_fn(num_trait_bounds) |i| { + ty::mk_param(tcx, i, dummy_defid) }; - let self_param = ty::mk_param(ccx.tcx, trait_bounds.len(), + + // Represents [D'] + let self_param = ty::mk_param(tcx, num_trait_bounds, dummy_defid); - let shifted_method_tps = do vec::from_fn(m.tps.len()) |i| { - ty::mk_param(ccx.tcx, i + 1, dummy_defid) + + // Represents [E',F',G'] + let num_method_bounds = m.generics.type_param_defs.len(); + let shifted_method_tps = do vec::from_fn(num_method_bounds) |i| { + ty::mk_param(tcx, i + 1, dummy_defid) }; + // build up the substitution from + // A,B,C => A',B',C' + // Self => D' + // D,E,F => E',F',G' let substs = substs { self_r: None, self_ty: Some(self_param), tps: non_shifted_trait_tps + shifted_method_tps }; - let ty = ty::subst(ccx.tcx, + + // create the type of `foo`, applying the substitution above + let ty = ty::subst(tcx, &substs, - ty::mk_bare_fn(ccx.tcx, copy m.fty)); - let bounds = @(*trait_bounds + ~[@~[ty::bound_trait(trait_ty)]] - + *m.tps); - ccx.tcx.tcache.insert(local_def(am.id), - ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, - ty: ty}); - } + ty::mk_bare_fn(tcx, copy m.fty)); + + // create the type parameter definitions for `foo`, applying + // the substitution to any traits that appear in their bounds. + + // add in the type parameters from the trait + let mut new_type_param_defs = ~[]; + let substd_type_param_defs = + trait_ty_generics.type_param_defs.subst(tcx, &substs); + new_type_param_defs.push_all(*substd_type_param_defs); + + // add in the "self" type parameter + let self_trait_def = get_trait_def(ccx, local_def(trait_id)); + let self_trait_ref = @self_trait_def.trait_ref.subst(tcx, &substs); + new_type_param_defs.push(ty::TypeParameterDef { + def_id: dummy_defid, + bounds: @~[ty::bound_trait(self_trait_ref)] + }); + // add in the type parameters from the method + let substd_type_param_defs = m.generics.type_param_defs.subst(tcx, &substs); + new_type_param_defs.push_all(*substd_type_param_defs); - let tcx = ccx.tcx; - let region_paramd = tcx.region_paramd_items.find(&id).map_consume(|x| *x); - match *tcx.items.get(&id) { - ast_map::node_item(@ast::item { - node: ast::item_trait(ref generics, _, ref ms), - _ - }, _) => { - store_methods::(ccx, id, *ms, |m| { - let def_id; - match *m { - ast::required(ref ty_method) => { - def_id = local_def((*ty_method).id) - } - ast::provided(method) => def_id = local_def(method.id) - } + debug!("static method %s type_param_defs=%s substs=%s", + m.def_id.repr(tcx), + new_type_param_defs.repr(tcx), + substs.repr(tcx)); - let trait_bounds = ty_param_bounds(ccx, generics); - let ty_m = trait_method_to_ty_method(m); - let method_ty = ty_of_ty_method( - ccx, - &ty_m, - region_paramd, - def_id, - generics - ); - if ty_m.self_ty.node == ast::sty_static { - make_static_method_ty(ccx, &ty_m, region_paramd, - method_ty, trait_ty, - trait_bounds); - } - method_ty - }); - } - _ => { /* Ignore things that aren't traits */ } + tcx.tcache.insert(m.def_id, + ty_param_bounds_and_ty { + generics: ty::Generics { + type_param_defs: @new_type_param_defs, + region_param: trait_ty_generics.region_param + }, + ty: ty + }); + } + + fn ty_method_of_trait_method(self: &CrateCtxt, + trait_id: ast::node_id, + trait_rp: Option, + trait_generics: &ast::Generics, + m_id: &ast::node_id, + m_ident: &ast::ident, + m_self_ty: &ast::self_ty, + m_generics: &ast::Generics, + m_purity: &ast::purity, + m_decl: &ast::fn_decl) -> ty::method + { + let trait_self_ty = ty::mk_self(self.tcx, local_def(trait_id)); + let rscope = MethodRscope::new(m_self_ty.node, trait_rp, trait_generics); + let (transformed_self_ty, fty) = + astconv::ty_of_method(self, &rscope, *m_purity, &m_generics.lifetimes, + trait_self_ty, *m_self_ty, m_decl); + let num_trait_type_params = trait_generics.ty_params.len(); + ty::method { + ident: *m_ident, + generics: ty_generics(self, None, m_generics, num_trait_type_params), + transformed_self_ty: transformed_self_ty, + fty: fty, + self_ty: m_self_ty.node, + // assume public, because this is only invoked on trait methods + vis: ast::public, + def_id: local_def(*m_id) + } } } @@ -316,25 +404,30 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, id: ast::node_id, sp: codemap::span, rp: Option, - trait_refs: &[@ast::trait_ref], - generics: &ast::Generics) { + ast_trait_refs: &[@ast::trait_ref], + generics: &ast::Generics) +{ let tcx = ccx.tcx; if tcx.supertraits.contains_key(&local_def(id)) { return; } - let mut instantiated = ~[]; - for trait_refs.each |trait_ref| { - let (did, tpt) = instantiate_trait_ref(ccx, *trait_ref, rp, generics); - if instantiated.any(|other_trait: &InstantiatedTraitRef| - { other_trait.def_id == did }) { + let self_ty = ty::mk_self(ccx.tcx, local_def(id)); + let mut ty_trait_refs: ~[@ty::TraitRef] = ~[]; + for ast_trait_refs.each |&ast_trait_ref| { + let trait_ref = instantiate_trait_ref(ccx, ast_trait_ref, rp, + generics, self_ty); + + // FIXME(#5527) Could have same trait multiple times + if ty_trait_refs.any(|other_trait| other_trait.def_id == trait_ref.def_id) { // This means a trait inherited from the same supertrait more // than once. tcx.sess.span_err(sp, ~"Duplicate supertrait in trait \ declaration"); - return; + break; + } else { + ty_trait_refs.push(trait_ref); } - instantiated.push(InstantiatedTraitRef { def_id: did, tpt: tpt }); } - tcx.supertraits.insert(local_def(id), @instantiated); + tcx.supertraits.insert(local_def(id), @ty_trait_refs); } /** @@ -360,43 +453,50 @@ pub fn compare_impl_method(tcx: ty::ctxt, let impl_m = &cm.mty; - // FIXME(#2687)---this check is too strict. For example, a trait - // method with self type `&self` or `&mut self` should be - // implementable by an `&const self` method (the impl assumes less - // than the trait provides). - if impl_m.self_ty != trait_m.self_ty { - if impl_m.self_ty == ast::sty_static { - // Needs to be a fatal error because otherwise, - // method::transform_self_type_for_method ICEs - tcx.sess.span_fatal(cm.span, - fmt!("method `%s` is declared as \ - static in its impl, but not in \ - its trait", *tcx.sess.str_of(impl_m.ident))); - } - else if trait_m.self_ty == ast::sty_static { - tcx.sess.span_fatal(cm.span, - fmt!("method `%s` is declared as \ - static in its trait, but not in \ - its impl", *tcx.sess.str_of(impl_m.ident))); + // Try to give more informative error messages about self typing + // mismatches. Note that any mismatch will also be detected + // below, where we construct a canonical function type that + // includes the self parameter as a normal parameter. It's just + // that the error messages you get out of this code are a bit more + // inscrutable, particularly for cases where one method has no + // self. + match (&trait_m.self_ty, &impl_m.self_ty) { + (&ast::sty_static, &ast::sty_static) => {} + (&ast::sty_static, _) => { + tcx.sess.span_err( + cm.span, + fmt!("method `%s` has a `%s` declaration in the impl, \ + but not in the trait", + *tcx.sess.str_of(trait_m.ident), + self_ty_to_str(impl_m.self_ty, tcx.sess.intr()))); + return; } - else { + (_, &ast::sty_static) => { tcx.sess.span_err( cm.span, - fmt!("method `%s`'s self type does \ - not match the trait method's \ - self type", *tcx.sess.str_of(impl_m.ident))); + fmt!("method `%s` has a `%s` declaration in the trait, \ + but not in the impl", + *tcx.sess.str_of(trait_m.ident), + self_ty_to_str(trait_m.self_ty, tcx.sess.intr()))); + return; + } + _ => { + // Let the type checker catch other errors below } } - if impl_m.tps.len() != trait_m.tps.len() { + let num_impl_m_type_params = impl_m.generics.type_param_defs.len(); + let num_trait_m_type_params = trait_m.generics.type_param_defs.len(); + if num_impl_m_type_params != num_trait_m_type_params { tcx.sess.span_err( cm.span, fmt!("method `%s` has %u type %s, but its trait \ declaration has %u type %s", - *tcx.sess.str_of(trait_m.ident), impl_m.tps.len(), - pluralize(impl_m.tps.len(), ~"parameter"), - trait_m.tps.len(), - pluralize(trait_m.tps.len(), ~"parameter"))); + *tcx.sess.str_of(trait_m.ident), + num_impl_m_type_params, + pluralize(num_impl_m_type_params, ~"parameter"), + num_trait_m_type_params, + pluralize(num_trait_m_type_params, ~"parameter"))); return; } @@ -414,23 +514,23 @@ pub fn compare_impl_method(tcx: ty::ctxt, // FIXME(#2687)---we should be checking that the bounds of the // trait imply the bounds of the subtype, but it appears // we are...not checking this. - for trait_m.tps.eachi() |i, trait_param_bounds| { + for trait_m.generics.type_param_defs.eachi |i, trait_param_def| { // For each of the corresponding impl ty param's bounds... - let impl_param_bounds = impl_m.tps[i]; + let impl_param_def = &impl_m.generics.type_param_defs[i]; // Make sure the bounds lists have the same length // Would be nice to use the ty param names in the error message, // but we don't have easy access to them here - if impl_param_bounds.len() != trait_param_bounds.len() { + if impl_param_def.bounds.len() != trait_param_def.bounds.len() { tcx.sess.span_err( cm.span, fmt!("in method `%s`, \ type parameter %u has %u %s, but the same type \ parameter in its trait declaration has %u %s", *tcx.sess.str_of(trait_m.ident), - i, impl_param_bounds.len(), - pluralize(impl_param_bounds.len(), ~"bound"), - trait_param_bounds.len(), - pluralize(trait_param_bounds.len(), ~"bound"))); + i, impl_param_def.bounds.len(), + pluralize(impl_param_def.bounds.len(), ~"bound"), + trait_param_def.bounds.len(), + pluralize(trait_param_def.bounds.len(), ~"bound"))); return; } } @@ -439,9 +539,55 @@ pub fn compare_impl_method(tcx: ty::ctxt, // a free region. So, for example, if the impl type is // "&'self str", then this would replace the self type with a free // region `self`. - let dummy_self_r = ty::re_free(cm.body_id, ty::br_self); + let dummy_self_r = ty::re_free(ty::FreeRegion {scope_id: cm.body_id, + bound_region: ty::br_self}); let self_ty = replace_bound_self(tcx, self_ty, dummy_self_r); + // We are going to create a synthetic fn type that includes + // both the method's self argument and its normal arguments. + // So a method like `fn(&self, a: uint)` would be converted + // into a function `fn(self: &T, a: uint)`. + let mut trait_fn_args = ~[]; + let mut impl_fn_args = ~[]; + + // For both the trait and the impl, create an argument to + // represent the self argument (unless this is a static method). + // This argument will have the *transformed* self type. + for trait_m.transformed_self_ty.each |&t| { + trait_fn_args.push(ty::arg {mode: ast::expl(ast::by_copy), ty: t}); + } + for impl_m.transformed_self_ty.each |&t| { + impl_fn_args.push(ty::arg {mode: ast::expl(ast::by_copy), ty: t}); + } + + // Add in the normal arguments. + trait_fn_args.push_all(trait_m.fty.sig.inputs); + impl_fn_args.push_all(impl_m.fty.sig.inputs); + + // Create a bare fn type for trait/impl that includes self argument + let trait_fty = + ty::mk_bare_fn( + tcx, + ty::BareFnTy {purity: trait_m.fty.purity, + abis: trait_m.fty.abis, + sig: ty::FnSig { + bound_lifetime_names: + copy trait_m.fty.sig.bound_lifetime_names, + inputs: trait_fn_args, + output: trait_m.fty.sig.output + }}); + let impl_fty = + ty::mk_bare_fn( + tcx, + ty::BareFnTy {purity: impl_m.fty.purity, + abis: impl_m.fty.abis, + sig: ty::FnSig { + bound_lifetime_names: + copy impl_m.fty.sig.bound_lifetime_names, + inputs: impl_fn_args, + output: impl_m.fty.sig.output + }}); + // Perform substitutions so that the trait/impl methods are expressed // in terms of the same set of type/region parameters: // - replace trait type parameters with those from `trait_substs`, @@ -450,16 +596,15 @@ pub fn compare_impl_method(tcx: ty::ctxt, // that correspond to the parameters we will find on the impl // - replace self region with a fresh, dummy region let impl_fty = { - let impl_fty = ty::mk_bare_fn(tcx, copy impl_m.fty); debug!("impl_fty (pre-subst): %s", ppaux::ty_to_str(tcx, impl_fty)); replace_bound_self(tcx, impl_fty, dummy_self_r) }; - debug!("impl_fty: %s", ppaux::ty_to_str(tcx, impl_fty)); + debug!("impl_fty (post-subst): %s", ppaux::ty_to_str(tcx, impl_fty)); let trait_fty = { - let dummy_tps = do vec::from_fn((*trait_m.tps).len()) |i| { - // hack: we don't know the def id of the impl tp, but it - // is not important for unification - ty::mk_param(tcx, i + impl_tps, ast::def_id {crate: 0, node: 0}) + let num_trait_m_type_params = trait_m.generics.type_param_defs.len(); + let dummy_tps = do vec::from_fn(num_trait_m_type_params) |i| { + ty::mk_param(tcx, i + impl_tps, + impl_m.generics.type_param_defs[i].def_id) }; let trait_tps = trait_substs.tps.map( |t| replace_bound_self(tcx, *t, dummy_self_r)); @@ -468,10 +613,11 @@ pub fn compare_impl_method(tcx: ty::ctxt, self_ty: Some(self_ty), tps: vec::append(trait_tps, dummy_tps) }; - let trait_fty = ty::mk_bare_fn(tcx, copy trait_m.fty); - debug!("trait_fty (pre-subst): %s", ppaux::ty_to_str(tcx, trait_fty)); + debug!("trait_fty (pre-subst): %s substs=%s", + trait_fty.repr(tcx), substs.repr(tcx)); ty::subst(tcx, &substs, trait_fty) }; + debug!("trait_fty (post-subst): %s", trait_fty.repr(tcx)); let infcx = infer::new_infer_ctxt(tcx); match infer::mk_subty(infcx, false, cm.span, impl_fty, trait_fty) { @@ -501,40 +647,27 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, rp: Option, selfty: ty::t, a_trait_ty: @ast::trait_ref, - impl_ms: &[ConvertedMethod]) { - + impl_ms: &[ConvertedMethod]) +{ let tcx = ccx.tcx; - let (did, tpt) = instantiate_trait_ref(ccx, a_trait_ty, rp, generics); - - if did.crate == ast::local_crate { - // NB: This is subtle. We need to do this on the type of the trait - // item *itself*, not on the type that includes the parameter - // substitutions provided by the programmer at this particular - // trait ref. Otherwise, we will potentially overwrite the types of - // the methods within the trait with bogus results. (See issue #3903.) - - match tcx.items.find(&did.node) { - Some(&ast_map::node_item(item, _)) => { - let tpt = ty_of_item(ccx, item); - ensure_trait_methods(ccx, did.node, tpt.ty); - } - _ => { - tcx.sess.bug(~"trait ref didn't resolve to trait"); - } - } + let trait_ref = instantiate_trait_ref(ccx, a_trait_ty, rp, + generics, selfty); + + if trait_ref.def_id.crate == ast::local_crate { + ensure_trait_methods(ccx, trait_ref.def_id.node); } // Check that each method we impl is a method on the trait // Trait methods we don't implement must be default methods, but if not // we'll catch it in coherence - let trait_ms = ty::trait_methods(tcx, did); + let trait_ms = ty::trait_methods(tcx, trait_ref.def_id); for impl_ms.each |impl_m| { match trait_ms.find(|trait_m| trait_m.ident == impl_m.mty.ident) { - Some(ref trait_m) => { + Some(trait_m) => { let num_impl_tps = generics.ty_params.len(); compare_impl_method( ccx.tcx, num_impl_tps, impl_m, trait_m, - &tpt.substs, selfty); + &trait_ref.substs, selfty); } None => { // This method is not part of the trait @@ -550,7 +683,7 @@ pub fn check_methods_against_trait(ccx: &CrateCtxt, pub fn convert_field(ccx: &CrateCtxt, rp: Option, - bounds: @~[ty::param_bounds], + type_param_defs: @~[ty::TypeParameterDef], v: @ast::struct_field, generics: &ast::Generics) { let region_parameterization = @@ -560,14 +693,16 @@ pub fn convert_field(ccx: &CrateCtxt, /* add the field to the tcache */ ccx.tcx.tcache.insert(local_def(v.node.id), ty::ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, + generics: ty::Generics { + type_param_defs: type_param_defs, + region_param: rp + }, ty: tt }); } pub struct ConvertedMethod { - mty: ty::method, + mty: @ty::method, id: ast::node_id, span: span, body_id: ast::node_id @@ -575,29 +710,78 @@ pub struct ConvertedMethod { pub fn convert_methods(ccx: &CrateCtxt, ms: &[@ast::method], - rp: Option, - rcvr_bounds: @~[ty::param_bounds], - rcvr_generics: &ast::Generics) - -> ~[ConvertedMethod] { - + untransformed_rcvr_ty: ty::t, + rcvr_ty_generics: &ty::Generics, + rcvr_ast_generics: &ast::Generics, + rcvr_visibility: ast::visibility) + -> ~[ConvertedMethod] +{ let tcx = ccx.tcx; - do vec::map(ms) |m| { - let bounds = ty_param_bounds(ccx, &m.generics); - let mty = ty_of_method(ccx, *m, rp, rcvr_generics, &m.generics); - let fty = ty::mk_bare_fn(tcx, copy mty.fty); + return vec::map(ms, |m| { + let num_rcvr_ty_params = rcvr_ty_generics.type_param_defs.len(); + let m_ty_generics = + ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics, + num_rcvr_ty_params); + let mty = + @ty_of_method(ccx, *m, rcvr_ty_generics.region_param, + untransformed_rcvr_ty, + rcvr_ast_generics, rcvr_visibility, + &m.generics); + let fty = + ty::mk_bare_fn(tcx, copy mty.fty); tcx.tcache.insert( local_def(m.id), // n.b.: the type of a method is parameterized by both // the tps on the receiver and those on the method itself ty_param_bounds_and_ty { - bounds: @(vec::append(/*bad*/copy *rcvr_bounds, *bounds)), - region_param: rp, + generics: ty::Generics { + type_param_defs: @vec::append( + copy *rcvr_ty_generics.type_param_defs, + *m_ty_generics.type_param_defs), + region_param: rcvr_ty_generics.region_param + }, ty: fty }); write_ty_to_tcx(tcx, m.id, fty); + tcx.methods.insert(mty.def_id, mty); ConvertedMethod {mty: mty, id: m.id, span: m.span, body_id: m.body.node.id} + }); + + fn ty_of_method(ccx: &CrateCtxt, + m: @ast::method, + rp: Option, + untransformed_rcvr_ty: ty::t, + rcvr_generics: &ast::Generics, + rcvr_visibility: ast::visibility, + method_generics: &ast::Generics) -> ty::method + { + let rscope = MethodRscope::new(m.self_ty.node, + rp, + rcvr_generics); + let (transformed_self_ty, fty) = + astconv::ty_of_method(ccx, &rscope, m.purity, + &method_generics.lifetimes, + untransformed_rcvr_ty, + m.self_ty, &m.decl); + + // if the method specifies a visibility, use that, otherwise + // inherit the visibility from the impl (so `foo` in `pub impl + // { fn foo(); }` is public, but private in `priv impl { fn + // foo(); }`). + let method_vis = m.vis.inherit_from(rcvr_visibility); + + let num_rcvr_type_params = rcvr_generics.ty_params.len(); + ty::method { + ident: m.ident, + generics: ty_generics(ccx, None, &m.generics, num_rcvr_type_params), + transformed_self_ty: transformed_self_ty, + fty: fty, + self_ty: m.self_ty.node, + vis: method_vis, + def_id: local_def(m.id) + } } } @@ -633,36 +817,50 @@ pub fn convert(ccx: &CrateCtxt, it: @ast::item) { generics, rp); } - ast::item_impl(ref generics, trait_ref, selfty, ref ms) => { - let i_bounds = ty_param_bounds(ccx, generics); + ast::item_impl(ref generics, opt_trait_ref, selfty, ref ms) => { + let i_ty_generics = ty_generics(ccx, rp, generics, 0); let region_parameterization = RegionParameterization::from_variance_and_generics(rp, generics); let selfty = ccx.to_ty(&type_rscope(region_parameterization), selfty); write_ty_to_tcx(tcx, it.id, selfty); tcx.tcache.insert(local_def(it.id), ty_param_bounds_and_ty { - bounds: i_bounds, - region_param: rp, - ty: selfty}); + generics: i_ty_generics, + ty: selfty}); + + // If there is a trait reference, treat the methods as always public. + // This is to work around some incorrect behavior in privacy checking: + // when the method belongs to a trait, it should acquire the privacy + // from the trait, not the impl. Forcing the visibility to be public + // makes things sorta work. + let parent_visibility = if opt_trait_ref.is_some() { + ast::public + } else { + it.vis + }; - // XXX: Bad copy of `ms` below. - let cms = convert_methods(ccx, *ms, rp, i_bounds, generics); - for trait_ref.each |t| { + let cms = convert_methods(ccx, *ms, selfty, + &i_ty_generics, generics, + parent_visibility); + for opt_trait_ref.each |t| { check_methods_against_trait(ccx, generics, rp, selfty, *t, cms); } } ast::item_trait(ref generics, ref supertraits, ref trait_methods) => { - let tpt = ty_of_item(ccx, it); - debug!("item_trait(it.id=%d, tpt.ty=%s)", - it.id, ppaux::ty_to_str(tcx, tpt.ty)); - write_ty_to_tcx(tcx, it.id, tpt.ty); - ensure_trait_methods(ccx, it.id, tpt.ty); - ensure_supertraits(ccx, it.id, it.span, rp, *supertraits, generics); - - let (_, provided_methods) = - split_trait_methods(*trait_methods); - let (bounds, _) = mk_substs(ccx, generics, rp); - let _ = convert_methods(ccx, provided_methods, rp, bounds, generics); + let trait_def = trait_def_of_item(ccx, it); + tcx.trait_defs.insert(local_def(it.id), trait_def); + ensure_trait_methods(ccx, it.id); + ensure_supertraits(ccx, it.id, it.span, rp, *supertraits, generics); + + let (_, provided_methods) = + split_trait_methods(*trait_methods); + let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id)); + let (ty_generics, _) = mk_item_substs(ccx, generics, rp, + Some(untransformed_rcvr_ty)); + let _ = convert_methods(ccx, provided_methods, + untransformed_rcvr_ty, + &ty_generics, generics, + it.vis); } ast::item_struct(struct_def, ref generics) => { ensure_no_ty_param_bounds(ccx, it.span, generics, "structure"); @@ -714,16 +912,18 @@ pub fn convert_struct(ccx: &CrateCtxt, write_ty_to_tcx(tcx, dtor.node.id, t_dtor); tcx.tcache.insert(local_def(dtor.node.id), ty_param_bounds_and_ty { - bounds: tpt.bounds, - region_param: rp, - ty: t_dtor}); + generics: ty::Generics { + type_param_defs: tpt.generics.type_param_defs, + region_param: rp + }, + ty: t_dtor}); }; // Write the type of each of the members for struct_def.fields.each |f| { - convert_field(ccx, rp, tpt.bounds, *f, generics); + convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics); } - let (_, substs) = mk_substs(ccx, generics, rp); + let (_, substs) = mk_item_substs(ccx, generics, rp, None); let selfty = ty::mk_struct(tcx, local_def(id), substs); // If this struct is enum-like or tuple-like, create the type of its @@ -744,8 +944,7 @@ pub fn convert_struct(ccx: &CrateCtxt, let ctor_fn_ty = ty::mk_ctor_fn(tcx, inputs, selfty); write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty); tcx.tcache.insert(local_def(ctor_id), ty_param_bounds_and_ty { - bounds: tpt.bounds, - region_param: tpt.region_param, + generics: tpt.generics, ty: ctor_fn_ty }); } @@ -762,85 +961,78 @@ pub fn convert_foreign(ccx: &CrateCtxt, i: @ast::foreign_item) { ccx.tcx.tcache.insert(local_def(i.id), tpt); } -pub fn ty_of_method(ccx: &CrateCtxt, - m: @ast::method, - rp: Option, - rcvr_generics: &ast::Generics, - method_generics: &ast::Generics) - -> ty::method { - let rscope = MethodRscope::new(m.self_ty.node, - rp, - rcvr_generics); - ty::method { - ident: m.ident, - tps: ty_param_bounds(ccx, &m.generics), - fty: astconv::ty_of_bare_fn(ccx, - &rscope, - m.purity, - AbiSet::Rust(), - &method_generics.lifetimes, - &m.decl), - self_ty: m.self_ty.node, - vis: m.vis, - def_id: local_def(m.id) - } -} - -pub fn ty_of_ty_method(self: &CrateCtxt, - m: &ast::ty_method, - rp: Option, - id: ast::def_id, - generics: &ast::Generics) - -> ty::method { - let rscope = MethodRscope::new(m.self_ty.node, rp, generics); - ty::method { - ident: m.ident, - tps: ty_param_bounds(self, &m.generics), - fty: astconv::ty_of_bare_fn(self, - &rscope, - m.purity, - AbiSet::Rust(), - &m.generics.lifetimes, - &m.decl), - // assume public, because this is only invoked on trait methods - self_ty: m.self_ty.node, - vis: ast::public, - def_id: id - } -} - -/* - Instantiates the path for the given trait reference, assuming that - it's bound to a valid trait type. Returns the def_id for the defining - trait. Fails if the type is a type other than an trait type. - */ pub fn instantiate_trait_ref(ccx: &CrateCtxt, - t: @ast::trait_ref, + ast_trait_ref: @ast::trait_ref, rp: Option, - generics: &ast::Generics) - -> (ast::def_id, ty_param_substs_and_ty) { - - let sp = t.path.span, err = ~"can only implement trait types", - sess = ccx.tcx.sess; + generics: &ast::Generics, + self_ty: ty::t) -> @ty::TraitRef +{ + /*! + * Instantiates the path for the given trait reference, assuming that + * it's bound to a valid trait type. Returns the def_id for the defining + * trait. Fails if the type is a type other than an trait type. + */ let rp = RegionParameterization::from_variance_and_generics(rp, generics); let rscope = type_rscope(rp); - match lookup_def_tcx(ccx.tcx, t.path.span, t.ref_id) { - ast::def_ty(t_id) => { - let tpt = astconv::ast_path_to_ty(ccx, &rscope, t_id, t.path); + match lookup_def_tcx(ccx.tcx, ast_trait_ref.path.span, ast_trait_ref.ref_id) { + ast::def_trait(trait_did) => { + let trait_ref = + astconv::ast_path_to_trait_ref( + ccx, &rscope, trait_did, Some(self_ty), ast_trait_ref.path); + ccx.tcx.trait_refs.insert( + ast_trait_ref.ref_id, trait_ref); + return trait_ref; + } + _ => { + ccx.tcx.sess.span_fatal( + ast_trait_ref.path.span, + fmt!("%s is not a trait", + path_to_str(ast_trait_ref.path, + ccx.tcx.sess.intr()))); + } + } +} - write_tpt_to_tcx(ccx.tcx, t.ref_id, &tpt); +fn get_trait_def(ccx: &CrateCtxt, trait_id: ast::def_id) -> @ty::TraitDef { + if trait_id.crate != ast::local_crate { + ty::lookup_trait_def(ccx.tcx, trait_id) + } else { + match ccx.tcx.items.get(&trait_id.node) { + &ast_map::node_item(item, _) => trait_def_of_item(ccx, item), + _ => ccx.tcx.sess.bug(fmt!("get_trait_def(%d): not an item", + trait_id.node)) + } + } +} - match ty::get(tpt.ty).sty { - ty::ty_trait(*) => { - (t_id, tpt) - } - _ => sess.span_fatal(sp, err), +pub fn trait_def_of_item(ccx: &CrateCtxt, it: @ast::item) -> @ty::TraitDef { + let def_id = local_def(it.id); + let tcx = ccx.tcx; + match tcx.trait_defs.find(&def_id) { + Some(&def) => return def, + _ => {} + } + let rp = tcx.region_paramd_items.find(&it.id).map_consume(|x| *x); + match it.node { + ast::item_trait(ref generics, _, _) => { + let self_ty = ty::mk_self(tcx, def_id); + let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, + Some(self_ty)); + let trait_ref = @ty::TraitRef {def_id: def_id, + substs: substs}; + let trait_def = @ty::TraitDef {generics: ty_generics, + trait_ref: trait_ref}; + tcx.trait_defs.insert(def_id, trait_def); + return trait_def; + } + ref s => { + tcx.sess.span_bug( + it.span, + fmt!("trait_def_of_item invoked on %?", s)); } - } - _ => sess.span_fatal(sp, err) } } @@ -861,7 +1053,8 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) return tpt; } ast::item_fn(ref decl, purity, _, ref generics, _) => { - let bounds = ty_param_bounds(ccx, generics); + assert!(rp.is_none()); + let ty_generics = ty_generics(ccx, None, generics, 0); let tofd = astconv::ty_of_bare_fn(ccx, &empty_rscope, purity, @@ -869,8 +1062,10 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) &generics.lifetimes, decl); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: None, + generics: ty::Generics { + type_param_defs: ty_generics.type_param_defs, + region_param: None + }, ty: ty::mk_bare_fn(ccx.tcx, tofd) }; debug!("type of %s (id %d) is %s", @@ -901,8 +1096,7 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } }; ty_param_bounds_and_ty { - bounds: ty_param_bounds(ccx, generics), - region_param: rp, + generics: ty_generics(ccx, rp, generics, 0), ty: ty } }; @@ -912,37 +1106,26 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: @ast::item) } ast::item_enum(_, ref generics) => { // Create a new generic polytype. - let (bounds, substs) = mk_substs(ccx, generics, rp); + let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); let t = ty::mk_enum(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, + generics: ty_generics, ty: t }; tcx.tcache.insert(local_def(it.id), tpt); return tpt; } - ast::item_trait(ref generics, _, _) => { - let (bounds, substs) = mk_substs(ccx, generics, rp); - let t = ty::mk_trait(tcx, - local_def(it.id), - substs, - ty::BareTraitStore); - let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, - ty: t - }; - tcx.tcache.insert(local_def(it.id), tpt); - return tpt; + ast::item_trait(*) => { + tcx.sess.span_bug( + it.span, + fmt!("Invoked ty_of_item on trait")); } ast::item_struct(_, ref generics) => { - let (bounds, substs) = mk_substs(ccx, generics, rp); + let (ty_generics, substs) = mk_item_substs(ccx, generics, rp, None); let t = ty::mk_struct(tcx, local_def(it.id), substs); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: rp, - ty: t + generics: ty_generics, + ty: t }; tcx.tcache.insert(local_def(it.id), tpt); return tpt; @@ -964,76 +1147,93 @@ pub fn ty_of_foreign_item(ccx: &CrateCtxt, it: @ast::foreign_item) } ast::foreign_item_const(t) => { ty::ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics { + type_param_defs: @~[], + region_param: None, + }, ty: ast_ty_to_ty(ccx, &empty_rscope, t) } } } } -// Translate the AST's notion of ty param bounds (which are an enum consisting -// of a newtyped Ty or a region) to ty's notion of ty param bounds, which can -// either be user-defined traits, or one of the four built-in traits (formerly -// known as kinds): Const, Copy, Durable, and Send. -pub fn compute_bounds(ccx: &CrateCtxt, - ast_bounds: @OptVec) - -> ty::param_bounds { - @ast_bounds.flat_map_to_vec(|b| { - match b { - &TraitTyParamBound(b) => { - let li = &ccx.tcx.lang_items; - let ity = ast_ty_to_ty(ccx, &empty_rscope, b); - match ty::get(ity).sty { - ty::ty_trait(did, _, _) => { - if did == li.owned_trait() { - ~[ty::bound_owned] - } else if did == li.copy_trait() { - ~[ty::bound_copy] - } else if did == li.const_trait() { - ~[ty::bound_const] - } else if did == li.durable_trait() { - ~[ty::bound_durable] - } else { - // Must be a user-defined trait - ~[ty::bound_trait(ity)] - } - } - _ => { - ccx.tcx.sess.span_err( - (*b).span, ~"type parameter bounds must be \ - trait types"); - ~[] - } +pub fn ty_generics(ccx: &CrateCtxt, + rp: Option, + generics: &ast::Generics, + base_index: uint) -> ty::Generics { + return ty::Generics { + region_param: rp, + type_param_defs: @generics.ty_params.mapi_to_vec(|offset, param| { + match ccx.tcx.ty_param_defs.find(¶m.id) { + Some(&def) => def, + None => { + let param_ty = ty::param_ty {idx: base_index + offset, + def_id: local_def(param.id)}; + let bounds = compute_bounds(ccx, rp, generics, + param_ty, param.bounds); + let def = ty::TypeParameterDef { + def_id: local_def(param.id), + bounds: bounds + }; + debug!("def for param: %s", def.repr(ccx.tcx)); + ccx.tcx.ty_param_defs.insert(param.id, def); + def } } - &RegionTyParamBound => ~[ty::bound_durable] - } - }) -} + }) + }; -pub fn ty_param_bounds(ccx: &CrateCtxt, - generics: &ast::Generics) - -> @~[ty::param_bounds] { - @do generics.ty_params.map_to_vec |param| { - match ccx.tcx.ty_param_bounds.find(¶m.id) { - Some(&bs) => bs, - None => { - let bounds = compute_bounds(ccx, param.bounds); - ccx.tcx.ty_param_bounds.insert(param.id, bounds); - bounds - } - } + fn compute_bounds( + ccx: &CrateCtxt, + rp: Option, + generics: &ast::Generics, + param_ty: ty::param_ty, + ast_bounds: @OptVec) -> ty::param_bounds + { + /*! + * + * Translate the AST's notion of ty param bounds (which are an + * enum consisting of a newtyped Ty or a region) to ty's + * notion of ty param bounds, which can either be user-defined + * traits, or one of the four built-in traits (formerly known + * as kinds): Const, Copy, Durable, and Send. + */ + + @ast_bounds.flat_map_to_vec(|b| { + match b { + &TraitTyParamBound(b) => { + let li = &ccx.tcx.lang_items; + 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() { + ~[ty::bound_owned] + } else if trait_ref.def_id == li.copy_trait() { + ~[ty::bound_copy] + } else if trait_ref.def_id == li.const_trait() { + ~[ty::bound_const] + } else if trait_ref.def_id == li.durable_trait() { + ~[ty::bound_durable] + } else { + // Must be a user-defined trait + ~[ty::bound_trait(trait_ref)] + } + } + + &RegionTyParamBound => { + ~[ty::bound_durable] + } + } + }) } } pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, decl: &ast::fn_decl, def_id: ast::def_id, - generics: &ast::Generics) + ast_generics: &ast::Generics) -> ty::ty_param_bounds_and_ty { - let bounds = ty_param_bounds(ccx, generics); - let region_param_names = RegionParamNames::from_generics(generics); + let ty_generics = ty_generics(ccx, None, ast_generics, 0); + let region_param_names = RegionParamNames::from_generics(ast_generics); let rb = in_binding_rscope(&empty_rscope, region_param_names); let input_tys = decl.inputs.map(|a| ty_of_arg(ccx, &rb, *a, None) ); let output_ty = ast_ty_to_ty(ccx, &rb, decl.output); @@ -1048,33 +1248,25 @@ pub fn ty_of_foreign_fn_decl(ccx: &CrateCtxt, output: output_ty} }); let tpt = ty_param_bounds_and_ty { - bounds: bounds, - region_param: None, + generics: ty_generics, ty: t_fn }; ccx.tcx.tcache.insert(def_id, tpt); return tpt; } -pub fn mk_generics(ccx: &CrateCtxt, generics: &ast::Generics) - -> (@~[ty::param_bounds], ~[ty::t]) -{ - let mut i = 0u; - let bounds = ty_param_bounds(ccx, generics); - (bounds, - generics.ty_params.map_to_vec(|atp| { - let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); - i += 1u; - t - })) -} - -pub fn mk_substs(ccx: &CrateCtxt, - generics: &ast::Generics, - rp: Option) - -> (@~[ty::param_bounds], ty::substs) +pub fn mk_item_substs(ccx: &CrateCtxt, + ast_generics: &ast::Generics, + rp: Option, + self_ty: Option) -> (ty::Generics, ty::substs) { - let (bounds, params) = mk_generics(ccx, generics); + let mut i = 0; + let ty_generics = ty_generics(ccx, rp, ast_generics, 0); + let params = ast_generics.ty_params.map_to_vec(|atp| { + let t = ty::mk_param(ccx.tcx, i, local_def(atp.id)); + i += 1u; + t + }); let self_r = rscope::bound_self_region(rp); - (bounds, substs { self_r: self_r, self_ty: None, tps: params }) + (ty_generics, substs {self_r: self_r, self_ty: self_ty, tps: params}) } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index add70b21e39a4..be1d291cfe5c9 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -90,7 +90,7 @@ pub trait Combine { fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]>; fn self_tys(&self, a: Option, b: Option) -> cres>; - fn substs(&self, did: ast::def_id, as_: &ty::substs, + fn substs(&self, generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres; fn bare_fn_tys(&self, a: &ty::BareFnTy, b: &ty::BareFnTy) -> cres; @@ -114,6 +114,7 @@ pub trait Combine { a: ty::TraitStore, b: ty::TraitStore) -> cres; + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres; } pub struct CombineFields { @@ -192,32 +193,31 @@ pub fn eq_opt_regions( } pub fn super_substs( - self: &C, did: ast::def_id, + self: &C, generics: &ty::Generics, a: &ty::substs, b: &ty::substs) -> cres { fn relate_region_param( self: &C, - did: ast::def_id, + generics: &ty::Generics, a: Option, b: Option) -> cres> { - let polyty = ty::lookup_item_type(self.infcx().tcx, did); - match (polyty.region_param, a, b) { - (None, None, None) => { + match (&generics.region_param, &a, &b) { + (&None, &None, &None) => { Ok(None) } - (Some(ty::rv_invariant), Some(a), Some(b)) => { + (&Some(ty::rv_invariant), &Some(a), &Some(b)) => { do eq_regions(self, a, b).then { Ok(Some(a)) } } - (Some(ty::rv_covariant), Some(a), Some(b)) => { + (&Some(ty::rv_covariant), &Some(a), &Some(b)) => { do self.regions(a, b).chain |r| { Ok(Some(r)) } } - (Some(ty::rv_contravariant), Some(a), Some(b)) => { + (&Some(ty::rv_contravariant), &Some(a), &Some(b)) => { do self.contraregions(a, b).chain |r| { Ok(Some(r)) } @@ -233,14 +233,14 @@ pub fn super_substs( b had opt_region %s with variance %?", a.inf_str(self.infcx()), b.inf_str(self.infcx()), - polyty.region_param)); + generics.region_param)); } } } do self.tps(a.tps, b.tps).chain |tps| { do self.self_tys(a.self_ty, b.self_ty).chain |self_ty| { - do relate_region_param(self, did, + do relate_region_param(self, generics, a.self_r, b.self_r).chain |self_r| { Ok(substs { @@ -274,15 +274,14 @@ pub fn super_tps( pub fn super_self_tys( self: &C, a: Option, b: Option) -> cres> { - // Note: the self type parameter is (currently) always treated as - // *invariant* (otherwise the type system would be unsound). - match (a, b) { (None, None) => { Ok(None) } (Some(a), Some(b)) => { - eq_tys(self, a, b).then(|| Ok(Some(a)) ) + // FIXME(#5781) this should be eq_tys + // eq_tys(self, a, b).then(|| Ok(Some(a)) ) + self.contratys(a, b).chain(|t| Ok(Some(t))) } (None, Some(_)) | (Some(_), None) => { @@ -520,26 +519,29 @@ pub fn super_tys( (ty::ty_enum(a_id, ref a_substs), ty::ty_enum(b_id, ref b_substs)) if a_id == b_id => { - do self.substs(a_id, a_substs, b_substs).chain |substs| { - Ok(ty::mk_enum(tcx, a_id, substs)) - } + let type_def = ty::lookup_item_type(tcx, a_id); + do self.substs(&type_def.generics, a_substs, b_substs).chain |substs| { + Ok(ty::mk_enum(tcx, a_id, substs)) + } } (ty::ty_trait(a_id, ref a_substs, a_store), ty::ty_trait(b_id, ref b_substs, b_store)) if a_id == b_id => { - do self.substs(a_id, a_substs, b_substs).chain |substs| { - do self.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { - Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s)) - } - } + let trait_def = ty::lookup_trait_def(tcx, a_id); + do self.substs(&trait_def.generics, a_substs, b_substs).chain |substs| { + do self.trait_stores(ty::terr_trait, a_store, b_store).chain |s| { + Ok(ty::mk_trait(tcx, a_id, /*bad*/copy substs, s)) + } + } } (ty::ty_struct(a_id, ref a_substs), ty::ty_struct(b_id, ref b_substs)) if a_id == b_id => { - do self.substs(a_id, a_substs, b_substs).chain |substs| { - Ok(ty::mk_struct(tcx, a_id, substs)) - } + let type_def = ty::lookup_item_type(tcx, a_id); + do self.substs(&type_def.generics, a_substs, b_substs).chain |substs| { + Ok(ty::mk_struct(tcx, a_id, substs)) + } } (ty::ty_box(ref a_mt), ty::ty_box(ref b_mt)) => { @@ -634,3 +636,25 @@ pub fn super_tys( Ok(ty::mk_mach_float(tcx, val)) } } + +pub fn super_trait_refs( + self: &C, a: &ty::TraitRef, b: &ty::TraitRef) -> cres +{ + // Different traits cannot be related + + // - NOTE in the future, expand out subtraits! + + if a.def_id != b.def_id { + Err(ty::terr_traits( + expected_found(self, a.def_id, b.def_id))) + } else { + let tcx = self.infcx().tcx; + let trait_def = ty::lookup_trait_def(tcx, a.def_id); + let substs = if_ok!(self.substs(&trait_def.generics, &a.substs, &b.substs)); + Ok(ty::TraitRef { + def_id: a.def_id, + substs: substs + }) + } +} + diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 9c8c8997ae087..43f2b0eaf7229 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -299,10 +299,11 @@ impl Combine for Glb { super_closure_tys(self, a, b) } - fn substs(&self, did: ast::def_id, + fn substs(&self, + generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres { - super_substs(self, did, as_, bs) + super_substs(self, generics, as_, bs) } fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { @@ -313,5 +314,9 @@ impl Combine for Glb { -> cres> { super_self_tys(self, a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + super_trait_refs(self, a, b) + } } diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 5a705c31c1239..7cf4d25c67024 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -244,10 +244,11 @@ impl Combine for Lub { super_args(self, a, b) } - fn substs(&self, did: ast::def_id, + fn substs(&self, + generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres { - super_substs(self, did, as_, bs) + super_substs(self, generics, as_, bs) } fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { @@ -258,4 +259,8 @@ impl Combine for Lub { -> cres> { super_self_tys(self, a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + super_trait_refs(self, a, b) + } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index d8093d571a111..58de0122c8c9b 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -265,7 +265,7 @@ use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::unify::{ValsAndBindings, Root}; use middle::typeck::isr_alist; use util::common::indent; -use util::ppaux::{bound_region_to_str, ty_to_str}; +use util::ppaux::{bound_region_to_str, ty_to_str, trait_ref_to_str}; use core::cmp::Eq; use core::result::{Result, Ok, Err}; @@ -419,6 +419,23 @@ pub fn mk_eqty(cx: @mut InferCtxt, }.to_ures() } +pub fn mk_sub_trait_refs(cx: @mut InferCtxt, + a_is_expected: bool, + span: span, + a: &ty::TraitRef, + b: &ty::TraitRef) + -> ures +{ + debug!("mk_sub_trait_refs(%s <: %s)", + a.inf_str(cx), b.inf_str(cx)); + do indent { + do cx.commit { + let suber = cx.sub(a_is_expected, span); + suber.trait_refs(a, b) + } + }.to_ures() +} + pub fn mk_coercety(cx: @mut InferCtxt, a_is_expected: bool, span: span, @@ -700,6 +717,11 @@ pub impl InferCtxt { self.resolve_type_vars_if_possible(t)) } + fn trait_ref_to_str(@mut self, t: &ty::TraitRef) -> ~str { + let t = self.resolve_type_vars_in_trait_ref_if_possible(t); + trait_ref_to_str(self.tcx, &t) + } + fn resolve_type_vars_if_possible(@mut self, typ: ty::t) -> ty::t { match resolve_type(self, typ, resolve_nested_tvar | resolve_ivar) { result::Ok(new_type) => new_type, @@ -707,6 +729,31 @@ pub impl InferCtxt { } } + fn resolve_type_vars_in_trait_ref_if_possible(@mut self, + trait_ref: &ty::TraitRef) + -> ty::TraitRef + { + // make up a dummy type just to reuse/abuse the resolve machinery + let dummy0 = ty::mk_trait(self.tcx, + trait_ref.def_id, + copy trait_ref.substs, + ty::UniqTraitStore); + let dummy1 = self.resolve_type_vars_if_possible(dummy0); + match ty::get(dummy1).sty { + ty::ty_trait(ref def_id, ref substs, _) => { + ty::TraitRef {def_id: *def_id, + substs: copy *substs} + } + _ => { + self.tcx.sess.bug( + fmt!("resolve_type_vars_if_possible() yielded %s \ + when supplied with %s", + self.ty_to_str(dummy0), + self.ty_to_str(dummy1))); + } + } + } + fn type_error_message(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, actual_ty: ty::t, err: Option<&ty::type_err>) { let actual_ty = self.resolve_type_vars_if_possible(actual_ty); diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs index d9f00451dd57e..7252566d84c17 100644 --- a/src/librustc/middle/typeck/infer/region_inference.rs +++ b/src/librustc/middle/typeck/infer/region_inference.rs @@ -538,22 +538,22 @@ more convincing in the future. use core::prelude::*; -use middle::region::is_subregion_of; -use middle::region; use middle::ty; -use middle::ty::{Region, RegionVid, re_static, re_infer, re_free, re_bound}; +use middle::ty::{FreeRegion, Region, RegionVid}; +use middle::ty::{re_static, re_infer, re_free, re_bound}; use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh}; use middle::typeck::infer::cres; use util::common::indenter; use util::ppaux::note_and_explain_region; use core::cell::{Cell, empty_cell}; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::result::{Err, Ok}; use core::to_bytes; use core::uint; use core::vec; use syntax::codemap::span; +use syntax::ast; #[deriving(Eq)] enum Constraint { @@ -600,12 +600,12 @@ enum CombineMapType { Lub, Glb } -type CombineMap = LinearMap; +type CombineMap = HashMap; pub struct RegionVarBindings { tcx: ty::ctxt, var_spans: ~[span], - constraints: LinearMap, + constraints: HashMap, lubs: CombineMap, glbs: CombineMap, skolemization_count: uint, @@ -632,9 +632,9 @@ pub fn RegionVarBindings(tcx: ty::ctxt) -> RegionVarBindings { tcx: tcx, var_spans: ~[], values: empty_cell(), - constraints: LinearMap::new(), - lubs: LinearMap::new(), - glbs: LinearMap::new(), + constraints: HashMap::new(), + lubs: HashMap::new(), + glbs: HashMap::new(), skolemization_count: 0, bound_count: 0, undo_log: ~[] @@ -1025,11 +1025,12 @@ pub impl RegionVarBindings { } priv impl RegionVarBindings { - fn is_subregion_of(&mut self, sub: Region, sup: Region) -> bool { - is_subregion_of(self.tcx.region_map, sub, sup) + fn is_subregion_of(&self, sub: Region, sup: Region) -> bool { + let rm = self.tcx.region_maps; + rm.is_subregion_of(sub, sup) } - fn lub_concrete_regions(&mut self, +a: Region, +b: Region) -> Region { + fn lub_concrete_regions(&self, +a: Region, +b: Region) -> Region { match (a, b) { (re_static, _) | (_, re_static) => { re_static // nothing lives longer than static @@ -1042,17 +1043,17 @@ priv impl RegionVarBindings { non-concrete regions: %?, %?", a, b)); } - (f @ re_free(f_id, _), re_scope(s_id)) | - (re_scope(s_id), f @ re_free(f_id, _)) => { + (f @ re_free(ref fr), re_scope(s_id)) | + (re_scope(s_id), f @ re_free(ref fr)) => { // A "free" region can be interpreted as "some region - // at least as big as the block f_id". So, we can + // at least as big as the block fr.scope_id". So, we can // reasonably compare free regions and scopes: - let rm = self.tcx.region_map; - match region::nearest_common_ancestor(rm, f_id, s_id) { - // if the free region's scope `f_id` is bigger than + let rm = self.tcx.region_maps; + match rm.nearest_common_ancestor(fr.scope_id, s_id) { + // if the free region's scope `fr.scope_id` is bigger than // the scope region `s_id`, then the LUB is the free // region itself: - Some(r_id) if r_id == f_id => f, + Some(r_id) if r_id == fr.scope_id => f, // otherwise, we don't know what the free region is, // so we must conservatively say the LUB is static: @@ -1064,32 +1065,67 @@ priv impl RegionVarBindings { // The region corresponding to an outer block is a // subtype of the region corresponding to an inner // block. - let rm = self.tcx.region_map; - match region::nearest_common_ancestor(rm, a_id, b_id) { + let rm = self.tcx.region_maps; + match rm.nearest_common_ancestor(a_id, b_id) { Some(r_id) => re_scope(r_id), _ => re_static } } + (re_free(ref a_fr), re_free(ref b_fr)) => { + self.lub_free_regions(a_fr, b_fr) + } + // For these types, we cannot define any additional // relationship: (re_infer(ReSkolemized(*)), _) | (_, re_infer(ReSkolemized(*))) | - (re_free(_, _), re_free(_, _)) | (re_bound(_), re_bound(_)) | - (re_bound(_), re_free(_, _)) | + (re_bound(_), re_free(_)) | (re_bound(_), re_scope(_)) | - (re_free(_, _), re_bound(_)) | + (re_free(_), re_bound(_)) | (re_scope(_), re_bound(_)) => { if a == b {a} else {re_static} } } } - fn glb_concrete_regions(&mut self, + fn lub_free_regions(&self, + a: &FreeRegion, + b: &FreeRegion) -> ty::Region + { + /*! + * Computes a region that encloses both free region arguments. + * Guarantee that if the same two regions are given as argument, + * in any order, a consistent result is returned. + */ + + return match a.cmp(b) { + Less => helper(self, a, b), + Greater => helper(self, b, a), + Equal => ty::re_free(*a) + }; + + fn helper(self: &RegionVarBindings, + a: &FreeRegion, + b: &FreeRegion) -> ty::Region + { + let rm = self.tcx.region_maps; + if rm.sub_free_region(*a, *b) { + ty::re_free(*b) + } else if rm.sub_free_region(*b, *a) { + ty::re_free(*a) + } else { + ty::re_static + } + } + } + + fn glb_concrete_regions(&self, +a: Region, +b: Region) -> cres { + debug!("glb_concrete_regions(%?, %?)", a, b); match (a, b) { (re_static, r) | (r, re_static) => { // static lives longer than everything else @@ -1104,37 +1140,26 @@ priv impl RegionVarBindings { non-concrete regions: %?, %?", a, b)); } - (re_free(f_id, _), s @ re_scope(s_id)) | - (s @ re_scope(s_id), re_free(f_id, _)) => { + (re_free(ref fr), s @ re_scope(s_id)) | + (s @ re_scope(s_id), re_free(ref fr)) => { // Free region is something "at least as big as - // `f_id`." If we find that the scope `f_id` is bigger + // `fr.scope_id`." If we find that the scope `fr.scope_id` is bigger // than the scope `s_id`, then we can say that the GLB // is the scope `s_id`. Otherwise, as we do not know // big the free region is precisely, the GLB is undefined. - let rm = self.tcx.region_map; - match region::nearest_common_ancestor(rm, f_id, s_id) { - Some(r_id) if r_id == f_id => Ok(s), + let rm = self.tcx.region_maps; + match rm.nearest_common_ancestor(fr.scope_id, s_id) { + Some(r_id) if r_id == fr.scope_id => Ok(s), _ => Err(ty::terr_regions_no_overlap(b, a)) } } - (re_scope(a_id), re_scope(b_id)) | - (re_free(a_id, _), re_free(b_id, _)) => { - if a == b { - // Same scope or same free identifier, easy case. - Ok(a) - } else { - // We want to generate the intersection of two - // scopes or two free regions. So, if one of - // these scopes is a subscope of the other, return - // it. Otherwise fail. - let rm = self.tcx.region_map; - match region::nearest_common_ancestor(rm, a_id, b_id) { - Some(r_id) if a_id == r_id => Ok(re_scope(b_id)), - Some(r_id) if b_id == r_id => Ok(re_scope(a_id)), - _ => Err(ty::terr_regions_no_overlap(b, a)) - } - } + (re_scope(a_id), re_scope(b_id)) => { + self.intersect_scopes(a, b, a_id, b_id) + } + + (re_free(ref a_fr), re_free(ref b_fr)) => { + self.glb_free_regions(a_fr, b_fr) } // For these types, we cannot define any additional @@ -1142,9 +1167,9 @@ priv impl RegionVarBindings { (re_infer(ReSkolemized(*)), _) | (_, re_infer(ReSkolemized(*))) | (re_bound(_), re_bound(_)) | - (re_bound(_), re_free(_, _)) | + (re_bound(_), re_free(_)) | (re_bound(_), re_scope(_)) | - (re_free(_, _), re_bound(_)) | + (re_free(_), re_bound(_)) | (re_scope(_), re_bound(_)) => { if a == b { Ok(a) @@ -1155,10 +1180,62 @@ priv impl RegionVarBindings { } } + fn glb_free_regions(&self, + a: &FreeRegion, + b: &FreeRegion) -> cres + { + /*! + * Computes a region that is enclosed by both free region arguments, + * if any. Guarantees that if the same two regions are given as argument, + * in any order, a consistent result is returned. + */ + + return match a.cmp(b) { + Less => helper(self, a, b), + Greater => helper(self, b, a), + Equal => Ok(ty::re_free(*a)) + }; + + fn helper(self: &RegionVarBindings, + a: &FreeRegion, + b: &FreeRegion) -> cres + { + let rm = self.tcx.region_maps; + if rm.sub_free_region(*a, *b) { + Ok(ty::re_free(*a)) + } else if rm.sub_free_region(*b, *a) { + Ok(ty::re_free(*b)) + } else { + self.intersect_scopes(ty::re_free(*a), ty::re_free(*b), + a.scope_id, b.scope_id) + } + } + } + fn report_type_error(&mut self, span: span, terr: &ty::type_err) { let terr_str = ty::type_err_to_str(self.tcx, terr); self.tcx.sess.span_err(span, terr_str); } + + fn intersect_scopes(&self, + region_a: ty::Region, + region_b: ty::Region, + scope_a: ast::node_id, + scope_b: ast::node_id) -> cres + { + // We want to generate the intersection of two + // scopes or two free regions. So, if one of + // these scopes is a subscope of the other, return + // it. Otherwise fail. + debug!("intersect_scopes(scope_a=%?, scope_b=%?, region_a=%?, region_b=%?)", + scope_a, scope_b, region_a, region_b); + let rm = self.tcx.region_maps; + match rm.nearest_common_ancestor(scope_a, scope_b) { + Some(r_id) if scope_a == r_id => Ok(re_scope(scope_b)), + Some(r_id) if scope_b == r_id => Ok(re_scope(scope_a)), + _ => Err(ty::terr_regions_no_overlap(region_a, region_b)) + } + } } // ______________________________________________________________________ @@ -1194,7 +1271,7 @@ struct SpannedRegion { span: span, } -type TwoRegionsMap = LinearSet; +type TwoRegionsMap = HashSet; pub impl RegionVarBindings { fn infer_variable_values(&mut self) -> ~[GraphNodeValue] { @@ -1223,7 +1300,7 @@ pub impl RegionVarBindings { // It would be nice to write this using map(): let mut edges = vec::with_capacity(num_edges); - for self.constraints.each |&(constraint, span)| { + for self.constraints.each |constraint, span| { edges.push(GraphEdge { next_edge: [uint::max_value, uint::max_value], constraint: *constraint, @@ -1423,7 +1500,7 @@ pub impl RegionVarBindings { &mut self, graph: &Graph) -> ~[GraphNodeValue] { - let mut dup_map = LinearSet::new(); + let mut dup_map = HashSet::new(); graph.nodes.mapi(|idx, node| { match node.value { Value(_) => { @@ -1598,7 +1675,7 @@ pub impl RegionVarBindings { orig_node_idx: RegionVid, dir: Direction) -> ~[SpannedRegion] { - let mut set = LinearSet::new(); + let mut set = HashSet::new(); let mut stack = ~[orig_node_idx]; set.insert(orig_node_idx.to_uint()); let mut result = ~[]; diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 161905c12e5dd..2e1be2c380f8f 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -256,10 +256,11 @@ impl Combine for Sub { super_args(self, a, b) } - fn substs(&self, did: ast::def_id, + fn substs(&self, + generics: &ty::Generics, as_: &ty::substs, bs: &ty::substs) -> cres { - super_substs(self, did, as_, bs) + super_substs(self, generics, as_, bs) } fn tps(&self, as_: &[ty::t], bs: &[ty::t]) -> cres<~[ty::t]> { @@ -270,5 +271,9 @@ impl Combine for Sub { -> cres> { super_self_tys(self, a, b) } + + fn trait_refs(&self, a: &ty::TraitRef, b: &ty::TraitRef) -> cres { + super_trait_refs(self, a, b) + } } diff --git a/src/librustc/middle/typeck/infer/test.rs b/src/librustc/middle/typeck/infer/test.rs index 52a0300c5a089..bf607e2c36246 100644 --- a/src/librustc/middle/typeck/infer/test.rs +++ b/src/librustc/middle/typeck/infer/test.rs @@ -210,7 +210,9 @@ pub impl Env { } fn t_rptr_free(&self, nid: ast::node_id, id: uint) -> ty::t { - ty::mk_imm_rptr(self.tcx, ty::re_free(nid, ty::br_anon(id)), + ty::mk_imm_rptr(self.tcx, + ty::re_free(ty::FreeRegion {scope_id: nid, + bound_region: ty::br_anon(id)}), self.t_int()) } diff --git a/src/librustc/middle/typeck/infer/to_str.rs b/src/librustc/middle/typeck/infer/to_str.rs index 559d29e66efba..d4959961f12ce 100644 --- a/src/librustc/middle/typeck/infer/to_str.rs +++ b/src/librustc/middle/typeck/infer/to_str.rs @@ -16,7 +16,7 @@ use middle::ty; use middle::typeck::infer::{Bound, Bounds}; use middle::typeck::infer::InferCtxt; use middle::typeck::infer::unify::{Redirect, Root, VarValue}; -use util::ppaux::{mt_to_str, ty_to_str}; +use util::ppaux::{mt_to_str, ty_to_str, trait_ref_to_str}; use syntax::ast; @@ -91,3 +91,9 @@ impl InferStr for ast::float_ty { self.to_str() } } + +impl InferStr for ty::TraitRef { + fn inf_str(&self, cx: &InferCtxt) -> ~str { + trait_ref_to_str(cx.tcx, self) + } +} diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 2b5a47c18c6d9..98117278f3826 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -50,19 +50,23 @@ independently: use core::prelude::*; +use driver::session; + use middle::resolve; use middle::ty; use util::common::time; +use util::ppaux::Repr; use util::ppaux; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::result; use core::vec; use std::list::List; use std::list; use syntax::codemap::span; use syntax::print::pprust::*; -use syntax::{ast, ast_map}; +use syntax::{ast, ast_map, abi}; +use syntax::opt_vec; #[path = "check/mod.rs"] pub mod check; @@ -129,7 +133,7 @@ pub struct method_map_entry { // maps from an expression id that corresponds to a method call to the details // of the method to be invoked -pub type method_map = @mut LinearMap; +pub type method_map = @mut HashMap; // Resolutions for bounds of all parameters, left to right, for a given path. pub type vtable_res = @~[vtable_origin]; @@ -153,14 +157,15 @@ pub enum vtable_origin { vtable_param(uint, uint) } -pub impl vtable_origin { - fn to_str(&self, tcx: ty::ctxt) -> ~str { +impl Repr for vtable_origin { + fn repr(&self, tcx: ty::ctxt) -> ~str { match *self { vtable_static(def_id, ref tys, ref vtable_res) => { - fmt!("vtable_static(%?:%s, %?, %?)", - def_id, ty::item_path_str(tcx, def_id), - tys, - vtable_res.map(|o| o.to_str(tcx))) + fmt!("vtable_static(%?:%s, %s, %s)", + def_id, + ty::item_path_str(tcx, def_id), + tys.repr(tcx), + vtable_res.repr(tcx)) } vtable_param(x, y) => { @@ -170,7 +175,7 @@ pub impl vtable_origin { } } -pub type vtable_map = @mut LinearMap; +pub type vtable_map = @mut HashMap; pub struct CrateCtxt { // A mapping from method call sites to traits that have that method. @@ -222,8 +227,8 @@ pub fn lookup_def_ccx(ccx: @mut CrateCtxt, sp: span, id: ast::node_id) pub fn no_params(t: ty::t) -> ty::ty_param_bounds_and_ty { ty::ty_param_bounds_and_ty { - bounds: @~[], - region_param: None, + generics: ty::Generics {type_param_defs: @~[], + region_param: None}, ty: t } } @@ -325,12 +330,68 @@ fn check_main_fn_ty(ccx: @mut CrateCtxt, } } -fn check_for_main_fn(ccx: @mut CrateCtxt) { +fn check_start_fn_ty(ccx: @mut CrateCtxt, + start_id: ast::node_id, + start_span: span) { + + let tcx = ccx.tcx; + let start_t = ty::node_id_to_type(tcx, start_id); + match ty::get(start_t).sty { + ty::ty_bare_fn(_) => { + match tcx.items.find(&start_id) { + Some(&ast_map::node_item(it,_)) => { + match it.node { + ast::item_fn(_,_,_,ref ps,_) + if ps.is_parameterized() => { + tcx.sess.span_err( + start_span, + ~"start function is not allowed to have type \ + parameters"); + return; + } + _ => () + } + } + _ => () + } + + fn arg(m: ast::rmode, ty: ty::t) -> ty::arg { + ty::arg {mode: ast::expl(m), ty: ty} + } + + let se_ty = ty::mk_bare_fn(tcx, ty::BareFnTy { + purity: ast::impure_fn, + abis: abi::AbiSet::Rust(), + sig: ty::FnSig {bound_lifetime_names: opt_vec::Empty, + inputs: ~[arg(ast::by_copy, ty::mk_int(tcx)), + arg(ast::by_copy, ty::mk_imm_ptr(tcx, + ty::mk_imm_ptr(tcx, ty::mk_u8(tcx)))), + arg(ast::by_copy, ty::mk_imm_ptr(tcx, ty::mk_u8(tcx)))], + output: ty::mk_int(tcx)} + }); + + require_same_types(tcx, None, false, start_span, start_t, se_ty, + || fmt!("start function expects type: `%s`", ppaux::ty_to_str(ccx.tcx, se_ty))); + + } + _ => { + tcx.sess.span_bug(start_span, + ~"start has a non-function type: found `" + + ppaux::ty_to_str(tcx, start_t) + ~"`"); + } + } +} + +fn check_for_entry_fn(ccx: @mut CrateCtxt) { let tcx = ccx.tcx; if !*tcx.sess.building_library { - match *tcx.sess.main_fn { - Some((id, sp)) => check_main_fn_ty(ccx, id, sp), - None => tcx.sess.err(~"main function not found") + match *tcx.sess.entry_fn { + Some((id, sp)) => match *tcx.sess.entry_type { + Some(session::EntryMain) => check_main_fn_ty(ccx, id, sp), + Some(session::EntryStart) => check_start_fn_ty(ccx, id, sp), + None => tcx.sess.bug(~"entry function without a type") + }, + None => tcx.sess.err(~"entry function not found") } } } @@ -342,8 +403,8 @@ pub fn check_crate(tcx: ty::ctxt, let time_passes = tcx.sess.time_passes(); let ccx = @mut CrateCtxt { trait_map: trait_map, - method_map: @mut LinearMap::new(), - vtable_map: @mut LinearMap::new(), + method_map: @mut HashMap::new(), + vtable_map: @mut HashMap::new(), coherence_info: @coherence::CoherenceInfo(), tcx: tcx }; @@ -357,7 +418,7 @@ pub fn check_crate(tcx: ty::ctxt, time(time_passes, ~"type checking", || check::check_item_types(ccx, crate)); - check_for_main_fn(ccx); + check_for_entry_fn(ccx); tcx.sess.abort_if_errors(); (ccx.method_map, ccx.vtable_map) } diff --git a/src/librustc/middle/typeck/rscope.rs b/src/librustc/middle/typeck/rscope.rs index eeca90dbecd5d..3ff36a409a71f 100644 --- a/src/librustc/middle/typeck/rscope.rs +++ b/src/librustc/middle/typeck/rscope.rs @@ -180,12 +180,11 @@ impl region_scope for MethodRscope { }) } fn self_region(&self, _span: span) -> Result { - assert!(self.variance.is_some() || self.self_ty.is_borrowed()); + assert!(self.variance.is_some()); match self.variance { None => {} // must be borrowed self, so this is OK Some(_) => { - if !self.self_ty.is_borrowed() && - !self.region_param_names.has_self() { + if !self.region_param_names.has_self() { return Err(RegionError { msg: ~"the `self` lifetime must be declared", replacement: ty::re_bound(ty::br_self) diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 456f9743afab4..d1dbb48ba08a4 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -10,7 +10,7 @@ #[link(name = "rustc", - vers = "0.6", + vers = "0.7-pre", uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf", url = "https://github.com/mozilla/rust/tree/master/src/rustc")]; @@ -27,9 +27,9 @@ #[no_core]; -extern mod core(vers = "0.6"); -extern mod std(vers = "0.6"); -extern mod syntax(vers = "0.6"); +extern mod core(vers = "0.7-pre"); +extern mod std(vers = "0.7-pre"); +extern mod syntax(vers = "0.7-pre"); use core::prelude::*; @@ -83,6 +83,7 @@ pub mod middle { pub mod asm; } pub mod ty; + pub mod subst; pub mod resolve; #[path = "typeck/mod.rs"] pub mod typeck; @@ -176,7 +177,7 @@ Available lint options: padded(max_key, ~"name"), ~"default", ~"meaning")); io::println(fmt!(" %s %7.7s %s\n", padded(max_key, ~"----"), ~"-------", ~"-------")); - for lint_dict.each |&(k, v)| { + for lint_dict.each |k, v| { let k = str::replace(*k, ~"_", ~"-"); io::println(fmt!(" %s %7.7s %s", padded(max_key, k), diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 2a2d921ba8636..30152c2284574 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -14,7 +14,7 @@ use syntax::ast; use syntax::codemap::{span}; use syntax::visit; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use core::str; use std; @@ -114,7 +114,7 @@ pub fn pluralize(n: uint, +s: ~str) -> ~str { } // A set of node IDs (used to keep track of which node IDs are for statements) -pub type stmt_set = @mut LinearSet; +pub type stmt_set = @mut HashSet; // // Local Variables: diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index afbf3f485d0ae..9b9e0e81b4346 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -11,6 +11,7 @@ use core::prelude::*; use middle::ty; +use middle::typeck; use middle::ty::canon_mode; use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid, br_fresh}; @@ -35,10 +36,14 @@ use syntax::abi::AbiSet; use core::str; use core::vec; +pub trait Repr { + fn repr(&self, tcx: ctxt) -> ~str; +} + pub fn note_and_explain_region(cx: ctxt, - prefix: ~str, + prefix: &str, region: ty::Region, - suffix: ~str) { + suffix: &str) { match explain_region_and_span(cx, region) { (ref str, Some(span)) => { cx.sess.span_note( @@ -93,23 +98,23 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) } } - re_free(id, br) => { - let prefix = match br { + re_free(ref fr) => { + let prefix = match fr.bound_region { br_anon(idx) => fmt!("the anonymous lifetime #%u defined on", idx + 1), br_fresh(_) => fmt!("an anonymous lifetime defined on"), _ => fmt!("the lifetime %s as defined on", - bound_region_to_str(cx, br)) + bound_region_to_str(cx, fr.bound_region)) }; - match cx.items.find(&id) { + match cx.items.find(&fr.scope_id) { Some(&ast_map::node_block(ref blk)) => { let (msg, opt_span) = explain_span(cx, "block", blk.span); (fmt!("%s %s", prefix, msg), opt_span) } Some(_) | None => { // this really should not happen - (fmt!("%s node %d", prefix, id), None) + (fmt!("%s node %d", prefix, fr.scope_id), None) } } } @@ -210,7 +215,7 @@ pub fn region_to_str_space(cx: ctxt, prefix: &str, region: Region) -> ~str { match region { re_scope(_) => prefix.to_str(), re_bound(br) => bound_region_to_str_space(cx, prefix, br), - re_free(_, br) => bound_region_to_str_space(cx, prefix, br), + re_free(ref fr) => bound_region_to_str_space(cx, prefix, fr.bound_region), re_infer(ReSkolemized(_, br)) => { bound_region_to_str_space(cx, prefix, br) } @@ -220,12 +225,16 @@ pub fn region_to_str_space(cx: ctxt, prefix: &str, region: Region) -> ~str { } pub fn mt_to_str(cx: ctxt, m: &mt) -> ~str { + mt_to_str_wrapped(cx, "", m, "") +} + +pub fn mt_to_str_wrapped(cx: ctxt, before: &str, m: &mt, after: &str) -> ~str { let mstr = match m.mutbl { ast::m_mutbl => "mut ", ast::m_imm => "", ast::m_const => "const " }; - return fmt!("%s%s", mstr, ty_to_str(cx, m.ty)); + return fmt!("%s%s%s%s", mstr, before, ty_to_str(cx, m.ty), after); } pub fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str { @@ -239,37 +248,23 @@ pub fn vstore_to_str(cx: ctxt, vs: ty::vstore) -> ~str { pub fn trait_store_to_str(cx: ctxt, s: ty::TraitStore) -> ~str { match s { - ty::BareTraitStore => ~"", ty::UniqTraitStore => ~"~", ty::BoxTraitStore => ~"@", ty::RegionTraitStore(r) => region_to_str_space(cx, "&", r) } } -pub fn vstore_ty_to_str(cx: ctxt, ty: ~str, vs: ty::vstore) -> ~str { +pub fn vstore_ty_to_str(cx: ctxt, mt: &mt, vs: ty::vstore) -> ~str { match vs { - ty::vstore_fixed(_) => { - fmt!("[%s * %s]", ty, vstore_to_str(cx, vs)) - } - ty::vstore_slice(_) => { - fmt!("%s %s", vstore_to_str(cx, vs), ty) - } - _ => fmt!("%s[%s]", vstore_to_str(cx, vs), ty) + ty::vstore_fixed(_) => { + fmt!("[%s, .. %s]", mt_to_str(cx, mt), vstore_to_str(cx, vs)) + } + _ => { + fmt!("%s%s", vstore_to_str(cx, vs), mt_to_str_wrapped(cx, "[", mt, "]")) + } } } -pub fn expr_repr(cx: ctxt, expr: @ast::expr) -> ~str { - fmt!("expr(%d: %s)", - expr.id, - pprust::expr_to_str(expr, cx.sess.intr())) -} - -pub fn pat_repr(cx: ctxt, pat: @ast::pat) -> ~str { - fmt!("pat(%d: %s)", - pat.id, - pprust::pat_to_str(pat, cx.sess.intr())) -} - pub fn tys_to_str(cx: ctxt, ts: &[t]) -> ~str { let tstrs = ts.map(|t| ty_to_str(cx, *t)); fmt!("(%s)", str::connect(tstrs, ", ")) @@ -285,6 +280,18 @@ pub fn fn_sig_to_str(cx: ctxt, typ: &ty::FnSig) -> ~str { ty_to_str(cx, typ.output)) } +pub fn trait_ref_to_str(cx: ctxt, trait_ref: &ty::TraitRef) -> ~str { + let path = ty::item_path(cx, trait_ref.def_id); + let base = ast_map::path_to_str(path, cx.sess.intr()); + if cx.sess.verbose() && trait_ref.substs.self_ty.is_some() { + let mut all_tps = copy trait_ref.substs.tps; + for trait_ref.substs.self_ty.each |&t| { all_tps.push(t); } + parameterized(cx, base, trait_ref.substs.self_r, all_tps) + } else { + parameterized(cx, base, trait_ref.substs.self_r, trait_ref.substs.tps) + } +} + pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { fn fn_input_to_str(cx: ctxt, input: ty::arg) -> ~str { let ty::arg {mode: mode, ty: ty} = input; @@ -443,7 +450,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { str::from_bytes(~[('a' as u8) + (id as u8)])) } } - ty_self(*) => ~"self", + ty_self(*) => ~"Self", ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let path = ty::item_path(cx, did); let base = ast_map::path_to_str(path, cx.sess.intr()); @@ -456,7 +463,7 @@ pub fn ty_to_str(cx: ctxt, typ: t) -> ~str { fmt!("%s%s", trait_store_to_str(cx, s), ty) } ty_evec(ref mt, vs) => { - vstore_ty_to_str(cx, fmt!("%s", mt_to_str(cx, mt)), vs) + vstore_ty_to_str(cx, mt, vs) } ty_estr(vs) => fmt!("%s%s", vstore_to_str(cx, vs), ~"str"), ty_opaque_box => ~"@?", @@ -492,10 +499,267 @@ pub fn ty_to_short_str(cx: ctxt, typ: t) -> ~str { return s; } +impl Repr for Option { + fn repr(&self, tcx: ctxt) -> ~str { + match self { + &None => ~"None", + &Some(ref t) => fmt!("Some(%s)", t.repr(tcx)) + } + } +} + +/* +Annoyingly, these conflict with @ast::expr. + +impl Repr for @T { + fn repr(&self, tcx: ctxt) -> ~str { + (&**self).repr(tcx) + } +} + +impl Repr for ~T { + fn repr(&self, tcx: ctxt) -> ~str { + (&**self).repr(tcx) + } +} +*/ + +fn repr_vec(tcx: ctxt, v: &[T]) -> ~str { + fmt!("[%s]", str::connect(v.map(|t| t.repr(tcx)), ",")) +} + +impl<'self, T:Repr> Repr for &'self [T] { + fn repr(&self, tcx: ctxt) -> ~str { + repr_vec(tcx, *self) + } +} + +// This is necessary to handle types like Option<@~[T]>, for which +// autoderef cannot convert the &[T] handler +impl Repr for @~[T] { + fn repr(&self, tcx: ctxt) -> ~str { + repr_vec(tcx, **self) + } +} + +impl Repr for ty::TypeParameterDef { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("TypeParameterDef {%?, bounds: %s}", + self.def_id, self.bounds.repr(tcx)) + } +} + +impl Repr for ty::t { + fn repr(&self, tcx: ctxt) -> ~str { + ty_to_str(tcx, *self) + } +} + +impl Repr for ty::substs { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("substs(self_r=%s, self_ty=%s, tps=%s)", + self.self_r.repr(tcx), + self.self_ty.repr(tcx), + self.tps.repr(tcx)) + } +} + +impl Repr for ty::param_bound { + fn repr(&self, tcx: ctxt) -> ~str { + match *self { + ty::bound_copy => ~"copy", + ty::bound_durable => ~"'static", + ty::bound_owned => ~"owned", + ty::bound_const => ~"const", + ty::bound_trait(ref t) => t.repr(tcx) + } + } +} + +impl Repr for ty::TraitRef { + fn repr(&self, tcx: ctxt) -> ~str { + trait_ref_to_str(tcx, self) + } +} + +impl Repr for @ast::expr { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("expr(%d: %s)", + self.id, + pprust::expr_to_str(*self, tcx.sess.intr())) + } +} + +impl Repr for @ast::pat { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("pat(%d: %s)", + self.id, + pprust::pat_to_str(*self, tcx.sess.intr())) + } +} + +impl Repr for ty::Region { + fn repr(&self, tcx: ctxt) -> ~str { + region_to_str(tcx, *self) + } +} + +impl Repr for ast::def_id { + fn repr(&self, tcx: ctxt) -> ~str { + // Unfortunately, there seems to be no way to attempt to print + // a path for a def-id, so I'll just make a best effort for now + // and otherwise fallback to just printing the crate/node pair + if self.crate == ast::local_crate { + match tcx.items.find(&self.node) { + Some(&ast_map::node_item(*)) | + Some(&ast_map::node_foreign_item(*)) | + Some(&ast_map::node_method(*)) | + Some(&ast_map::node_trait_method(*)) | + Some(&ast_map::node_variant(*)) | + Some(&ast_map::node_struct_ctor(*)) => { + return fmt!("%?:%s", *self, ty::item_path_str(tcx, *self)); + } + _ => {} + } + } + return fmt!("%?", *self); + } +} + +impl Repr for ty::ty_param_bounds_and_ty { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("ty_param_bounds_and_ty {generics: %s, ty: %s}", + self.generics.repr(tcx), + self.ty.repr(tcx)) + } +} + +impl Repr for ty::Generics { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("Generics {type_param_defs: %s, region_param: %?}", + self.type_param_defs.repr(tcx), + self.region_param) + } +} + +impl Repr for ty::method { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("method {ident: %s, generics: %s, transformed_self_ty: %s, \ + fty: %s, self_ty: %s, vis: %s, def_id: %s}", + self.ident.repr(tcx), + self.generics.repr(tcx), + self.transformed_self_ty.repr(tcx), + self.fty.repr(tcx), + self.self_ty.repr(tcx), + self.vis.repr(tcx), + self.def_id.repr(tcx)) + } +} + +impl Repr for ast::ident { + fn repr(&self, tcx: ctxt) -> ~str { + copy *tcx.sess.intr().get(*self) + } +} + +impl Repr for ast::self_ty_ { + fn repr(&self, _tcx: ctxt) -> ~str { + fmt!("%?", *self) + } +} + +impl Repr for ast::visibility { + fn repr(&self, _tcx: ctxt) -> ~str { + fmt!("%?", *self) + } +} + +impl Repr for ty::BareFnTy { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("BareFnTy {purity: %?, abis: %s, sig: %s}", + self.purity, + self.abis.to_str(), + self.sig.repr(tcx)) + } +} + +impl Repr for ty::FnSig { + fn repr(&self, tcx: ctxt) -> ~str { + fn_sig_to_str(tcx, self) + } +} + +impl Repr for typeck::method_map_entry { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("method_map_entry {self_arg: %s, \ + explicit_self: %s, \ + origin: %s}", + self.self_arg.repr(tcx), + self.explicit_self.repr(tcx), + self.origin.repr(tcx)) + } +} + +impl Repr for ty::arg { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("%?(%s)", self.mode, self.ty.repr(tcx)) + } +} + +impl Repr for typeck::method_origin { + fn repr(&self, tcx: ctxt) -> ~str { + match self { + &typeck::method_super(def_id, n) => { + fmt!("method_super(%s, %?)", + def_id.repr(tcx), n) + } + &typeck::method_static(def_id) => { + fmt!("method_static(%s)", def_id.repr(tcx)) + } + &typeck::method_param(ref p) => { + p.repr(tcx) + } + &typeck::method_trait(def_id, n, st) => { + fmt!("method_trait(%s, %?, %s)", def_id.repr(tcx), n, + st.repr(tcx)) + } + &typeck::method_self(def_id, n) => { + fmt!("method_self(%s, %?)", def_id.repr(tcx), n) + } + } + } +} + +impl Repr for typeck::method_param { + fn repr(&self, tcx: ctxt) -> ~str { + fmt!("method_param(%s,%?,%?,%?)", + self.trait_id.repr(tcx), + self.method_num, + self.param_num, + self.bound_num) + } +} + +impl Repr for ty::TraitStore { + fn repr(&self, tcx: ctxt) -> ~str { + match self { + &ty::BoxTraitStore => ~"@Trait", + &ty::UniqTraitStore => ~"~Trait", + &ty::RegionTraitStore(r) => fmt!("&%s Trait", r.repr(tcx)) + } + } +} + +impl Repr for ty::vstore { + fn repr(&self, tcx: ctxt) -> ~str { + vstore_to_str(tcx, *self) + } +} + // Local Variables: // mode: rust // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix -// End: +// End diff --git a/src/librustdoc/attr_parser.rs b/src/librustdoc/attr_parser.rs index 213198e6f2158..efd061209a503 100644 --- a/src/librustdoc/attr_parser.rs +++ b/src/librustdoc/attr_parser.rs @@ -25,26 +25,6 @@ pub struct CrateAttrs { name: Option<~str> } -#[cfg(test)] -mod test { - use syntax::ast; - use syntax; - - use core::option::None; - - pub fn parse_attributes(source: ~str) -> ~[ast::attribute] { - use syntax::parse; - use syntax::parse::attr::parser_attr; - use syntax::codemap; - - let parse_sess = syntax::parse::new_parse_sess(None); - let parser = parse::new_parser_from_source_str( - parse_sess, ~[], ~"-", codemap::FssNone, @source); - - parser.parse_outer_attributes() - } -} - fn doc_metas( attrs: ~[ast::attribute] ) -> ~[@ast::meta_item] { @@ -66,30 +46,6 @@ pub fn parse_crate(attrs: ~[ast::attribute]) -> CrateAttrs { } } -#[test] -fn should_extract_crate_name_from_link_attribute() { - let source = ~"#[link(name = \"snuggles\")]"; - let attrs = test::parse_attributes(source); - let attrs = parse_crate(attrs); - assert!(attrs.name == Some(~"snuggles")); -} - -#[test] -fn should_not_extract_crate_name_if_no_link_attribute() { - let source = ~""; - let attrs = test::parse_attributes(source); - let attrs = parse_crate(attrs); - assert!(attrs.name == None); -} - -#[test] -fn should_not_extract_crate_name_if_no_name_value_in_link_attribute() { - let source = ~"#[link(whatever)]"; - let attrs = test::parse_attributes(source); - let attrs = parse_crate(attrs); - assert!(attrs.name == None); -} - pub fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> { let doc_strs = do doc_metas(attrs).filter_mapped |meta| { attr::get_meta_item_value_str(*meta).map(|s| copy **s) @@ -101,60 +57,103 @@ pub fn parse_desc(attrs: ~[ast::attribute]) -> Option<~str> { } } -#[test] -fn parse_desc_should_handle_undocumented_mods() { - let source = ~""; - let attrs = test::parse_attributes(source); - let attrs = parse_desc(attrs); - assert!(attrs == None); -} - -#[test] -fn parse_desc_should_parse_simple_doc_attributes() { - let source = ~"#[doc = \"basic\"]"; - let attrs = test::parse_attributes(source); - let attrs = parse_desc(attrs); - assert!(attrs == Some(~"basic")); -} - pub fn parse_hidden(attrs: ~[ast::attribute]) -> bool { do doc_metas(attrs).find |meta| { match attr::get_meta_item_list(*meta) { - Some(metas) => { - let hiddens = attr::find_meta_items_by_name(metas, ~"hidden"); - !hiddens.is_empty() - } - None => false + Some(metas) => { + let hiddens = attr::find_meta_items_by_name(metas, ~"hidden"); + !hiddens.is_empty() + } + None => false } }.is_some() } -#[test] -fn should_parse_hidden_attribute() { - let source = ~"#[doc(hidden)]"; - let attrs = test::parse_attributes(source); - assert!(parse_hidden(attrs) == true); -} +#[cfg(test)] +mod test { + use syntax::ast; + use syntax; + use super::{parse_hidden, parse_crate, parse_desc}; + use core::prelude::*; -#[test] -fn should_parse_hidden_attribute_with_other_docs() { - let source = ~"#[doc = \"foo\"] #[doc(hidden)] #[doc = \"foo\"]"; - let attrs = test::parse_attributes(source); - assert!(parse_hidden(attrs) == true); -} + fn parse_attributes(source: ~str) -> ~[ast::attribute] { + use syntax::parse; + use syntax::parse::attr::parser_attr; + use syntax::codemap; -#[test] -fn should_not_parse_non_hidden_attribute() { - let source = ~"#[doc = \"\"]"; - let attrs = test::parse_attributes(source); - assert!(parse_hidden(attrs) == false); -} + let parse_sess = syntax::parse::new_parse_sess(None); + let parser = parse::new_parser_from_source_str( + parse_sess, ~[], ~"-", codemap::FssNone, @source); + + parser.parse_outer_attributes() + } -#[test] -fn should_concatenate_multiple_doc_comments() { - let source = ~"/// foo\n/// bar"; - let desc = parse_desc(test::parse_attributes(source)); - assert!(desc == Some(~"foo\nbar")); -} + #[test] + fn should_extract_crate_name_from_link_attribute() { + let source = ~"#[link(name = \"snuggles\")]"; + let attrs = parse_attributes(source); + let attrs = parse_crate(attrs); + assert!(attrs.name == Some(~"snuggles")); + } + #[test] + fn should_not_extract_crate_name_if_no_link_attribute() { + let source = ~""; + let attrs = parse_attributes(source); + let attrs = parse_crate(attrs); + assert!(attrs.name == None); + } + + #[test] + fn should_not_extract_crate_name_if_no_name_value_in_link_attribute() { + let source = ~"#[link(whatever)]"; + let attrs = parse_attributes(source); + let attrs = parse_crate(attrs); + assert!(attrs.name == None); + } + + #[test] + fn parse_desc_should_handle_undocumented_mods() { + let source = ~""; + let attrs = parse_attributes(source); + let attrs = parse_desc(attrs); + assert!(attrs == None); + } + + #[test] + fn parse_desc_should_parse_simple_doc_attributes() { + let source = ~"#[doc = \"basic\"]"; + let attrs = parse_attributes(source); + let attrs = parse_desc(attrs); + assert!(attrs == Some(~"basic")); + } + + #[test] + fn should_parse_hidden_attribute() { + let source = ~"#[doc(hidden)]"; + let attrs = parse_attributes(source); + assert!(parse_hidden(attrs) == true); + } + + #[test] + fn should_parse_hidden_attribute_with_other_docs() { + let source = ~"#[doc = \"foo\"] #[doc(hidden)] #[doc = \"foo\"]"; + let attrs = parse_attributes(source); + assert!(parse_hidden(attrs) == true); + } + + #[test] + fn should_not_parse_non_hidden_attribute() { + let source = ~"#[doc = \"\"]"; + let attrs = parse_attributes(source); + assert!(parse_hidden(attrs) == false); + } + + #[test] + fn should_concatenate_multiple_doc_comments() { + let source = ~"/// foo\n/// bar"; + let desc = parse_desc(parse_attributes(source)); + assert!(desc == Some(~"foo\nbar")); + } +} diff --git a/src/librustdoc/attr_pass.rs b/src/librustdoc/attr_pass.rs index b550155140f0b..a666bff18c97c 100644 --- a/src/librustdoc/attr_pass.rs +++ b/src/librustdoc/attr_pass.rs @@ -78,12 +78,6 @@ fn fold_crate( } } -#[test] -fn should_replace_top_module_name_with_crate_name() { - let doc = test::mk_doc(~"#[link(name = \"bond\")];"); - assert!(doc.cratemod().name() == ~"bond"); -} - fn fold_item( fold: &fold::Fold, doc: doc::ItemDoc @@ -113,38 +107,14 @@ fn parse_item_attrs( parse_attrs: ~fn(a: ~[ast::attribute]) -> T) -> T { do astsrv::exec(srv) |ctxt| { let attrs = match *ctxt.ast_map.get(&id) { - ast_map::node_item(item, _) => copy item.attrs, - ast_map::node_foreign_item(item, _, _, _) => copy item.attrs, - _ => fail!(~"parse_item_attrs: not an item") + ast_map::node_item(item, _) => copy item.attrs, + ast_map::node_foreign_item(item, _, _, _) => copy item.attrs, + _ => fail!(~"parse_item_attrs: not an item") }; parse_attrs(attrs) } } -#[test] -fn should_should_extract_mod_attributes() { - let doc = test::mk_doc(~"#[doc = \"test\"] mod a { }"); - assert!(doc.cratemod().mods()[0].desc() == Some(~"test")); -} - -#[test] -fn should_extract_top_mod_attributes() { - let doc = test::mk_doc(~"#[doc = \"test\"];"); - assert!(doc.cratemod().desc() == Some(~"test")); -} - -#[test] -fn should_extract_foreign_fn_attributes() { - let doc = test::mk_doc(~"extern { #[doc = \"test\"] fn a(); }"); - assert!(doc.cratemod().nmods()[0].fns[0].desc() == Some(~"test")); -} - -#[test] -fn should_extract_fn_attributes() { - let doc = test::mk_doc(~"#[doc = \"test\"] fn a() -> int { }"); - assert!(doc.cratemod().fns()[0].desc() == Some(~"test")); -} - fn fold_enum( fold: &fold::Fold, doc: doc::EnumDoc @@ -174,8 +144,8 @@ fn fold_enum( } _ => { fail!(fmt!("Enum variant %s has id that's \ - not bound to an enum item", - variant.name)) + not bound to an enum item", + variant.name)) } } } @@ -190,19 +160,6 @@ fn fold_enum( } } -#[test] -fn should_extract_enum_docs() { - let doc = test::mk_doc(~"#[doc = \"b\"]\ - enum a { v }"); - assert!(doc.cratemod().enums()[0].desc() == Some(~"b")); -} - -#[test] -fn should_extract_variant_docs() { - let doc = test::mk_doc(~"enum a { #[doc = \"c\"] v }"); - assert!(doc.cratemod().enums()[0].variants[0].desc == Some(~"c")); -} - fn fold_trait( fold: &fold::Fold, doc: doc::TraitDoc @@ -225,30 +182,30 @@ fn merge_method_attrs( // Create an assoc list from method name to attributes let attrs: ~[(~str, Option<~str>)] = do astsrv::exec(srv) |ctxt| { match *ctxt.ast_map.get(&item_id) { - ast_map::node_item(@ast::item { - node: ast::item_trait(_, _, ref methods), _ - }, _) => { - vec::map(*methods, |method| { - match copy *method { - ast::required(ty_m) => { - (to_str(ty_m.ident), - attr_parser::parse_desc(copy ty_m.attrs)) - } - ast::provided(m) => { - (to_str(m.ident), attr_parser::parse_desc(copy m.attrs)) - } - } - }) - } - ast_map::node_item(@ast::item { - node: ast::item_impl(_, _, _, ref methods), _ - }, _) => { - vec::map(*methods, |method| { - (to_str(method.ident), - attr_parser::parse_desc(copy method.attrs)) - }) - } - _ => fail!(~"unexpected item") + ast_map::node_item(@ast::item { + node: ast::item_trait(_, _, ref methods), _ + }, _) => { + vec::map(*methods, |method| { + match copy *method { + ast::required(ty_m) => { + (to_str(ty_m.ident), + attr_parser::parse_desc(copy ty_m.attrs)) + } + ast::provided(m) => { + (to_str(m.ident), attr_parser::parse_desc(copy m.attrs)) + } + } + }) + } + ast_map::node_item(@ast::item { + node: ast::item_impl(_, _, _, ref methods), _ + }, _) => { + vec::map(*methods, |method| { + (to_str(method.ident), + attr_parser::parse_desc(copy method.attrs)) + }) + } + _ => fail!(~"unexpected item") } }; @@ -263,22 +220,6 @@ fn merge_method_attrs( } } -#[test] -fn should_extract_trait_docs() { - let doc = test::mk_doc(~"#[doc = \"whatever\"] trait i { fn a(); }"); - assert!(doc.cratemod().traits()[0].desc() == Some(~"whatever")); -} - -#[test] -fn should_extract_trait_method_docs() { - let doc = test::mk_doc( - ~"trait i {\ - #[doc = \"desc\"]\ - fn f(a: bool) -> bool;\ - }"); - assert!(doc.cratemod().traits()[0].methods[0].desc == Some(~"desc")); -} - fn fold_impl( fold: &fold::Fold, @@ -293,34 +234,94 @@ fn fold_impl( } } -#[test] -fn should_extract_impl_docs() { - let doc = test::mk_doc( - ~"#[doc = \"whatever\"] impl int { fn a() { } }"); - assert!(doc.cratemod().impls()[0].desc() == Some(~"whatever")); -} - -#[test] -fn should_extract_impl_method_docs() { - let doc = test::mk_doc( - ~"impl int {\ - #[doc = \"desc\"]\ - fn f(a: bool) -> bool { }\ - }"); - assert!(doc.cratemod().impls()[0].methods[0].desc == Some(~"desc")); -} - #[cfg(test)] mod test { use astsrv; use attr_pass::run; use doc; use extract; + use core::prelude::*; - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { do astsrv::from_str(copy source) |srv| { let doc = extract::from_srv(srv.clone(), ~""); run(srv.clone(), doc) } } + + #[test] + fn should_replace_top_module_name_with_crate_name() { + let doc = mk_doc(~"#[link(name = \"bond\")];"); + assert!(doc.cratemod().name() == ~"bond"); + } + + #[test] + fn should_should_extract_mod_attributes() { + let doc = mk_doc(~"#[doc = \"test\"] mod a { }"); + assert!(doc.cratemod().mods()[0].desc() == Some(~"test")); + } + + #[test] + fn should_extract_top_mod_attributes() { + let doc = mk_doc(~"#[doc = \"test\"];"); + assert!(doc.cratemod().desc() == Some(~"test")); + } + + #[test] + fn should_extract_foreign_fn_attributes() { + let doc = mk_doc(~"extern { #[doc = \"test\"] fn a(); }"); + assert!(doc.cratemod().nmods()[0].fns[0].desc() == Some(~"test")); + } + + #[test] + fn should_extract_fn_attributes() { + let doc = mk_doc(~"#[doc = \"test\"] fn a() -> int { }"); + assert!(doc.cratemod().fns()[0].desc() == Some(~"test")); + } + + #[test] + fn should_extract_enum_docs() { + let doc = mk_doc(~"#[doc = \"b\"]\ + enum a { v }"); + assert!(doc.cratemod().enums()[0].desc() == Some(~"b")); + } + + #[test] + fn should_extract_variant_docs() { + let doc = mk_doc(~"enum a { #[doc = \"c\"] v }"); + assert!(doc.cratemod().enums()[0].variants[0].desc == Some(~"c")); + } + + #[test] + fn should_extract_trait_docs() { + let doc = mk_doc(~"#[doc = \"whatever\"] trait i { fn a(); }"); + assert!(doc.cratemod().traits()[0].desc() == Some(~"whatever")); + } + + #[test] + fn should_extract_trait_method_docs() { + let doc = mk_doc( + ~"trait i {\ + #[doc = \"desc\"]\ + fn f(a: bool) -> bool;\ + }"); + assert!(doc.cratemod().traits()[0].methods[0].desc == Some(~"desc")); + } + + #[test] + fn should_extract_impl_docs() { + let doc = mk_doc( + ~"#[doc = \"whatever\"] impl int { fn a() { } }"); + assert!(doc.cratemod().impls()[0].desc() == Some(~"whatever")); + } + + #[test] + fn should_extract_impl_method_docs() { + let doc = mk_doc( + ~"impl int {\ + #[doc = \"desc\"]\ + fn f(a: bool) -> bool { }\ + }"); + assert!(doc.cratemod().impls()[0].methods[0].desc == Some(~"desc")); + } } diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 62ddec7a1199c..ed1a54c49a731 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -209,7 +209,7 @@ fn parse_output_style(output_style: &str) -> Result { } } -fn maybe_find_pandoc( +pub fn maybe_find_pandoc( config: &Config, maybe_pandoc_cmd: Option<~str>, program_output: Process @@ -243,140 +243,140 @@ fn maybe_find_pandoc( } } -#[test] -fn should_find_pandoc() { - let config = Config { - output_format: PandocHtml, - .. default_config(&Path("test")) - }; - let mock_program_output: ~fn(&str, &[~str]) -> ProgramOutput = |_, _| { - ProgramOutput { status: 0, out: ~"pandoc 1.8.2.1", err: ~"" } - }; - let result = maybe_find_pandoc(&config, None, mock_program_output); - assert!(result == result::Ok(Some(~"pandoc"))); -} - -#[test] -fn should_error_with_no_pandoc() { - let config = Config { - output_format: PandocHtml, - .. default_config(&Path("test")) - }; - let mock_program_output: ~fn(&str, &[~str]) -> ProgramOutput = |_, _| { - ProgramOutput { status: 1, out: ~"", err: ~"" } - }; - let result = maybe_find_pandoc(&config, None, mock_program_output); - assert!(result == result::Err(~"couldn't find pandoc")); -} - #[cfg(test)] mod test { - use config::{Config, mock_program_output, parse_config_}; - - use core::result::Result; + use config::*; + use core::prelude::*; + use core::run::ProgramOutput; - pub fn parse_config(args: &[~str]) -> Result { + fn parse_config(args: &[~str]) -> Result { parse_config_(args, mock_program_output) } -} -#[test] -fn should_error_with_no_crates() { - let config = test::parse_config(~[~"rustdoc"]); - assert!(config.get_err() == ~"no crates specified"); -} + #[test] + fn should_find_pandoc() { + let config = Config { + output_format: PandocHtml, + .. default_config(&Path("test")) + }; + let mock_program_output: ~fn(&str, &[~str]) -> ProgramOutput = |_, _| { + ProgramOutput { status: 0, out: ~"pandoc 1.8.2.1", err: ~"" } + }; + let result = maybe_find_pandoc(&config, None, mock_program_output); + assert!(result == result::Ok(Some(~"pandoc"))); + } -#[test] -fn should_error_with_multiple_crates() { - let config = - test::parse_config(~[~"rustdoc", ~"crate1.rc", ~"crate2.rc"]); - assert!(config.get_err() == ~"multiple crates specified"); -} + #[test] + fn should_error_with_no_pandoc() { + let config = Config { + output_format: PandocHtml, + .. default_config(&Path("test")) + }; + let mock_program_output: ~fn(&str, &[~str]) -> ProgramOutput = |_, _| { + ProgramOutput { status: 1, out: ~"", err: ~"" } + }; + let result = maybe_find_pandoc(&config, None, mock_program_output); + assert!(result == result::Err(~"couldn't find pandoc")); + } -#[test] -fn should_set_output_dir_to_cwd_if_not_provided() { - let config = test::parse_config(~[~"rustdoc", ~"crate.rc"]); - assert!(config.get().output_dir == Path(".")); -} + #[test] + fn should_error_with_no_crates() { + let config = parse_config(~[~"rustdoc"]); + assert!(config.get_err() == ~"no crates specified"); + } -#[test] -fn should_set_output_dir_if_provided() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--output-dir", ~"snuggles" - ]); - assert!(config.get().output_dir == Path("snuggles")); -} + #[test] + fn should_error_with_multiple_crates() { + let config = + parse_config(~[~"rustdoc", ~"crate1.rc", ~"crate2.rc"]); + assert!(config.get_err() == ~"multiple crates specified"); + } -#[test] -fn should_set_output_format_to_pandoc_html_if_not_provided() { - let config = test::parse_config(~[~"rustdoc", ~"crate.rc"]); - assert!(config.get().output_format == PandocHtml); -} + #[test] + fn should_set_output_dir_to_cwd_if_not_provided() { + let config = parse_config(~[~"rustdoc", ~"crate.rc"]); + assert!(config.get().output_dir == Path(".")); + } -#[test] -fn should_set_output_format_to_markdown_if_requested() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--output-format", ~"markdown" - ]); - assert!(config.get().output_format == Markdown); -} + #[test] + fn should_set_output_dir_if_provided() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--output-dir", ~"snuggles" + ]); + assert!(config.get().output_dir == Path("snuggles")); + } -#[test] -fn should_set_output_format_to_pandoc_html_if_requested() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--output-format", ~"html" - ]); - assert!(config.get().output_format == PandocHtml); -} + #[test] + fn should_set_output_format_to_pandoc_html_if_not_provided() { + let config = parse_config(~[~"rustdoc", ~"crate.rc"]); + assert!(config.get().output_format == PandocHtml); + } -#[test] -fn should_error_on_bogus_format() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--output-format", ~"bogus" - ]); - assert!(config.get_err() == ~"unknown output format 'bogus'"); -} + #[test] + fn should_set_output_format_to_markdown_if_requested() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--output-format", ~"markdown" + ]); + assert!(config.get().output_format == Markdown); + } -#[test] -fn should_set_output_style_to_doc_per_mod_by_default() { - let config = test::parse_config(~[~"rustdoc", ~"crate.rc"]); - assert!(config.get().output_style == DocPerMod); -} + #[test] + fn should_set_output_format_to_pandoc_html_if_requested() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--output-format", ~"html" + ]); + assert!(config.get().output_format == PandocHtml); + } -#[test] -fn should_set_output_style_to_one_doc_if_requested() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--output-style", ~"doc-per-crate" - ]); - assert!(config.get().output_style == DocPerCrate); -} + #[test] + fn should_error_on_bogus_format() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--output-format", ~"bogus" + ]); + assert!(config.get_err() == ~"unknown output format 'bogus'"); + } -#[test] -fn should_set_output_style_to_doc_per_mod_if_requested() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--output-style", ~"doc-per-mod" - ]); - assert!(config.get().output_style == DocPerMod); -} + #[test] + fn should_set_output_style_to_doc_per_mod_by_default() { + let config = parse_config(~[~"rustdoc", ~"crate.rc"]); + assert!(config.get().output_style == DocPerMod); + } -#[test] -fn should_error_on_bogus_output_style() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--output-style", ~"bogus" - ]); - assert!(config.get_err() == ~"unknown output style 'bogus'"); -} + #[test] + fn should_set_output_style_to_one_doc_if_requested() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--output-style", ~"doc-per-crate" + ]); + assert!(config.get().output_style == DocPerCrate); + } -#[test] -fn should_set_pandoc_command_if_requested() { - let config = test::parse_config(~[ - ~"rustdoc", ~"crate.rc", ~"--pandoc-cmd", ~"panda-bear-doc" - ]); - assert!(config.get().pandoc_cmd == Some(~"panda-bear-doc")); -} + #[test] + fn should_set_output_style_to_doc_per_mod_if_requested() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--output-style", ~"doc-per-mod" + ]); + assert!(config.get().output_style == DocPerMod); + } -#[test] -fn should_set_pandoc_command_when_using_pandoc() { - let config = test::parse_config(~[~"rustdoc", ~"crate.rc"]); - assert!(config.get().pandoc_cmd == Some(~"pandoc")); -} + #[test] + fn should_error_on_bogus_output_style() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--output-style", ~"bogus" + ]); + assert!(config.get_err() == ~"unknown output style 'bogus'"); + } + + #[test] + fn should_set_pandoc_command_if_requested() { + let config = parse_config(~[ + ~"rustdoc", ~"crate.rc", ~"--pandoc-cmd", ~"panda-bear-doc" + ]); + assert!(config.get().pandoc_cmd == Some(~"panda-bear-doc")); + } + + #[test] + fn should_set_pandoc_command_when_using_pandoc() { + let config = parse_config(~[~"rustdoc", ~"crate.rc"]); + assert!(config.get().pandoc_cmd == Some(~"pandoc")); + } +} \ No newline at end of file diff --git a/src/librustdoc/desc_to_brief_pass.rs b/src/librustdoc/desc_to_brief_pass.rs index 7c50af40f337a..5027b24435599 100644 --- a/src/librustdoc/desc_to_brief_pass.rs +++ b/src/librustdoc/desc_to_brief_pass.rs @@ -81,44 +81,7 @@ fn fold_impl(fold: &fold::Fold<()>, doc: doc::ImplDoc) -> doc::ImplDoc { } } -#[test] -fn should_promote_desc() { - let doc = test::mk_doc(~"#[doc = \"desc\"] mod m { }"); - assert!(doc.cratemod().mods()[0].brief() == Some(~"desc")); -} - -#[test] -fn should_promote_trait_method_desc() { - let doc = test::mk_doc(~"trait i { #[doc = \"desc\"] fn a(); }"); - assert!(doc.cratemod().traits()[0].methods[0].brief == - Some(~"desc")); -} - -#[test] -fn should_promote_impl_method_desc() { - let doc = test::mk_doc( - ~"impl int { #[doc = \"desc\"] fn a() { } }"); - assert!(doc.cratemod().impls()[0].methods[0].brief == Some(~"desc")); -} - -#[cfg(test)] -pub mod test { - use astsrv; - use attr_pass; - use desc_to_brief_pass::run; - use doc; - use extract; - - pub fn mk_doc(source: ~str) -> doc::Doc { - do astsrv::from_str(copy source) |srv| { - let doc = extract::from_srv(srv.clone(), ~""); - let doc = (attr_pass::mk_pass().f)(srv.clone(), doc); - run(srv.clone(), doc) - } - } -} - -fn extract(desc: Option<~str>) -> Option<~str> { +pub fn extract(desc: Option<~str>) -> Option<~str> { if desc.is_none() { return None } @@ -182,7 +145,7 @@ fn first_sentence_(s: &str) -> ~str { } } -fn paragraphs(s: &str) -> ~[~str] { +pub fn paragraphs(s: &str) -> ~[~str] { let mut lines = ~[]; for str::each_line_any(s) |line| { lines.push(line.to_owned()); } let mut whitespace_lines = 0; @@ -219,28 +182,65 @@ fn paragraphs(s: &str) -> ~[~str] { } } -#[test] -fn test_paragraphs_1() { - let paras = paragraphs(~"1\n\n2"); - assert!(paras == ~[~"1", ~"2"]); -} +#[cfg(test)] +mod test { + use astsrv; + use attr_pass; + use super::{extract, paragraphs, run}; + use doc; + use extract; + use core::prelude::*; -#[test] -fn test_paragraphs_2() { - let paras = paragraphs(~"\n\n1\n1\n\n2\n\n"); - assert!(paras == ~[~"1\n1", ~"2"]); -} + fn mk_doc(source: ~str) -> doc::Doc { + do astsrv::from_str(copy source) |srv| { + let doc = extract::from_srv(srv.clone(), ~""); + let doc = (attr_pass::mk_pass().f)(srv.clone(), doc); + run(srv.clone(), doc) + } + } -#[test] -fn should_promote_short_descs() { - let desc = Some(~"desc"); - let brief = extract(copy desc); - assert!(brief == desc); -} + #[test] + fn should_promote_desc() { + let doc = mk_doc(~"#[doc = \"desc\"] mod m { }"); + assert!(doc.cratemod().mods()[0].brief() == Some(~"desc")); + } + + #[test] + fn should_promote_trait_method_desc() { + let doc = mk_doc(~"trait i { #[doc = \"desc\"] fn a(); }"); + assert!(doc.cratemod().traits()[0].methods[0].brief == + Some(~"desc")); + } + + #[test] + fn should_promote_impl_method_desc() { + let doc = mk_doc( + ~"impl int { #[doc = \"desc\"] fn a() { } }"); + assert!(doc.cratemod().impls()[0].methods[0].brief == Some(~"desc")); + } -#[test] -fn should_not_promote_long_descs() { - let desc = Some(~"Warkworth Castle is a ruined medieval building + #[test] + fn test_paragraphs_1() { + let paras = paragraphs(~"1\n\n2"); + assert!(paras == ~[~"1", ~"2"]); + } + + #[test] + fn test_paragraphs_2() { + let paras = paragraphs(~"\n\n1\n1\n\n2\n\n"); + assert!(paras == ~[~"1\n1", ~"2"]); + } + + #[test] + fn should_promote_short_descs() { + let desc = Some(~"desc"); + let brief = extract(copy desc); + assert!(brief == desc); + } + + #[test] + fn should_not_promote_long_descs() { + let desc = Some(~"Warkworth Castle is a ruined medieval building in the town of the same name in the English county of Northumberland, and the town and castle occupy a loop of the River Coquet, less than a mile from England's north-east coast. When the castle was founded is uncertain, @@ -248,13 +248,13 @@ but traditionally its construction has been ascribed to Prince Henry of Scotland in the mid 12th century, although it may have been built by King Henry II of England when he took control of England'snorthern counties."); - let brief = extract(desc); - assert!(brief == None); -} + let brief = extract(desc); + assert!(brief == None); + } -#[test] -fn should_promote_first_sentence() { - let desc = Some(~"Warkworth Castle is a ruined medieval building + #[test] + fn should_promote_first_sentence() { + let desc = Some(~"Warkworth Castle is a ruined medieval building in the town. of the same name in the English county of Northumberland, and the town and castle occupy a loop of the River Coquet, less than a mile from England's north-east coast. When the castle was founded is uncertain, @@ -262,14 +262,14 @@ but traditionally its construction has been ascribed to Prince Henry of Scotland in the mid 12th century, although it may have been built by King Henry II of England when he took control of England'snorthern counties."); - let brief = extract(desc); - assert!(brief == Some( - ~"Warkworth Castle is a ruined medieval building in the town")); -} + let brief = extract(desc); + assert!(brief == Some( + ~"Warkworth Castle is a ruined medieval building in the town")); + } -#[test] -fn should_not_consider_double_period_to_end_sentence() { - let desc = Some(~"Warkworth..Castle is a ruined medieval building + #[test] + fn should_not_consider_double_period_to_end_sentence() { + let desc = Some(~"Warkworth..Castle is a ruined medieval building in the town. of the same name in the English county of Northumberland, and the town and castle occupy a loop of the River Coquet, less than a mile from England's north-east coast. When the castle was founded is uncertain, @@ -277,14 +277,14 @@ but traditionally its construction has been ascribed to Prince Henry of Scotland in the mid 12th century, although it may have been built by King Henry II of England when he took control of England'snorthern counties."); - let brief = extract(desc); - assert!(brief == Some( - ~"Warkworth..Castle is a ruined medieval building in the town")); -} + let brief = extract(desc); + assert!(brief == Some( + ~"Warkworth..Castle is a ruined medieval building in the town")); + } -#[test] -fn should_not_consider_triple_period_to_end_sentence() { - let desc = Some(~"Warkworth... Castle is a ruined medieval building + #[test] + fn should_not_consider_triple_period_to_end_sentence() { + let desc = Some(~"Warkworth... Castle is a ruined medieval building in the town. of the same name in the English county of Northumberland, and the town and castle occupy a loop of the River Coquet, less than a mile from England's north-east coast. When the castle was founded is uncertain, @@ -292,7 +292,8 @@ but traditionally its construction has been ascribed to Prince Henry of Scotland in the mid 12th century, although it may have been built by King Henry II of England when he took control of England'snorthern counties."); - let brief = extract(desc); - assert!(brief == Some( - ~"Warkworth... Castle is a ruined medieval building in the town")); + let brief = extract(desc); + assert!(brief == Some( + ~"Warkworth... Castle is a ruined medieval building in the town")); + } } diff --git a/src/librustdoc/extract.rs b/src/librustdoc/extract.rs index 1d6d569e1c29d..fa3f7d6432489 100644 --- a/src/librustdoc/extract.rs +++ b/src/librustdoc/extract.rs @@ -182,13 +182,6 @@ fn constdoc_from_const(itemdoc: doc::ItemDoc) -> doc::ConstDoc { } } -#[test] -fn should_extract_const_name_and_id() { - let doc = test::mk_doc(~"static a: int = 0;"); - assert!(doc.cratemod().consts()[0].id() != 0); - assert!(doc.cratemod().consts()[0].name() == ~"a"); -} - fn enumdoc_from_enum( itemdoc: doc::ItemDoc, variants: ~[ast::variant] @@ -213,19 +206,6 @@ fn variantdoc_from_variant(variant: &ast::variant) -> doc::VariantDoc { } } -#[test] -fn should_extract_enums() { - let doc = test::mk_doc(~"enum e { v }"); - assert!(doc.cratemod().enums()[0].id() != 0); - assert!(doc.cratemod().enums()[0].name() == ~"e"); -} - -#[test] -fn should_extract_enum_variants() { - let doc = test::mk_doc(~"enum e { v }"); - assert!(doc.cratemod().enums()[0].variants[0].name == ~"v"); -} - fn traitdoc_from_trait( itemdoc: doc::ItemDoc, methods: ~[ast::trait_method] @@ -259,18 +239,6 @@ fn traitdoc_from_trait( } } -#[test] -fn should_extract_traits() { - let doc = test::mk_doc(~"trait i { fn f(); }"); - assert!(doc.cratemod().traits()[0].name() == ~"i"); -} - -#[test] -fn should_extract_trait_methods() { - let doc = test::mk_doc(~"trait i { fn f(); }"); - assert!(doc.cratemod().traits()[0].methods[0].name == ~"f"); -} - fn impldoc_from_impl( itemdoc: doc::ItemDoc, methods: ~[@ast::method] @@ -293,12 +261,6 @@ fn impldoc_from_impl( } } -#[test] -fn should_extract_impl_methods() { - let doc = test::mk_doc(~"impl int { fn f() { } }"); - assert!(doc.cratemod().impls()[0].methods[0].name == ~"f"); -} - fn tydoc_from_ty( itemdoc: doc::ItemDoc ) -> doc::TyDoc { @@ -308,12 +270,6 @@ fn tydoc_from_ty( } } -#[test] -fn should_extract_tys() { - let doc = test::mk_doc(~"type a = int;"); - assert!(doc.cratemod().types()[0].name() == ~"a"); -} - fn structdoc_from_struct( itemdoc: doc::ItemDoc, struct_def: @ast::struct_def @@ -330,18 +286,6 @@ fn structdoc_from_struct( } } -#[test] -fn should_extract_structs() { - let doc = test::mk_doc(~"struct Foo { field: () }"); - assert!(doc.cratemod().structs()[0].name() == ~"Foo"); -} - -#[test] -fn should_extract_struct_fields() { - let doc = test::mk_doc(~"struct Foo { field: () }"); - assert!(doc.cratemod().structs()[0].fields[0] == ~"field"); -} - #[cfg(test)] mod test { use astsrv; @@ -351,20 +295,20 @@ mod test { use core::vec; - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { let ast = parse::from_str(source); extract(ast, ~"") } #[test] - pub fn extract_empty_crate() { + fn extract_empty_crate() { let doc = mk_doc(~""); assert!(vec::is_empty(doc.cratemod().mods())); assert!(vec::is_empty(doc.cratemod().fns())); } #[test] - pub fn extract_mods() { + fn extract_mods() { let doc = mk_doc(~"mod a { mod b { } mod c { } }"); assert!(doc.cratemod().mods()[0].name() == ~"a"); assert!(doc.cratemod().mods()[0].mods()[0].name() == ~"b"); @@ -372,26 +316,26 @@ mod test { } #[test] - pub fn extract_fns_from_foreign_mods() { + fn extract_fns_from_foreign_mods() { let doc = mk_doc(~"extern { fn a(); }"); assert!(doc.cratemod().nmods()[0].fns[0].name() == ~"a"); } #[test] - pub fn extract_mods_deep() { + fn extract_mods_deep() { let doc = mk_doc(~"mod a { mod b { mod c { } } }"); assert!(doc.cratemod().mods()[0].mods()[0].mods()[0].name() == ~"c"); } #[test] - pub fn extract_should_set_mod_ast_id() { + fn extract_should_set_mod_ast_id() { let doc = mk_doc(~"mod a { }"); assert!(doc.cratemod().mods()[0].id() != 0); } #[test] - pub fn extract_fns() { + fn extract_fns() { let doc = mk_doc( ~"fn a() { } \ mod b { fn c() { @@ -401,13 +345,13 @@ mod test { } #[test] - pub fn extract_should_set_fn_ast_id() { + fn extract_should_set_fn_ast_id() { let doc = mk_doc(~"fn a() { }"); assert!(doc.cratemod().fns()[0].id() != 0); } #[test] - pub fn extract_should_use_default_crate_name() { + fn extract_should_use_default_crate_name() { let source = ~""; let ast = parse::from_str(source); let doc = extract(ast, ~"burp"); @@ -415,11 +359,67 @@ mod test { } #[test] - pub fn extract_from_seq_srv() { + fn extract_from_seq_srv() { let source = ~""; do astsrv::from_str(source) |srv| { let doc = from_srv(srv, ~"name"); assert!(doc.cratemod().name() == ~"name"); } } + + #[test] + fn should_extract_const_name_and_id() { + let doc = mk_doc(~"static a: int = 0;"); + assert!(doc.cratemod().consts()[0].id() != 0); + assert!(doc.cratemod().consts()[0].name() == ~"a"); + } + + #[test] + fn should_extract_enums() { + let doc = mk_doc(~"enum e { v }"); + assert!(doc.cratemod().enums()[0].id() != 0); + assert!(doc.cratemod().enums()[0].name() == ~"e"); + } + + #[test] + fn should_extract_enum_variants() { + let doc = mk_doc(~"enum e { v }"); + assert!(doc.cratemod().enums()[0].variants[0].name == ~"v"); + } + + #[test] + fn should_extract_traits() { + let doc = mk_doc(~"trait i { fn f(); }"); + assert!(doc.cratemod().traits()[0].name() == ~"i"); + } + + #[test] + fn should_extract_trait_methods() { + let doc = mk_doc(~"trait i { fn f(); }"); + assert!(doc.cratemod().traits()[0].methods[0].name == ~"f"); + } + + #[test] + fn should_extract_impl_methods() { + let doc = mk_doc(~"impl int { fn f() { } }"); + assert!(doc.cratemod().impls()[0].methods[0].name == ~"f"); + } + + #[test] + fn should_extract_tys() { + let doc = mk_doc(~"type a = int;"); + assert!(doc.cratemod().types()[0].name() == ~"a"); + } + + #[test] + fn should_extract_structs() { + let doc = mk_doc(~"struct Foo { field: () }"); + assert!(doc.cratemod().structs()[0].name() == ~"Foo"); + } + + #[test] + fn should_extract_struct_fields() { + let doc = mk_doc(~"struct Foo { field: () }"); + assert!(doc.cratemod().structs()[0].fields[0] == ~"field"); + } } diff --git a/src/librustdoc/markdown_index_pass.rs b/src/librustdoc/markdown_index_pass.rs index 55901b4904aa3..866fbba2be87a 100644 --- a/src/librustdoc/markdown_index_pass.rs +++ b/src/librustdoc/markdown_index_pass.rs @@ -115,7 +115,7 @@ fn item_to_entry( } } -fn pandoc_header_id(header: &str) -> ~str { +pub fn pandoc_header_id(header: &str) -> ~str { // http://johnmacfarlane.net/pandoc/README.html#headers @@ -162,110 +162,6 @@ fn pandoc_header_id(header: &str) -> ~str { fn maybe_use_section_id(s: &str) -> ~str { s.to_str() } } -#[test] -fn should_remove_punctuation_from_headers() { - assert!(pandoc_header_id(~"impl foo of bar") == - ~"impl-foo-of-bara"); - assert!(pandoc_header_id(~"impl of num::num for int") - == ~"impl-of-numnum-for-int"); - assert!(pandoc_header_id(~"impl of num::num for int/&") - == ~"impl-of-numnum-for-int"); - assert!(pandoc_header_id(~"impl of num::num for ^int") - == ~"impl-of-numnum-for-int"); - assert!(pandoc_header_id(~"impl for & condvar") - == ~"impl-for-condvar"); - assert!(pandoc_header_id(~"impl of Select for (Left, Right)") - == ~"impl-of-selectt-u-for-left-right"); - assert!(pandoc_header_id(~"impl of Condition<'self, T, U>") - == ~"impl-of-conditionself-t-u"); - assert!(pandoc_header_id(~"impl of Condition") - == ~"impl-of-conditiont-copy-clone"); -} - -#[test] -fn should_trim_whitespace_after_removing_punctuation() { - assert!(pandoc_header_id("impl foo for ()") == ~"impl-foo-for"); -} - -#[test] -fn should_index_mod_contents() { - let doc = test::mk_doc( - config::DocPerCrate, - ~"mod a { } fn b() { }" - ); - assert!((&doc.cratemod().index).get().entries[0] == doc::IndexEntry { - kind: ~"Module", - name: ~"a", - brief: None, - link: ~"#module-a" - }); - assert!((&doc.cratemod().index).get().entries[1] == doc::IndexEntry { - kind: ~"Function", - name: ~"b", - brief: None, - link: ~"#function-b" - }); -} - -#[test] -fn should_index_mod_contents_multi_page() { - let doc = test::mk_doc( - config::DocPerMod, - ~"mod a { } fn b() { }" - ); - assert!((&doc.cratemod().index).get().entries[0] == doc::IndexEntry { - kind: ~"Module", - name: ~"a", - brief: None, - link: ~"a.html" - }); - assert!((&doc.cratemod().index).get().entries[1] == doc::IndexEntry { - kind: ~"Function", - name: ~"b", - brief: None, - link: ~"#function-b" - }); -} - -#[test] -fn should_index_foreign_mod_pages() { - let doc = test::mk_doc( - config::DocPerMod, - ~"extern mod a { }" - ); - assert!((&doc.cratemod().index).get().entries[0] == doc::IndexEntry { - kind: ~"Foreign module", - name: ~"a", - brief: None, - link: ~"a.html" - }); -} - -#[test] -fn should_add_brief_desc_to_index() { - let doc = test::mk_doc( - config::DocPerMod, - ~"#[doc = \"test\"] mod a { }" - ); - assert!((&doc.cratemod().index).get().entries[0].brief - == Some(~"test")); -} - -#[test] -fn should_index_foreign_mod_contents() { - let doc = test::mk_doc( - config::DocPerCrate, - ~"extern mod a { fn b(); }" - ); - assert!((&doc.cratemod().nmods()[0].index).get().entries[0] - == doc::IndexEntry { - kind: ~"Function", - name: ~"b", - brief: None, - link: ~"#function-b" - }); -} - #[cfg(test)] mod test { use astsrv; @@ -276,10 +172,10 @@ mod test { use extract; use markdown_index_pass::run; use path_pass; + use super::pandoc_header_id; + use core::prelude::*; - use core::path::Path; - - pub fn mk_doc(output_style: config::OutputStyle, source: ~str) + fn mk_doc(output_style: config::OutputStyle, source: ~str) -> doc::Doc { do astsrv::from_str(source) |srv| { let config = config::Config { @@ -293,4 +189,108 @@ mod test { run(srv.clone(), doc, config) } } + + #[test] + fn should_remove_punctuation_from_headers() { + assert!(pandoc_header_id(~"impl foo of bar") == + ~"impl-foo-of-bara"); + assert!(pandoc_header_id(~"impl of num::num for int") + == ~"impl-of-numnum-for-int"); + assert!(pandoc_header_id(~"impl of num::num for int/&") + == ~"impl-of-numnum-for-int"); + assert!(pandoc_header_id(~"impl of num::num for ^int") + == ~"impl-of-numnum-for-int"); + assert!(pandoc_header_id(~"impl for & condvar") + == ~"impl-for-condvar"); + assert!(pandoc_header_id(~"impl of Select for (Left, Right)") + == ~"impl-of-selectt-u-for-left-right"); + assert!(pandoc_header_id(~"impl of Condition<'self, T, U>") + == ~"impl-of-conditionself-t-u"); + assert!(pandoc_header_id(~"impl of Condition") + == ~"impl-of-conditiont-copy-clone"); + } + + #[test] + fn should_trim_whitespace_after_removing_punctuation() { + assert!(pandoc_header_id("impl foo for ()") == ~"impl-foo-for"); + } + + #[test] + fn should_index_mod_contents() { + let doc = mk_doc( + config::DocPerCrate, + ~"mod a { } fn b() { }" + ); + assert!((&doc.cratemod().index).get().entries[0] == doc::IndexEntry { + kind: ~"Module", + name: ~"a", + brief: None, + link: ~"#module-a" + }); + assert!((&doc.cratemod().index).get().entries[1] == doc::IndexEntry { + kind: ~"Function", + name: ~"b", + brief: None, + link: ~"#function-b" + }); + } + + #[test] + fn should_index_mod_contents_multi_page() { + let doc = mk_doc( + config::DocPerMod, + ~"mod a { } fn b() { }" + ); + assert!((&doc.cratemod().index).get().entries[0] == doc::IndexEntry { + kind: ~"Module", + name: ~"a", + brief: None, + link: ~"a.html" + }); + assert!((&doc.cratemod().index).get().entries[1] == doc::IndexEntry { + kind: ~"Function", + name: ~"b", + brief: None, + link: ~"#function-b" + }); + } + + #[test] + fn should_index_foreign_mod_pages() { + let doc = mk_doc( + config::DocPerMod, + ~"extern mod a { }" + ); + assert!((&doc.cratemod().index).get().entries[0] == doc::IndexEntry { + kind: ~"Foreign module", + name: ~"a", + brief: None, + link: ~"a.html" + }); + } + + #[test] + fn should_add_brief_desc_to_index() { + let doc = mk_doc( + config::DocPerMod, + ~"#[doc = \"test\"] mod a { }" + ); + assert!((&doc.cratemod().index).get().entries[0].brief + == Some(~"test")); + } + + #[test] + fn should_index_foreign_mod_contents() { + let doc = mk_doc( + config::DocPerCrate, + ~"extern mod a { fn b(); }" + ); + assert!((&doc.cratemod().nmods()[0].index).get().entries[0] + == doc::IndexEntry { + kind: ~"Function", + name: ~"b", + brief: None, + link: ~"#function-b" + }); + } } diff --git a/src/librustdoc/markdown_pass.rs b/src/librustdoc/markdown_pass.rs index 8c4cd26bb7c11..2dfc04e8ec709 100644 --- a/src/librustdoc/markdown_pass.rs +++ b/src/librustdoc/markdown_pass.rs @@ -22,10 +22,6 @@ use markdown_writer::WriterFactory; use pass::Pass; use sort_pass; -#[cfg(test)] use config; -#[cfg(test)] use markdown_writer; -#[cfg(test)] use page_pass; - use core::cell::Cell; use core::str; use core::vec; @@ -48,8 +44,8 @@ fn run( fn mods_last(item1: &doc::ItemTag, item2: &doc::ItemTag) -> bool { fn is_mod(item: &doc::ItemTag) -> bool { match *item { - doc::ModTag(_) => true, - _ => false + doc::ModTag(_) => true, + _ => false } } @@ -69,33 +65,6 @@ fn run( return doc; } -#[test] -fn should_write_modules_last() { - /* - Because the markdown pass writes all modules at the same level of - indentation (it doesn't 'nest' them), we need to make sure that we - write all of the modules contained in each module after all other - types of items, or else the header nesting will end up wrong, with - modules appearing to contain items that they do not. - */ - let markdown = test::render( - ~"mod a { }\ - fn b() { }\ - mod c { - }\ - fn d() { }" - ); - - let idx_a = str::find_str(markdown, ~"# Module `a`").get(); - let idx_b = str::find_str(markdown, ~"## Function `b`").get(); - let idx_c = str::find_str(markdown, ~"# Module `c`").get(); - let idx_d = str::find_str(markdown, ~"## Function `d`").get(); - - assert!(idx_b < idx_d); - assert!(idx_d < idx_a); - assert!(idx_a < idx_c); -} - struct Ctxt { w: Writer } @@ -118,33 +87,18 @@ pub fn write_markdown( fn write_page(ctxt: &Ctxt, page: &doc::Page) { write_title(ctxt, copy *page); match copy *page { - doc::CratePage(doc) => { - write_crate(ctxt, doc); - } - doc::ItemPage(doc) => { - // We don't write a header for item's pages because their - // header in the html output is created by the page title - write_item_no_header(ctxt, doc); - } + doc::CratePage(doc) => { + write_crate(ctxt, doc); + } + doc::ItemPage(doc) => { + // We don't write a header for item's pages because their + // header in the html output is created by the page title + write_item_no_header(ctxt, doc); + } } ctxt.w.put_done(); } -#[test] -fn should_request_new_writer_for_each_page() { - // This port will send us a (page, str) pair for every writer - // that was created - let (writer_factory, po) = markdown_writer::future_writer_factory(); - let (srv, doc) = test::create_doc_srv(~"mod a { }"); - // Split the document up into pages - let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); - write_markdown(doc, writer_factory); - // We expect two pages to have been written - for iter::repeat(2) { - po.recv(); - } -} - fn write_title(ctxt: &Ctxt, page: doc::Page) { ctxt.w.put_line(fmt!("%% %s", make_title(page))); ctxt.w.put_line(~""); @@ -152,38 +106,18 @@ fn write_title(ctxt: &Ctxt, page: doc::Page) { fn make_title(page: doc::Page) -> ~str { let item = match page { - doc::CratePage(CrateDoc) => { - doc::ModTag(copy CrateDoc.topmod) - } - doc::ItemPage(ItemTag) => { - ItemTag - } + doc::CratePage(CrateDoc) => { + doc::ModTag(copy CrateDoc.topmod) + } + doc::ItemPage(ItemTag) => { + ItemTag + } }; let title = markdown_pass::header_text(item); let title = str::replace(title, ~"`", ~""); return title; } -#[test] -fn should_write_title_for_each_page() { - let (writer_factory, po) = markdown_writer::future_writer_factory(); - let (srv, doc) = test::create_doc_srv( - ~"#[link(name = \"core\")]; mod a { }"); - let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); - write_markdown(doc, writer_factory); - for iter::repeat(2) { - let (page, markdown) = po.recv(); - match page { - doc::CratePage(_) => { - assert!(str::contains(markdown, ~"% Crate core")); - } - doc::ItemPage(_) => { - assert!(str::contains(markdown, ~"% Module a")); - } - } - } -} - enum Hlvl { H1 = 1, H2 = 2, @@ -204,94 +138,94 @@ fn write_header_(ctxt: &Ctxt, lvl: Hlvl, title: ~str) { pub fn header_kind(doc: doc::ItemTag) -> ~str { match doc { - doc::ModTag(_) => { - if doc.id() == syntax::ast::crate_node_id { - ~"Crate" - } else { - ~"Module" + doc::ModTag(_) => { + if doc.id() == syntax::ast::crate_node_id { + ~"Crate" + } else { + ~"Module" + } + } + doc::NmodTag(_) => { + ~"Foreign module" + } + doc::FnTag(_) => { + ~"Function" + } + doc::ConstTag(_) => { + ~"Const" + } + doc::EnumTag(_) => { + ~"Enum" + } + doc::TraitTag(_) => { + ~"Trait" + } + doc::ImplTag(_) => { + ~"Implementation" + } + doc::TyTag(_) => { + ~"Type" + } + doc::StructTag(_) => { + ~"Struct" } - } - doc::NmodTag(_) => { - ~"Foreign module" - } - doc::FnTag(_) => { - ~"Function" - } - doc::ConstTag(_) => { - ~"Const" - } - doc::EnumTag(_) => { - ~"Enum" - } - doc::TraitTag(_) => { - ~"Trait" - } - doc::ImplTag(_) => { - ~"Implementation" - } - doc::TyTag(_) => { - ~"Type" - } - doc::StructTag(_) => { - ~"Struct" - } } } pub fn header_name(doc: doc::ItemTag) -> ~str { let fullpath = str::connect(doc.path() + ~[doc.name()], ~"::"); match &doc { - &doc::ModTag(_) if doc.id() != syntax::ast::crate_node_id => { - fullpath - } - &doc::NmodTag(_) => { - fullpath - } - &doc::ImplTag(ref doc) => { - assert!(doc.self_ty.is_some()); - let bounds = if (&doc.bounds_str).is_some() { - fmt!(" where %s", (&doc.bounds_str).get()) - } else { - ~"" - }; - let self_ty = (&doc.self_ty).get(); - let mut trait_part = ~""; - for doc.trait_types.eachi |i, trait_type| { - if i == 0 { - trait_part += ~" of "; + &doc::ModTag(_) if doc.id() != syntax::ast::crate_node_id => { + fullpath + } + &doc::NmodTag(_) => { + fullpath + } + &doc::ImplTag(ref doc) => { + assert!(doc.self_ty.is_some()); + let bounds = if (&doc.bounds_str).is_some() { + fmt!(" where %s", (&doc.bounds_str).get()) } else { - trait_part += ~", "; + ~"" + }; + let self_ty = (&doc.self_ty).get(); + let mut trait_part = ~""; + for doc.trait_types.eachi |i, trait_type| { + if i == 0 { + trait_part += ~" of "; + } else { + trait_part += ~", "; + } + trait_part += *trait_type; } - trait_part += *trait_type; + fmt!("%s for %s%s", trait_part, self_ty, bounds) + } + _ => { + doc.name() } - fmt!("%s for %s%s", trait_part, self_ty, bounds) - } - _ => { - doc.name() - } } } pub fn header_text(doc: doc::ItemTag) -> ~str { match &doc { - &doc::ImplTag(ref ImplDoc) => { - let header_kind = header_kind(copy doc); - let bounds = if (&ImplDoc.bounds_str).is_some() { - fmt!(" where `%s`", (&ImplDoc.bounds_str).get()) - } else { - ~"" - }; - let desc = if ImplDoc.trait_types.is_empty() { - fmt!("for `%s`%s", (&ImplDoc.self_ty).get(), bounds) - } else { - fmt!("of `%s` for `%s`%s", - ImplDoc.trait_types[0], - (&ImplDoc.self_ty).get(), - bounds) - }; - return fmt!("%s %s", header_kind, desc); - } - _ => {} + &doc::ImplTag(ref ImplDoc) => { + let header_kind = header_kind(copy doc); + let bounds = if (&ImplDoc.bounds_str).is_some() { + fmt!(" where `%s`", (&ImplDoc.bounds_str).get()) + } else { + ~"" + }; + let desc = if ImplDoc.trait_types.is_empty() { + fmt!("for `%s`%s", (&ImplDoc.self_ty).get(), bounds) + } else { + fmt!("of `%s` for `%s`%s", + ImplDoc.trait_types[0], + (&ImplDoc.self_ty).get(), + bounds) + }; + return fmt!("%s %s", header_kind, desc); + } + _ => {} } header_text_(header_kind(copy doc), @@ -323,12 +257,6 @@ fn write_mod( write_mod_contents(ctxt, ModDoc); } -#[test] -fn should_write_full_path_to_mod() { - let markdown = test::render(~"mod a { mod b { mod c { } } }"); - assert!(str::contains(markdown, ~"# Module `a::b::c`")); -} - fn write_common( ctxt: &Ctxt, desc: Option<~str>, @@ -363,17 +291,6 @@ fn write_section(ctxt: &Ctxt, section: doc::Section) { ctxt.w.put_line(~""); } -#[test] -fn should_write_sections() { - let markdown = test::render( - ~"#[doc = \"\ - # Header\n\ - Body\"]\ - mod a { - }"); - assert!(str::contains(markdown, ~"#### Header\n\nBody\n\n")); -} - fn write_mod_contents( ctxt: &Ctxt, doc: doc::ModDoc @@ -402,15 +319,15 @@ fn write_item_(ctxt: &Ctxt, doc: doc::ItemTag, write_header: bool) { } match doc { - doc::ModTag(ModDoc) => write_mod(ctxt, ModDoc), - doc::NmodTag(nModDoc) => write_nmod(ctxt, nModDoc), - doc::FnTag(FnDoc) => write_fn(ctxt, FnDoc), - doc::ConstTag(ConstDoc) => write_const(ctxt, ConstDoc), - doc::EnumTag(EnumDoc) => write_enum(ctxt, EnumDoc), - doc::TraitTag(TraitDoc) => write_trait(ctxt, TraitDoc), - doc::ImplTag(ImplDoc) => write_impl(ctxt, ImplDoc), - doc::TyTag(TyDoc) => write_type(ctxt, TyDoc), - doc::StructTag(StructDoc) => put_struct(ctxt, StructDoc), + doc::ModTag(ModDoc) => write_mod(ctxt, ModDoc), + doc::NmodTag(nModDoc) => write_nmod(ctxt, nModDoc), + doc::FnTag(FnDoc) => write_fn(ctxt, FnDoc), + doc::ConstTag(ConstDoc) => write_const(ctxt, ConstDoc), + doc::EnumTag(EnumDoc) => write_enum(ctxt, EnumDoc), + doc::TraitTag(TraitDoc) => write_trait(ctxt, TraitDoc), + doc::ImplTag(ImplDoc) => write_impl(ctxt, ImplDoc), + doc::TyTag(TyDoc) => write_type(ctxt, TyDoc), + doc::StructTag(StructDoc) => put_struct(ctxt, StructDoc), } } @@ -420,17 +337,11 @@ fn write_item_header(ctxt: &Ctxt, doc: doc::ItemTag) { fn item_header_lvl(doc: &doc::ItemTag) -> Hlvl { match doc { - &doc::ModTag(_) | &doc::NmodTag(_) => H1, - _ => H2 + &doc::ModTag(_) | &doc::NmodTag(_) => H1, + _ => H2 } } -#[test] -fn should_write_crate_description() { - let markdown = test::render(~"#[doc = \"this is the crate\"];"); - assert!(str::contains(markdown, ~"this is the crate")); -} - fn write_index(ctxt: &Ctxt, index: doc::Index) { if vec::is_empty(index.entries) { return; @@ -444,7 +355,7 @@ fn write_index(ctxt: &Ctxt, index: doc::Index) { let id = copy entry.link; if entry.brief.is_some() { ctxt.w.put_line(fmt!("* [%s](%s) - %s", - header, id, (&entry.brief).get())); + header, id, (&entry.brief).get())); } else { ctxt.w.put_line(fmt!("* [%s](%s)", header, id)); } @@ -454,37 +365,6 @@ fn write_index(ctxt: &Ctxt, index: doc::Index) { ctxt.w.put_line(~""); } -#[test] -fn should_write_index() { - let markdown = test::render(~"mod a { } mod b { }"); - assert!(str::contains( - markdown, - ~"\n\n* [Module `a`](#module-a)\n\ - * [Module `b`](#module-b)\n\n" - )); -} - -#[test] -fn should_write_index_brief() { - let markdown = test::render(~"#[doc = \"test\"] mod a { }"); - assert!(str::contains(markdown, ~"(#module-a) - test\n")); -} - -#[test] -fn should_not_write_index_if_no_entries() { - let markdown = test::render(~""); - assert!(!str::contains(markdown, ~"\n\n\n")); -} - -#[test] -fn should_write_index_for_foreign_mods() { - let markdown = test::render(~"extern mod a { fn a(); }"); - assert!(str::contains( - markdown, - ~"\n\n* [Function `a`](#function-a)\n\n" - )); -} - fn write_nmod(ctxt: &Ctxt, doc: doc::NmodDoc) { write_common(ctxt, doc.desc(), doc.sections()); if doc.index.is_some() { @@ -497,27 +377,6 @@ fn write_nmod(ctxt: &Ctxt, doc: doc::NmodDoc) { } } -#[test] -fn should_write_foreign_mods() { - let markdown = test::render(~"#[doc = \"test\"] extern mod a { }"); - assert!(str::contains(markdown, ~"Foreign module `a`")); - assert!(str::contains(markdown, ~"test")); -} - -#[test] -fn should_write_foreign_fns() { - let markdown = test::render( - ~"extern mod a { #[doc = \"test\"] fn a(); }"); - assert!(str::contains(markdown, ~"test")); -} - -#[test] -fn should_write_foreign_fn_headers() { - let markdown = test::render( - ~"extern mod a { #[doc = \"test\"] fn a(); }"); - assert!(str::contains(markdown, ~"## Function `a`")); -} - fn write_fn( ctxt: &Ctxt, doc: doc::FnDoc @@ -542,11 +401,11 @@ fn write_fnlike( fn write_sig(ctxt: &Ctxt, sig: Option<~str>) { match sig { - Some(sig) => { - ctxt.w.put_line(code_block_indent(sig)); - ctxt.w.put_line(~""); - } - None => fail!(~"unimplemented") + Some(sig) => { + ctxt.w.put_line(code_block_indent(sig)); + ctxt.w.put_line(~""); + } + None => fail!(~"unimplemented") } } @@ -558,51 +417,6 @@ fn code_block_indent(s: ~str) -> ~str { str::connect(indented, "\n") } -#[test] -fn write_markdown_should_write_function_header() { - let markdown = test::render(~"fn func() { }"); - assert!(str::contains(markdown, ~"## Function `func`")); -} - -#[test] -fn should_write_the_function_signature() { - let markdown = test::render(~"#[doc = \"f\"] fn a() { }"); - assert!(str::contains(markdown, ~"\n fn a()\n")); -} - -#[test] -fn should_insert_blank_line_after_fn_signature() { - let markdown = test::render(~"#[doc = \"f\"] fn a() { }"); - assert!(str::contains(markdown, ~"fn a()\n\n")); -} - -#[test] -fn should_correctly_indent_fn_signature() { - let doc = test::create_doc(~"fn a() { }"); - let doc = doc::Doc{ - pages: ~[ - doc::CratePage(doc::CrateDoc{ - topmod: doc::ModDoc{ - items: ~[doc::FnTag(doc::SimpleItemDoc{ - sig: Some(~"line 1\nline 2"), - .. copy doc.cratemod().fns()[0] - })], - .. doc.cratemod() - }, - .. doc.CrateDoc() - }) - ] - }; - let markdown = test::write_markdown_str(doc); - assert!(str::contains(markdown, ~" line 1\n line 2")); -} - -#[test] -fn should_leave_blank_line_between_fn_header_and_sig() { - let markdown = test::render(~"fn a() { }"); - assert!(str::contains(markdown, ~"Function `a`\n\n fn a()")); -} - fn write_const( ctxt: &Ctxt, doc: doc::ConstDoc @@ -611,20 +425,6 @@ fn write_const( write_common(ctxt, doc.desc(), doc.sections()); } -#[test] -fn should_write_const_header() { - let markdown = test::render(~"static a: bool = true;"); - assert!(str::contains(markdown, ~"## Const `a`\n\n")); -} - -#[test] -fn should_write_const_description() { - let markdown = test::render( - ~"#[doc = \"b\"]\ - static a: bool = true;"); - assert!(str::contains(markdown, ~"\n\nb\n\n")); -} - fn write_enum( ctxt: &Ctxt, doc: doc::EnumDoc @@ -633,19 +433,6 @@ fn write_enum( write_variants(ctxt, doc.variants); } -#[test] -fn should_write_enum_header() { - let markdown = test::render(~"enum a { b }"); - assert!(str::contains(markdown, ~"## Enum `a`\n\n")); -} - -#[test] -fn should_write_enum_description() { - let markdown = test::render( - ~"#[doc = \"b\"] enum a { b }"); - assert!(str::contains(markdown, ~"\n\nb\n\n")); -} - fn write_variants( ctxt: &Ctxt, docs: &[doc::VariantDoc] @@ -667,46 +454,13 @@ fn write_variant(ctxt: &Ctxt, doc: doc::VariantDoc) { assert!(doc.sig.is_some()); let sig = (&doc.sig).get(); match copy doc.desc { - Some(desc) => { - ctxt.w.put_line(fmt!("* `%s` - %s", sig, desc)); - } - None => { - ctxt.w.put_line(fmt!("* `%s`", sig)); - } - } -} - -#[test] -fn should_write_variant_list() { - let markdown = test::render( - ~"enum a { \ - #[doc = \"test\"] b, \ - #[doc = \"test\"] c }"); - assert!(str::contains( - markdown, - ~"\n\n#### Variants\n\ - \n* `b` - test\ - \n* `c` - test\n\n")); -} - -#[test] -fn should_write_variant_list_without_descs() { - let markdown = test::render(~"enum a { b, c }"); - assert!(str::contains( - markdown, - ~"\n\n#### Variants\n\ - \n* `b`\ - \n* `c`\n\n")); -} - -#[test] -fn should_write_variant_list_with_signatures() { - let markdown = test::render(~"enum a { b(int), #[doc = \"a\"] c(int) }"); - assert!(str::contains( - markdown, - ~"\n\n#### Variants\n\ - \n* `b(int)`\ - \n* `c(int)` - a\n\n")); + Some(desc) => { + ctxt.w.put_line(fmt!("* `%s` - %s", sig, desc)); + } + None => { + ctxt.w.put_line(fmt!("* `%s`", sig)); + } + } } fn write_trait(ctxt: &Ctxt, doc: doc::TraitDoc) { @@ -730,78 +484,11 @@ fn write_method(ctxt: &Ctxt, doc: doc::MethodDoc) { ); } -#[test] -fn should_write_trait_header() { - let markdown = test::render(~"trait i { fn a(); }"); - assert!(str::contains(markdown, ~"## Trait `i`")); -} - -#[test] -fn should_write_trait_desc() { - let markdown = test::render( - ~"#[doc = \"desc\"] trait i { fn a(); }"); - assert!(str::contains(markdown, ~"desc")); -} - -#[test] -fn should_write_trait_method_header() { - let markdown = test::render( - ~"trait i { fn a(); }"); - assert!(str::contains(markdown, ~"### Method `a`")); -} - -#[test] -fn should_write_trait_method_signature() { - let markdown = test::render( - ~"trait i { fn a(&self); }"); - assert!(str::contains(markdown, ~"\n fn a(&self)")); -} - fn write_impl(ctxt: &Ctxt, doc: doc::ImplDoc) { write_common(ctxt, doc.desc(), doc.sections()); write_methods(ctxt, doc.methods); } -#[test] -fn should_write_impl_header() { - let markdown = test::render(~"impl int { fn a() { } }"); - assert!(str::contains(markdown, ~"## Implementation for `int`")); -} - -#[test] -fn should_write_impl_header_with_bounds() { - let markdown = test::render(~"impl int { }"); - assert!(str::contains(markdown, ~"## Implementation for `int` where ``")); -} - -#[test] -fn should_write_impl_header_with_trait() { - let markdown = test::render(~"impl j for int { fn a() { } }"); - assert!(str::contains(markdown, - ~"## Implementation of `j` for `int`")); -} - -#[test] -fn should_write_impl_desc() { - let markdown = test::render( - ~"#[doc = \"desc\"] impl int { fn a() { } }"); - assert!(str::contains(markdown, ~"desc")); -} - -#[test] -fn should_write_impl_method_header() { - let markdown = test::render( - ~"impl int { fn a() { } }"); - assert!(str::contains(markdown, ~"### Method `a`")); -} - -#[test] -fn should_write_impl_method_signature() { - let markdown = test::render( - ~"impl int { fn a(&mut self) { } }"); - assert!(str::contains(markdown, ~"\n fn a(&mut self)")); -} - fn write_type( ctxt: &Ctxt, doc: doc::TyDoc @@ -810,25 +497,6 @@ fn write_type( write_common(ctxt, doc.desc(), doc.sections()); } -#[test] -fn should_write_type_header() { - let markdown = test::render(~"type t = int;"); - assert!(str::contains(markdown, ~"## Type `t`")); -} - -#[test] -fn should_write_type_desc() { - let markdown = test::render( - ~"#[doc = \"desc\"] type t = int;"); - assert!(str::contains(markdown, ~"\n\ndesc\n\n")); -} - -#[test] -fn should_write_type_signature() { - let markdown = test::render(~"type t = int;"); - assert!(str::contains(markdown, ~"\n\n type t = int\n\n")); -} - fn put_struct( ctxt: &Ctxt, doc: doc::StructDoc @@ -837,12 +505,6 @@ fn put_struct( write_common(ctxt, doc.desc(), doc.sections()); } -#[test] -fn should_put_struct_header() { - let markdown = test::render(~"struct S { field: () }"); - assert!(str::contains(markdown, ~"## Struct `S`\n\n")); -} - #[cfg(test)] mod test { use astsrv; @@ -855,22 +517,21 @@ mod test { use markdown_pass::{mk_pass, write_markdown}; use markdown_writer; use path_pass; + use page_pass; use sectionalize_pass; use trim_pass; use tystr_pass; use unindent_pass; + use core::prelude::*; - use core::path::Path; - use core::str; - - pub fn render(source: ~str) -> ~str { + fn render(source: ~str) -> ~str { let (srv, doc) = create_doc_srv(source); let markdown = write_markdown_str_srv(srv, doc); debug!("markdown: %s", markdown); markdown } - pub fn create_doc_srv(source: ~str) -> (astsrv::Srv, doc::Doc) { + fn create_doc_srv(source: ~str) -> (astsrv::Srv, doc::Doc) { do astsrv::from_str(source) |srv| { let config = config::Config { @@ -901,12 +562,12 @@ mod test { } } - pub fn create_doc(source: ~str) -> doc::Doc { + fn create_doc(source: ~str) -> doc::Doc { let (_, doc) = create_doc_srv(source); doc } - pub fn write_markdown_str( + fn write_markdown_str( doc: doc::Doc ) -> ~str { let (writer_factory, po) = markdown_writer::future_writer_factory(); @@ -914,7 +575,7 @@ mod test { return po.recv().second(); } - pub fn write_markdown_str_srv( + fn write_markdown_str_srv( srv: astsrv::Srv, doc: doc::Doc ) -> ~str { @@ -925,14 +586,349 @@ mod test { } #[test] - pub fn write_markdown_should_write_mod_headers() { + fn write_markdown_should_write_mod_headers() { let markdown = render(~"mod moo { }"); assert!(str::contains(markdown, ~"# Module `moo`")); } #[test] - pub fn should_leave_blank_line_after_header() { + fn should_leave_blank_line_after_header() { let markdown = render(~"mod morp { }"); assert!(str::contains(markdown, ~"Module `morp`\n\n")); } + + #[test] + fn should_write_modules_last() { + /* + Because the markdown pass writes all modules at the same level of + indentation (it doesn't 'nest' them), we need to make sure that we + write all of the modules contained in each module after all other + types of items, or else the header nesting will end up wrong, with + modules appearing to contain items that they do not. + */ + let markdown = render( + ~"mod a { }\ + fn b() { }\ + mod c { +}\ + fn d() { }" + ); + + let idx_a = str::find_str(markdown, ~"# Module `a`").get(); + let idx_b = str::find_str(markdown, ~"## Function `b`").get(); + let idx_c = str::find_str(markdown, ~"# Module `c`").get(); + let idx_d = str::find_str(markdown, ~"## Function `d`").get(); + + assert!(idx_b < idx_d); + assert!(idx_d < idx_a); + assert!(idx_a < idx_c); + } + + #[test] + fn should_request_new_writer_for_each_page() { + // This port will send us a (page, str) pair for every writer + // that was created + let (writer_factory, po) = markdown_writer::future_writer_factory(); + let (srv, doc) = create_doc_srv(~"mod a { }"); + // Split the document up into pages + let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); + write_markdown(doc, writer_factory); + // We expect two pages to have been written + for iter::repeat(2) { + po.recv(); + } + } + + #[test] + fn should_write_title_for_each_page() { + let (writer_factory, po) = markdown_writer::future_writer_factory(); + let (srv, doc) = create_doc_srv( + ~"#[link(name = \"core\")]; mod a { }"); + let doc = (page_pass::mk_pass(config::DocPerMod).f)(srv, doc); + write_markdown(doc, writer_factory); + for iter::repeat(2) { + let (page, markdown) = po.recv(); + match page { + doc::CratePage(_) => { + assert!(str::contains(markdown, ~"% Crate core")); + } + doc::ItemPage(_) => { + assert!(str::contains(markdown, ~"% Module a")); + } + } + } + } + + #[test] + fn should_write_full_path_to_mod() { + let markdown = render(~"mod a { mod b { mod c { } } }"); + assert!(str::contains(markdown, ~"# Module `a::b::c`")); + } + + #[test] + fn should_write_sections() { + let markdown = render( + ~"#[doc = \"\ + # Header\n\ + Body\"]\ + mod a { +}"); + assert!(str::contains(markdown, ~"#### Header\n\nBody\n\n")); + } + + #[test] + fn should_write_crate_description() { + let markdown = render(~"#[doc = \"this is the crate\"];"); + assert!(str::contains(markdown, ~"this is the crate")); + } + + + #[test] + fn should_write_index() { + let markdown = render(~"mod a { } mod b { }"); + assert!(str::contains( + markdown, + ~"\n\n* [Module `a`](#module-a)\n\ + * [Module `b`](#module-b)\n\n" + )); + } + + #[test] + fn should_write_index_brief() { + let markdown = render(~"#[doc = \"test\"] mod a { }"); + assert!(str::contains(markdown, ~"(#module-a) - test\n")); + } + + #[test] + fn should_not_write_index_if_no_entries() { + let markdown = render(~""); + assert!(!str::contains(markdown, ~"\n\n\n")); + } + + #[test] + fn should_write_index_for_foreign_mods() { + let markdown = render(~"extern mod a { fn a(); }"); + assert!(str::contains( + markdown, + ~"\n\n* [Function `a`](#function-a)\n\n" + )); + } + + #[test] + fn should_write_foreign_mods() { + let markdown = render(~"#[doc = \"test\"] extern mod a { }"); + assert!(str::contains(markdown, ~"Foreign module `a`")); + assert!(str::contains(markdown, ~"test")); + } + + #[test] + fn should_write_foreign_fns() { + let markdown = render( + ~"extern mod a { #[doc = \"test\"] fn a(); }"); + assert!(str::contains(markdown, ~"test")); + } + + #[test] + fn should_write_foreign_fn_headers() { + let markdown = render( + ~"extern mod a { #[doc = \"test\"] fn a(); }"); + assert!(str::contains(markdown, ~"## Function `a`")); + } + + #[test] + fn write_markdown_should_write_function_header() { + let markdown = render(~"fn func() { }"); + assert!(str::contains(markdown, ~"## Function `func`")); + } + + #[test] + fn should_write_the_function_signature() { + let markdown = render(~"#[doc = \"f\"] fn a() { }"); + assert!(str::contains(markdown, ~"\n fn a()\n")); + } + + #[test] + fn should_insert_blank_line_after_fn_signature() { + let markdown = render(~"#[doc = \"f\"] fn a() { }"); + assert!(str::contains(markdown, ~"fn a()\n\n")); + } + + #[test] + fn should_correctly_indent_fn_signature() { + let doc = create_doc(~"fn a() { }"); + let doc = doc::Doc{ + pages: ~[ + doc::CratePage(doc::CrateDoc{ + topmod: doc::ModDoc{ + items: ~[doc::FnTag(doc::SimpleItemDoc{ + sig: Some(~"line 1\nline 2"), + .. copy doc.cratemod().fns()[0] + })], + .. doc.cratemod() + }, + .. doc.CrateDoc() + }) + ] + }; + let markdown = write_markdown_str(doc); + assert!(str::contains(markdown, ~" line 1\n line 2")); + } + + #[test] + fn should_leave_blank_line_between_fn_header_and_sig() { + let markdown = render(~"fn a() { }"); + assert!(str::contains(markdown, ~"Function `a`\n\n fn a()")); + } + + #[test] + fn should_write_const_header() { + let markdown = render(~"static a: bool = true;"); + assert!(str::contains(markdown, ~"## Const `a`\n\n")); + } + + #[test] + fn should_write_const_description() { + let markdown = render( + ~"#[doc = \"b\"]\ + static a: bool = true;"); + assert!(str::contains(markdown, ~"\n\nb\n\n")); + } + + #[test] + fn should_write_enum_header() { + let markdown = render(~"enum a { b }"); + assert!(str::contains(markdown, ~"## Enum `a`\n\n")); + } + + #[test] + fn should_write_enum_description() { + let markdown = render( + ~"#[doc = \"b\"] enum a { b }"); + assert!(str::contains(markdown, ~"\n\nb\n\n")); + } + + #[test] + fn should_write_variant_list() { + let markdown = render( + ~"enum a { \ + #[doc = \"test\"] b, \ + #[doc = \"test\"] c }"); + assert!(str::contains( + markdown, + ~"\n\n#### Variants\n\ + \n* `b` - test\ + \n* `c` - test\n\n")); + } + + #[test] + fn should_write_variant_list_without_descs() { + let markdown = render(~"enum a { b, c }"); + assert!(str::contains( + markdown, + ~"\n\n#### Variants\n\ + \n* `b`\ + \n* `c`\n\n")); + } + + #[test] + fn should_write_variant_list_with_signatures() { + let markdown = render(~"enum a { b(int), #[doc = \"a\"] c(int) }"); + assert!(str::contains( + markdown, + ~"\n\n#### Variants\n\ + \n* `b(int)`\ + \n* `c(int)` - a\n\n")); + } + + #[test] + fn should_write_trait_header() { + let markdown = render(~"trait i { fn a(); }"); + assert!(str::contains(markdown, ~"## Trait `i`")); + } + + #[test] + fn should_write_trait_desc() { + let markdown = render( + ~"#[doc = \"desc\"] trait i { fn a(); }"); + assert!(str::contains(markdown, ~"desc")); + } + + #[test] + fn should_write_trait_method_header() { + let markdown = render( + ~"trait i { fn a(); }"); + assert!(str::contains(markdown, ~"### Method `a`")); + } + + #[test] + fn should_write_trait_method_signature() { + let markdown = render( + ~"trait i { fn a(&self); }"); + assert!(str::contains(markdown, ~"\n fn a(&self)")); + } + + #[test] + fn should_write_impl_header() { + let markdown = render(~"impl int { fn a() { } }"); + assert!(str::contains(markdown, ~"## Implementation for `int`")); + } + + #[test] + fn should_write_impl_header_with_bounds() { + let markdown = render(~"impl int { }"); + assert!(str::contains(markdown, ~"## Implementation for `int` where ``")); + } + + #[test] + fn should_write_impl_header_with_trait() { + let markdown = render(~"impl j for int { fn a() { } }"); + assert!(str::contains(markdown, + ~"## Implementation of `j` for `int`")); + } + + #[test] + fn should_write_impl_desc() { + let markdown = render( + ~"#[doc = \"desc\"] impl int { fn a() { } }"); + assert!(str::contains(markdown, ~"desc")); + } + + #[test] + fn should_write_impl_method_header() { + let markdown = render( + ~"impl int { fn a() { } }"); + assert!(str::contains(markdown, ~"### Method `a`")); + } + + #[test] + fn should_write_impl_method_signature() { + let markdown = render( + ~"impl int { fn a(&mut self) { } }"); + assert!(str::contains(markdown, ~"\n fn a(&mut self)")); + } + + #[test] + fn should_write_type_header() { + let markdown = render(~"type t = int;"); + assert!(str::contains(markdown, ~"## Type `t`")); + } + + #[test] + fn should_write_type_desc() { + let markdown = render( + ~"#[doc = \"desc\"] type t = int;"); + assert!(str::contains(markdown, ~"\n\ndesc\n\n")); + } + + #[test] + fn should_write_type_signature() { + let markdown = render(~"type t = int;"); + assert!(str::contains(markdown, ~"\n\n type t = int\n\n")); + } + + #[test] + fn should_put_struct_header() { + let markdown = render(~"struct S { field: () }"); + assert!(str::contains(markdown, ~"## Struct `S`\n\n")); + } } diff --git a/src/librustdoc/markdown_writer.rs b/src/librustdoc/markdown_writer.rs index 2011649995ecd..fcf7011cbc309 100644 --- a/src/librustdoc/markdown_writer.rs +++ b/src/librustdoc/markdown_writer.rs @@ -182,7 +182,7 @@ fn generic_writer(process: ~fn(markdown: ~str)) -> Writer { result } -fn make_local_filename( +pub fn make_local_filename( config: config::Config, page: doc::Page ) -> Path { @@ -218,65 +218,6 @@ pub fn make_filename( Path(filename).with_filetype(ext) } -#[test] -fn should_use_markdown_file_name_based_off_crate() { - let config = config::Config { - output_dir: Path("output/dir"), - output_format: config::Markdown, - output_style: config::DocPerCrate, - .. config::default_config(&Path("input/test.rc")) - }; - let doc = test::mk_doc(~"test", ~""); - let page = doc::CratePage(doc.CrateDoc()); - let filename = make_local_filename(config, page); - assert!(filename.to_str() == ~"output/dir/test.md"); -} - -#[test] -fn should_name_html_crate_file_name_index_html_when_doc_per_mod() { - let config = config::Config { - output_dir: Path("output/dir"), - output_format: config::PandocHtml, - output_style: config::DocPerMod, - .. config::default_config(&Path("input/test.rc")) - }; - let doc = test::mk_doc(~"", ~""); - let page = doc::CratePage(doc.CrateDoc()); - let filename = make_local_filename(config, page); - assert!(filename.to_str() == ~"output/dir/index.html"); -} - -#[test] -fn should_name_mod_file_names_by_path() { - let config = config::Config { - output_dir: Path("output/dir"), - output_format: config::PandocHtml, - output_style: config::DocPerMod, - .. config::default_config(&Path("input/test.rc")) - }; - let doc = test::mk_doc(~"", ~"mod a { mod b { } }"); - let modb = copy doc.cratemod().mods()[0].mods()[0]; - let page = doc::ItemPage(doc::ModTag(modb)); - let filename = make_local_filename(config, page); - assert!(filename == Path("output/dir/a_b.html")); -} - -#[cfg(test)] -mod test { - use astsrv; - use doc; - use extract; - use path_pass; - - pub fn mk_doc(name: ~str, source: ~str) -> doc::Doc { - do astsrv::from_str(source) |srv| { - let doc = extract::from_srv(srv.clone(), copy name); - let doc = (path_pass::mk_pass().f)(srv.clone(), doc); - doc - } - } -} - fn write_file(path: &Path, s: ~str) { use core::io::WriterUtil; @@ -322,3 +263,65 @@ fn future_writer() -> (Writer, future::Future<~str>) { }; (writer, future) } + +#[cfg(test)] +mod test { + use astsrv; + use doc; + use extract; + use path_pass; + use config; + use super::make_local_filename; + use core::prelude::*; + + fn mk_doc(name: ~str, source: ~str) -> doc::Doc { + do astsrv::from_str(source) |srv| { + let doc = extract::from_srv(srv.clone(), copy name); + let doc = (path_pass::mk_pass().f)(srv.clone(), doc); + doc + } + } + + #[test] + fn should_use_markdown_file_name_based_off_crate() { + let config = config::Config { + output_dir: Path("output/dir"), + output_format: config::Markdown, + output_style: config::DocPerCrate, + .. config::default_config(&Path("input/test.rc")) + }; + let doc = mk_doc(~"test", ~""); + let page = doc::CratePage(doc.CrateDoc()); + let filename = make_local_filename(config, page); + assert!(filename.to_str() == ~"output/dir/test.md"); + } + + #[test] + fn should_name_html_crate_file_name_index_html_when_doc_per_mod() { + let config = config::Config { + output_dir: Path("output/dir"), + output_format: config::PandocHtml, + output_style: config::DocPerMod, + .. config::default_config(&Path("input/test.rc")) + }; + let doc = mk_doc(~"", ~""); + let page = doc::CratePage(doc.CrateDoc()); + let filename = make_local_filename(config, page); + assert!(filename.to_str() == ~"output/dir/index.html"); + } + + #[test] + fn should_name_mod_file_names_by_path() { + let config = config::Config { + output_dir: Path("output/dir"), + output_format: config::PandocHtml, + output_style: config::DocPerMod, + .. config::default_config(&Path("input/test.rc")) + }; + let doc = mk_doc(~"", ~"mod a { mod b { } }"); + let modb = copy doc.cratemod().mods()[0].mods()[0]; + let page = doc::ItemPage(doc::ModTag(modb)); + let filename = make_local_filename(config, page); + assert!(filename == Path("output/dir/a_b.html")); + } +} diff --git a/src/librustdoc/page_pass.rs b/src/librustdoc/page_pass.rs index 55f17f5c1501d..c620e20530e66 100644 --- a/src/librustdoc/page_pass.rs +++ b/src/librustdoc/page_pass.rs @@ -149,27 +149,6 @@ fn fold_nmod( return doc; } -#[test] -fn should_not_split_the_doc_into_pages_for_doc_per_crate() { - let doc = test::mk_doc_( - config::DocPerCrate, - ~"mod a { } mod b { mod c { } }" - ); - assert!(doc.pages.len() == 1u); -} - -#[test] -fn should_make_a_page_for_every_mod() { - let doc = test::mk_doc(~"mod a { }"); - assert!(doc.pages.mods()[0].name() == ~"a"); -} - -#[test] -fn should_remove_mods_from_containing_mods() { - let doc = test::mk_doc(~"mod a { }"); - assert!(vec::is_empty(doc.cratemod().mods())); -} - #[cfg(test)] mod test { use astsrv; @@ -177,8 +156,9 @@ mod test { use doc; use extract; use page_pass::run; + use core::vec; - pub fn mk_doc_( + fn mk_doc_( output_style: config::OutputStyle, source: ~str ) -> doc::Doc { @@ -188,7 +168,28 @@ mod test { } } - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { mk_doc_(config::DocPerMod, copy source) } + + #[test] + fn should_not_split_the_doc_into_pages_for_doc_per_crate() { + let doc = mk_doc_( + config::DocPerCrate, + ~"mod a { } mod b { mod c { } }" + ); + assert!(doc.pages.len() == 1u); + } + + #[test] + fn should_make_a_page_for_every_mod() { + let doc = mk_doc(~"mod a { }"); + assert!(doc.pages.mods()[0].name() == ~"a"); + } + + #[test] + fn should_remove_mods_from_containing_mods() { + let doc = mk_doc(~"mod a { }"); + assert!(vec::is_empty(doc.cratemod().mods())); + } } diff --git a/src/librustdoc/prune_hidden_pass.rs b/src/librustdoc/prune_hidden_pass.rs index f46d183ffcfaf..a50f1f51765f9 100644 --- a/src/librustdoc/prune_hidden_pass.rs +++ b/src/librustdoc/prune_hidden_pass.rs @@ -61,25 +61,25 @@ fn is_hidden(srv: astsrv::Srv, doc: doc::ItemDoc) -> bool { } } -#[test] -fn should_prune_hidden_items() { - use core::vec; - - let doc = test::mk_doc(~"#[doc(hidden)] mod a { }"); - assert!(vec::is_empty(doc.cratemod().mods())) -} - #[cfg(test)] -pub mod test { +mod test { use astsrv; use doc; use extract; use prune_hidden_pass::run; - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { do astsrv::from_str(copy source) |srv| { let doc = extract::from_srv(srv.clone(), ~""); run(srv.clone(), doc) } } + + #[test] + fn should_prune_hidden_items() { + use core::vec; + + let doc = mk_doc(~"#[doc(hidden)] mod a { }"); + assert!(vec::is_empty(doc.cratemod().mods())) + } } diff --git a/src/librustdoc/prune_private_pass.rs b/src/librustdoc/prune_private_pass.rs index a1f8fdb75d9ea..0578169e257d4 100644 --- a/src/librustdoc/prune_private_pass.rs +++ b/src/librustdoc/prune_private_pass.rs @@ -117,7 +117,7 @@ fn fold_mod( !doc.methods.is_empty() } else { // This is a trait implementation, make it visible - // NOTE: This is not quite right since this could be an impl + // NB: This is not quite right since this could be an impl // of a private trait. We can't know that without running // resolve though. true @@ -154,106 +154,106 @@ fn is_visible(srv: astsrv::Srv, doc: doc::ItemDoc) -> bool { } } -#[test] -fn should_prune_items_without_pub_modifier() { - let doc = test::mk_doc(~"mod a { }"); - assert!(vec::is_empty(doc.cratemod().mods())); -} - -#[test] -fn should_not_prune_trait_impls() { - // Impls are more complicated - let doc = test::mk_doc( - ~" \ - trait Foo { } \ - impl Foo for int { } \ - "); - assert!(!doc.cratemod().impls().is_empty()); -} - -#[test] -fn should_prune_associated_methods_without_vis_modifier_on_impls_without_vis_modifier() { - let doc = test::mk_doc( - ~"impl Foo {\ - pub fn bar() { }\ - fn baz() { }\ - }"); - assert!(doc.cratemod().impls()[0].methods.len() == 1); -} - -#[test] -fn should_prune_priv_associated_methods_on_impls_without_vis_modifier() { - let doc = test::mk_doc( - ~"impl Foo {\ - pub fn bar() { }\ - priv fn baz() { }\ - }"); - assert!(doc.cratemod().impls()[0].methods.len() == 1); -} - -#[test] -fn should_prune_priv_associated_methods_on_pub_impls() { - let doc = test::mk_doc( - ~"pub impl Foo {\ - fn bar() { }\ - priv fn baz() { }\ - }"); - assert!(doc.cratemod().impls()[0].methods.len() == 1); -} - -#[test] -fn should_prune_associated_methods_without_vis_modifier_on_priv_impls() { - let doc = test::mk_doc( - ~"priv impl Foo {\ - pub fn bar() { }\ - fn baz() { }\ - }"); - assert!(doc.cratemod().impls()[0].methods.len() == 1); -} - -#[test] -fn should_prune_priv_associated_methods_on_priv_impls() { - let doc = test::mk_doc( - ~"priv impl Foo {\ - pub fn bar() { }\ - priv fn baz() { }\ - }"); - assert!(doc.cratemod().impls()[0].methods.len() == 1); -} - -#[test] -fn should_prune_associated_impls_with_no_pub_methods() { - let doc = test::mk_doc( - ~"priv impl Foo {\ - fn baz() { }\ - }"); - assert!(doc.cratemod().impls().is_empty()); -} - -#[test] -fn should_not_prune_associated_impls_with_pub_methods() { - let doc = test::mk_doc( - ~" \ - impl Foo { pub fn bar() { } } \ - "); - assert!(!doc.cratemod().impls().is_empty()); -} - #[cfg(test)] -pub mod test { +mod test { use astsrv; use doc; use extract; use tystr_pass; use prune_private_pass::run; + use core::vec; - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { do astsrv::from_str(copy source) |srv| { let doc = extract::from_srv(srv.clone(), ~""); let doc = tystr_pass::run(srv.clone(), doc); run(srv.clone(), doc) } } -} + #[test] + fn should_prune_items_without_pub_modifier() { + let doc = mk_doc(~"mod a { }"); + assert!(vec::is_empty(doc.cratemod().mods())); + } + + #[test] + fn should_not_prune_trait_impls() { + // Impls are more complicated + let doc = mk_doc( + ~" \ + trait Foo { } \ + impl Foo for int { } \ + "); + assert!(!doc.cratemod().impls().is_empty()); + } + + #[test] + fn should_prune_associated_methods_without_vis_modifier_on_impls_without_vis_modifier() { + let doc = mk_doc( + ~"impl Foo {\ + pub fn bar() { }\ + fn baz() { }\ + }"); + assert!(doc.cratemod().impls()[0].methods.len() == 1); + } + + #[test] + fn should_prune_priv_associated_methods_on_impls_without_vis_modifier() { + let doc = mk_doc( + ~"impl Foo {\ + pub fn bar() { }\ + priv fn baz() { }\ + }"); + assert!(doc.cratemod().impls()[0].methods.len() == 1); + } + + #[test] + fn should_prune_priv_associated_methods_on_pub_impls() { + let doc = mk_doc( + ~"pub impl Foo {\ + fn bar() { }\ + priv fn baz() { }\ + }"); + assert!(doc.cratemod().impls()[0].methods.len() == 1); + } + + #[test] + fn should_prune_associated_methods_without_vis_modifier_on_priv_impls() { + let doc = mk_doc( + ~"priv impl Foo {\ + pub fn bar() { }\ + fn baz() { }\ + }"); + assert!(doc.cratemod().impls()[0].methods.len() == 1); + } + + #[test] + fn should_prune_priv_associated_methods_on_priv_impls() { + let doc = mk_doc( + ~"priv impl Foo {\ + pub fn bar() { }\ + priv fn baz() { }\ + }"); + assert!(doc.cratemod().impls()[0].methods.len() == 1); + } + + #[test] + fn should_prune_associated_impls_with_no_pub_methods() { + let doc = mk_doc( + ~"priv impl Foo {\ + fn baz() { }\ + }"); + assert!(doc.cratemod().impls().is_empty()); + } + + #[test] + fn should_not_prune_associated_impls_with_pub_methods() { + let doc = mk_doc( + ~" \ + impl Foo { pub fn bar() { } } \ + "); + assert!(!doc.cratemod().impls().is_empty()); + } +} diff --git a/src/librustdoc/rustdoc.rc b/src/librustdoc/rustdoc.rc index 9b19063a90866..f0c42162e7673 100644 --- a/src/librustdoc/rustdoc.rc +++ b/src/librustdoc/rustdoc.rc @@ -11,7 +11,7 @@ //! Rustdoc - The Rust documentation generator #[link(name = "rustdoc", - vers = "0.6", + vers = "0.7-pre", uuid = "f8abd014-b281-484d-a0c3-26e3de8e2412", url = "https://github.com/mozilla/rust/tree/master/src/rustdoc")]; @@ -23,10 +23,10 @@ #[allow(non_implicitly_copyable_typarams)]; -extern mod core(vers = "0.6"); -extern mod std(vers = "0.6"); -extern mod rustc(vers = "0.6"); -extern mod syntax(vers = "0.6"); +extern mod core(vers = "0.7-pre"); +extern mod std(vers = "0.7-pre"); +extern mod rustc(vers = "0.7-pre"); +extern mod syntax(vers = "0.7-pre"); use config::Config; use doc::Item; diff --git a/src/librustdoc/sectionalize_pass.rs b/src/librustdoc/sectionalize_pass.rs index 788f84b06c2e8..1cf43043004cf 100644 --- a/src/librustdoc/sectionalize_pass.rs +++ b/src/librustdoc/sectionalize_pass.rs @@ -160,106 +160,109 @@ fn parse_header(line: ~str) -> Option<~str> { } } -#[test] -fn should_create_section_headers() { - let doc = test::mk_doc( - ~"#[doc = \"\ - # Header\n\ - Body\"]\ - mod a { - }"); - assert!(str::contains( - doc.cratemod().mods()[0].item.sections[0].header, - ~"Header")); -} - -#[test] -fn should_create_section_bodies() { - let doc = test::mk_doc( - ~"#[doc = \"\ - # Header\n\ - Body\"]\ - mod a { - }"); - assert!(str::contains( - doc.cratemod().mods()[0].item.sections[0].body, - ~"Body")); -} -#[test] -fn should_not_create_sections_from_indented_headers() { - let doc = test::mk_doc( - ~"#[doc = \"\n\ - Text\n # Header\n\ - Body\"]\ - mod a { - }"); - assert!(vec::is_empty(doc.cratemod().mods()[0].item.sections)); -} - -#[test] -fn should_remove_section_text_from_main_desc() { - let doc = test::mk_doc( - ~"#[doc = \"\ - Description\n\n\ - # Header\n\ - Body\"]\ - mod a { - }"); - assert!(!str::contains( - doc.cratemod().mods()[0].desc().get(), - ~"Header")); - assert!(!str::contains( - doc.cratemod().mods()[0].desc().get(), - ~"Body")); -} - -#[test] -fn should_eliminate_desc_if_it_is_just_whitespace() { - let doc = test::mk_doc( - ~"#[doc = \"\ - # Header\n\ - Body\"]\ - mod a { - }"); - assert!(doc.cratemod().mods()[0].desc() == None); -} - -#[test] -fn should_sectionalize_trait_methods() { - let doc = test::mk_doc( - ~"trait i { - #[doc = \"\ - # Header\n\ - Body\"]\ - fn a(); }"); - assert!(doc.cratemod().traits()[0].methods[0].sections.len() == 1u); -} - -#[test] -fn should_sectionalize_impl_methods() { - let doc = test::mk_doc( - ~"impl bool { - #[doc = \"\ - # Header\n\ - Body\"]\ - fn a() { } }"); - assert!(doc.cratemod().impls()[0].methods[0].sections.len() == 1u); -} #[cfg(test)] -pub mod test { +mod test { use astsrv; use attr_pass; use doc; use extract; use sectionalize_pass::run; + use core::prelude::*; - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { do astsrv::from_str(copy source) |srv| { let doc = extract::from_srv(srv.clone(), ~""); let doc = (attr_pass::mk_pass().f)(srv.clone(), doc); run(srv.clone(), doc) } } + + #[test] + fn should_create_section_headers() { + let doc = mk_doc( + ~"#[doc = \"\ + # Header\n\ + Body\"]\ + mod a { +}"); + assert!(str::contains( + doc.cratemod().mods()[0].item.sections[0].header, + ~"Header")); + } + + #[test] + fn should_create_section_bodies() { + let doc = mk_doc( + ~"#[doc = \"\ + # Header\n\ + Body\"]\ + mod a { +}"); + assert!(str::contains( + doc.cratemod().mods()[0].item.sections[0].body, + ~"Body")); + } + + #[test] + fn should_not_create_sections_from_indented_headers() { + let doc = mk_doc( + ~"#[doc = \"\n\ + Text\n # Header\n\ + Body\"]\ + mod a { +}"); + assert!(vec::is_empty(doc.cratemod().mods()[0].item.sections)); + } + + #[test] + fn should_remove_section_text_from_main_desc() { + let doc = mk_doc( + ~"#[doc = \"\ + Description\n\n\ + # Header\n\ + Body\"]\ + mod a { +}"); + assert!(!str::contains( + doc.cratemod().mods()[0].desc().get(), + ~"Header")); + assert!(!str::contains( + doc.cratemod().mods()[0].desc().get(), + ~"Body")); + } + + #[test] + fn should_eliminate_desc_if_it_is_just_whitespace() { + let doc = mk_doc( + ~"#[doc = \"\ + # Header\n\ + Body\"]\ + mod a { +}"); + assert!(doc.cratemod().mods()[0].desc() == None); + } + + #[test] + fn should_sectionalize_trait_methods() { + let doc = mk_doc( + ~"trait i { +#[doc = \"\ + # Header\n\ + Body\"]\ + fn a(); }"); + assert!(doc.cratemod().traits()[0].methods[0].sections.len() == 1u); + } + + #[test] + fn should_sectionalize_impl_methods() { + let doc = mk_doc( + ~"impl bool { +#[doc = \"\ + # Header\n\ + Body\"]\ + fn a() { } }"); + assert!(doc.cratemod().impls()[0].methods[0].sections.len() == 1u); + } } diff --git a/src/librustdoc/text_pass.rs b/src/librustdoc/text_pass.rs index b5e9b452d148b..785428f00775d 100644 --- a/src/librustdoc/text_pass.rs +++ b/src/librustdoc/text_pass.rs @@ -137,181 +137,181 @@ fn fold_impl( } } -#[test] -fn should_execute_op_on_enum_brief() { - let doc = test::mk_doc(~"#[doc = \" a \"] enum a { b }"); - assert!(doc.cratemod().enums()[0].brief() == Some(~"a")); -} +#[cfg(test)] +mod test { + use astsrv; + use attr_pass; + use desc_to_brief_pass; + use doc; + use extract; + use sectionalize_pass; + use text_pass::mk_pass; -#[test] -fn should_execute_op_on_enum_desc() { - let doc = test::mk_doc(~"#[doc = \" a \"] enum a { b }"); - assert!(doc.cratemod().enums()[0].desc() == Some(~"a")); -} + use core::prelude::*; -#[test] -fn should_execute_op_on_variant_desc() { - let doc = test::mk_doc(~"enum a { #[doc = \" a \"] b }"); - assert!(doc.cratemod().enums()[0].variants[0].desc == Some(~"a")); -} + fn mk_doc(source: ~str) -> doc::Doc { + do astsrv::from_str(copy source) |srv| { + let doc = extract::from_srv(srv.clone(), ~""); + let doc = (attr_pass::mk_pass().f)(srv.clone(), doc); + let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc); + let doc = (sectionalize_pass::mk_pass().f)(srv.clone(), doc); + (mk_pass(~"", |s| str::trim(s).to_owned() ).f)(srv.clone(), doc) + } + } -#[test] -fn should_execute_op_on_trait_brief() { - let doc = test::mk_doc( - ~"#[doc = \" a \"] trait i { fn a(); }"); - assert!(doc.cratemod().traits()[0].brief() == Some(~"a")); -} + #[test] + fn should_execute_op_on_enum_brief() { + let doc = mk_doc(~"#[doc = \" a \"] enum a { b }"); + assert!(doc.cratemod().enums()[0].brief() == Some(~"a")); + } -#[test] -fn should_execute_op_on_trait_desc() { - let doc = test::mk_doc( - ~"#[doc = \" a \"] trait i { fn a(); }"); - assert!(doc.cratemod().traits()[0].desc() == Some(~"a")); -} + #[test] + fn should_execute_op_on_enum_desc() { + let doc = mk_doc(~"#[doc = \" a \"] enum a { b }"); + assert!(doc.cratemod().enums()[0].desc() == Some(~"a")); + } -#[test] -fn should_execute_op_on_trait_method_brief() { - let doc = test::mk_doc( - ~"trait i { #[doc = \" a \"] fn a(); }"); - assert!(doc.cratemod().traits()[0].methods[0].brief == Some(~"a")); -} + #[test] + fn should_execute_op_on_variant_desc() { + let doc = mk_doc(~"enum a { #[doc = \" a \"] b }"); + assert!(doc.cratemod().enums()[0].variants[0].desc == Some(~"a")); + } -#[test] -fn should_execute_op_on_trait_method_desc() { - let doc = test::mk_doc( - ~"trait i { #[doc = \" a \"] fn a(); }"); - assert!(doc.cratemod().traits()[0].methods[0].desc == Some(~"a")); -} + #[test] + fn should_execute_op_on_trait_brief() { + let doc = mk_doc( + ~"#[doc = \" a \"] trait i { fn a(); }"); + assert!(doc.cratemod().traits()[0].brief() == Some(~"a")); + } -#[test] -fn should_execute_op_on_impl_brief() { - let doc = test::mk_doc( - ~"#[doc = \" a \"] impl int { fn a() { } }"); - assert!(doc.cratemod().impls()[0].brief() == Some(~"a")); -} + #[test] + fn should_execute_op_on_trait_desc() { + let doc = mk_doc( + ~"#[doc = \" a \"] trait i { fn a(); }"); + assert!(doc.cratemod().traits()[0].desc() == Some(~"a")); + } -#[test] -fn should_execute_op_on_impl_desc() { - let doc = test::mk_doc( - ~"#[doc = \" a \"] impl int { fn a() { } }"); - assert!(doc.cratemod().impls()[0].desc() == Some(~"a")); -} + #[test] + fn should_execute_op_on_trait_method_brief() { + let doc = mk_doc( + ~"trait i { #[doc = \" a \"] fn a(); }"); + assert!(doc.cratemod().traits()[0].methods[0].brief == Some(~"a")); + } -#[test] -fn should_execute_op_on_impl_method_brief() { - let doc = test::mk_doc( - ~"impl int { #[doc = \" a \"] fn a() { } }"); - assert!(doc.cratemod().impls()[0].methods[0].brief == Some(~"a")); -} + #[test] + fn should_execute_op_on_trait_method_desc() { + let doc = mk_doc( + ~"trait i { #[doc = \" a \"] fn a(); }"); + assert!(doc.cratemod().traits()[0].methods[0].desc == Some(~"a")); + } -#[test] -fn should_execute_op_on_impl_method_desc() { - let doc = test::mk_doc( - ~"impl int { #[doc = \" a \"] fn a() { } }"); - assert!(doc.cratemod().impls()[0].methods[0].desc == Some(~"a")); -} + #[test] + fn should_execute_op_on_impl_brief() { + let doc = mk_doc( + ~"#[doc = \" a \"] impl int { fn a() { } }"); + assert!(doc.cratemod().impls()[0].brief() == Some(~"a")); + } -#[test] -fn should_execute_op_on_type_brief() { - let doc = test::mk_doc( - ~"#[doc = \" a \"] type t = int;"); - assert!(doc.cratemod().types()[0].brief() == Some(~"a")); -} + #[test] + fn should_execute_op_on_impl_desc() { + let doc = mk_doc( + ~"#[doc = \" a \"] impl int { fn a() { } }"); + assert!(doc.cratemod().impls()[0].desc() == Some(~"a")); + } -#[test] -fn should_execute_op_on_type_desc() { - let doc = test::mk_doc( - ~"#[doc = \" a \"] type t = int;"); - assert!(doc.cratemod().types()[0].desc() == Some(~"a")); -} + #[test] + fn should_execute_op_on_impl_method_brief() { + let doc = mk_doc( + ~"impl int { #[doc = \" a \"] fn a() { } }"); + assert!(doc.cratemod().impls()[0].methods[0].brief == Some(~"a")); + } -#[test] -fn should_execute_on_item_section_headers() { - let doc = test::mk_doc( - ~"#[doc = \"\ - # Header \n\ - Body\"]\ - fn a() { }"); - assert!(doc.cratemod().fns()[0].sections()[0].header == ~"Header"); -} + #[test] + fn should_execute_op_on_impl_method_desc() { + let doc = mk_doc( + ~"impl int { #[doc = \" a \"] fn a() { } }"); + assert!(doc.cratemod().impls()[0].methods[0].desc == Some(~"a")); + } -#[test] -fn should_execute_on_item_section_bodies() { - let doc = test::mk_doc( - ~"#[doc = \"\ - # Header\n\ - Body \"]\ - fn a() { }"); - assert!(doc.cratemod().fns()[0].sections()[0].body == ~"Body"); -} + #[test] + fn should_execute_op_on_type_brief() { + let doc = mk_doc( + ~"#[doc = \" a \"] type t = int;"); + assert!(doc.cratemod().types()[0].brief() == Some(~"a")); + } -#[test] -fn should_execute_on_trait_method_section_headers() { - let doc = test::mk_doc( - ~"trait i { - #[doc = \"\ - # Header \n\ - Body\"]\ - fn a(); }"); - assert!(doc.cratemod().traits()[0].methods[0].sections[0].header - == ~"Header"); -} + #[test] + fn should_execute_op_on_type_desc() { + let doc = mk_doc( + ~"#[doc = \" a \"] type t = int;"); + assert!(doc.cratemod().types()[0].desc() == Some(~"a")); + } -#[test] -fn should_execute_on_trait_method_section_bodies() { - let doc = test::mk_doc( - ~"trait i { - #[doc = \"\ - # Header\n\ - Body \"]\ - fn a(); }"); - assert!(doc.cratemod().traits()[0].methods[0].sections[0].body == - ~"Body"); -} + #[test] + fn should_execute_on_item_section_headers() { + let doc = mk_doc( + ~"#[doc = \"\ + # Header \n\ + Body\"]\ + fn a() { }"); + assert!(doc.cratemod().fns()[0].sections()[0].header == ~"Header"); + } -#[test] -fn should_execute_on_impl_method_section_headers() { - let doc = test::mk_doc( - ~"impl bool { - #[doc = \"\ - # Header \n\ - Body\"]\ - fn a() { } }"); - assert!(doc.cratemod().impls()[0].methods[0].sections[0].header - == ~"Header"); -} + #[test] + fn should_execute_on_item_section_bodies() { + let doc = mk_doc( + ~"#[doc = \"\ + # Header\n\ + Body \"]\ + fn a() { }"); + assert!(doc.cratemod().fns()[0].sections()[0].body == ~"Body"); + } -#[test] -fn should_execute_on_impl_method_section_bodies() { - let doc = test::mk_doc( - ~"impl bool { - #[doc = \"\ - # Header\n\ - Body \"]\ - fn a() { } }"); - assert!(doc.cratemod().impls()[0].methods[0].sections[0].body == - ~"Body"); -} + #[test] + fn should_execute_on_trait_method_section_headers() { + let doc = mk_doc( + ~"trait i { +#[doc = \"\ + # Header \n\ + Body\"]\ + fn a(); }"); + assert!(doc.cratemod().traits()[0].methods[0].sections[0].header + == ~"Header"); + } -#[cfg(test)] -mod test { - use astsrv; - use attr_pass; - use desc_to_brief_pass; - use doc; - use extract; - use sectionalize_pass; - use text_pass::mk_pass; + #[test] + fn should_execute_on_trait_method_section_bodies() { + let doc = mk_doc( + ~"trait i { +#[doc = \"\ + # Header\n\ + Body \"]\ + fn a(); }"); + assert!(doc.cratemod().traits()[0].methods[0].sections[0].body == + ~"Body"); + } - use core::str; + #[test] + fn should_execute_on_impl_method_section_headers() { + let doc = mk_doc( + ~"impl bool { +#[doc = \"\ + # Header \n\ + Body\"]\ + fn a() { } }"); + assert!(doc.cratemod().impls()[0].methods[0].sections[0].header + == ~"Header"); + } - pub fn mk_doc(source: ~str) -> doc::Doc { - do astsrv::from_str(copy source) |srv| { - let doc = extract::from_srv(srv.clone(), ~""); - let doc = (attr_pass::mk_pass().f)(srv.clone(), doc); - let doc = (desc_to_brief_pass::mk_pass().f)(srv.clone(), doc); - let doc = (sectionalize_pass::mk_pass().f)(srv.clone(), doc); - (mk_pass(~"", |s| str::trim(s).to_owned() ).f)(srv.clone(), doc) - } + #[test] + fn should_execute_on_impl_method_section_bodies() { + let doc = mk_doc( + ~"impl bool { +#[doc = \"\ + # Header\n\ + Body \"]\ + fn a() { } }"); + assert!(doc.cratemod().impls()[0].methods[0].sections[0].body == + ~"Body"); } } diff --git a/src/librustdoc/trim_pass.rs b/src/librustdoc/trim_pass.rs index ca543a27189dc..e56a5f18ac6f7 100644 --- a/src/librustdoc/trim_pass.rs +++ b/src/librustdoc/trim_pass.rs @@ -22,16 +22,6 @@ pub fn mk_pass() -> Pass { text_pass::mk_pass(~"trim", |s| s.trim().to_owned() ) } -#[test] -fn should_trim_text() { - use core::option::Some; - - let doc = test::mk_doc(~"#[doc = \" desc \"] \ - mod m { - }"); - assert!(doc.cratemod().mods()[0].desc() == Some(~"desc")); -} - #[cfg(test)] mod test { use astsrv; @@ -40,11 +30,21 @@ mod test { use extract; use trim_pass::mk_pass; - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { do astsrv::from_str(copy source) |srv| { let doc = extract::from_srv(srv.clone(), ~""); let doc = (attr_pass::mk_pass().f)(srv.clone(), doc); (mk_pass().f)(srv.clone(), doc) } } + + #[test] + fn should_trim_text() { + use core::option::Some; + + let doc = mk_doc(~"#[doc = \" desc \"] \ + mod m { +}"); + assert!(doc.cratemod().mods()[0].desc() == Some(~"desc")); + } } diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 6ccfb1bb8c4b9..c0562d306398a 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -67,35 +67,22 @@ fn fold_fn( fn get_fn_sig(srv: astsrv::Srv, fn_id: doc::AstId) -> Option<~str> { do astsrv::exec(srv) |ctxt| { match *ctxt.ast_map.get(&fn_id) { - ast_map::node_item(@ast::item { - ident: ident, - node: ast::item_fn(ref decl, purity, _, ref tys, _), _ - }, _) | - ast_map::node_foreign_item(@ast::foreign_item { - ident: ident, - node: ast::foreign_item_fn(ref decl, purity, ref tys), _ - }, _, _, _) => { - Some(pprust::fun_to_str(decl, purity, ident, None, tys, - extract::interner())) - } - _ => fail!(~"get_fn_sig: fn_id not bound to a fn item") + ast_map::node_item(@ast::item { + ident: ident, + node: ast::item_fn(ref decl, purity, _, ref tys, _), _ + }, _) | + ast_map::node_foreign_item(@ast::foreign_item { + ident: ident, + node: ast::foreign_item_fn(ref decl, purity, ref tys), _ + }, _, _, _) => { + Some(pprust::fun_to_str(decl, purity, ident, None, tys, + extract::interner())) + } + _ => fail!(~"get_fn_sig: fn_id not bound to a fn item") } } } -#[test] -fn should_add_fn_sig() { - let doc = test::mk_doc(~"fn a() -> int { }"); - assert!(doc.cratemod().fns()[0].sig == Some(~"fn a() -> int")); -} - -#[test] -fn should_add_foreign_fn_sig() { - let doc = test::mk_doc(~"extern mod a { fn a() -> int; }"); - assert!(doc.cratemod().nmods()[0].fns[0].sig == - Some(~"fn a() -> int")); -} - fn fold_const( fold: &fold::Fold, doc: doc::ConstDoc @@ -119,12 +106,6 @@ fn fold_const( } } -#[test] -fn should_add_const_types() { - let doc = test::mk_doc(~"static a: bool = true;"); - assert!(doc.cratemod().consts()[0].sig == Some(~"bool")); -} - fn fold_enum( fold: &fold::Fold, doc: doc::EnumDoc @@ -163,13 +144,6 @@ fn fold_enum( } } -#[test] -fn should_add_variant_sigs() { - let doc = test::mk_doc(~"enum a { b(int) }"); - assert!(doc.cratemod().enums()[0].variants[0].sig == - Some(~"b(int)")); -} - fn fold_trait( fold: &fold::Fold, doc: doc::TraitDoc @@ -200,73 +174,66 @@ fn get_method_sig( ) -> Option<~str> { do astsrv::exec(srv) |ctxt| { match *ctxt.ast_map.get(&item_id) { - ast_map::node_item(@ast::item { - node: ast::item_trait(_, _, ref methods), _ - }, _) => { - match vec::find(*methods, |method| { - match copy *method { - ast::required(ty_m) => to_str(ty_m.ident) == method_name, - ast::provided(m) => to_str(m.ident) == method_name, - } - }) { - Some(method) => { - match method { - ast::required(ty_m) => { - Some(pprust::fun_to_str( - &ty_m.decl, - ty_m.purity, - ty_m.ident, - Some(ty_m.self_ty.node), - &ty_m.generics, - extract::interner() - )) + ast_map::node_item(@ast::item { + node: ast::item_trait(_, _, ref methods), _ + }, _) => { + match vec::find(*methods, |method| { + match copy *method { + ast::required(ty_m) => to_str(ty_m.ident) == method_name, + ast::provided(m) => to_str(m.ident) == method_name, } - ast::provided(m) => { - Some(pprust::fun_to_str( - &m.decl, - m.purity, - m.ident, - Some(m.self_ty.node), - &m.generics, - extract::interner() - )) + }) { + Some(method) => { + match method { + ast::required(ty_m) => { + Some(pprust::fun_to_str( + &ty_m.decl, + ty_m.purity, + ty_m.ident, + Some(ty_m.self_ty.node), + &ty_m.generics, + extract::interner() + )) + } + ast::provided(m) => { + Some(pprust::fun_to_str( + &m.decl, + m.purity, + m.ident, + Some(m.self_ty.node), + &m.generics, + extract::interner() + )) + } + } } - } + _ => fail!(~"method not found") } - _ => fail!(~"method not found") } - } - ast_map::node_item(@ast::item { - node: ast::item_impl(_, _, _, ref methods), _ - }, _) => { - match vec::find(*methods, |method| { - to_str(method.ident) == method_name - }) { - Some(method) => { - Some(pprust::fun_to_str( - &method.decl, - method.purity, - method.ident, - Some(method.self_ty.node), - &method.generics, - extract::interner() - )) + ast_map::node_item(@ast::item { + node: ast::item_impl(_, _, _, ref methods), _ + }, _) => { + match vec::find(*methods, |method| { + to_str(method.ident) == method_name + }) { + Some(method) => { + Some(pprust::fun_to_str( + &method.decl, + method.purity, + method.ident, + Some(method.self_ty.node), + &method.generics, + extract::interner() + )) + } + None => fail!(~"method not found") } - None => fail!(~"method not found") } - } - _ => fail!(~"get_method_sig: item ID not bound to trait or impl") + _ => fail!(~"get_method_sig: item ID not bound to trait or impl") } } } -#[test] -fn should_add_trait_method_sigs() { - let doc = test::mk_doc(~"trait i { fn a(&mut self) -> int; }"); - assert!(doc.cratemod().traits()[0].methods[0].sig - == Some(~"fn a(&mut self) -> int")); -} - fn fold_impl( fold: &fold::Fold, doc: doc::ImplDoc @@ -305,37 +272,6 @@ fn fold_impl( } } -#[test] -fn should_add_impl_bounds() { - let doc = test::mk_doc(~"impl Option { }"); - assert!(doc.cratemod().impls()[0].bounds_str == Some(~"")); -} - -#[test] -fn should_add_impl_trait_types() { - let doc = test::mk_doc(~"impl j for int { fn a() { } }"); - assert!(doc.cratemod().impls()[0].trait_types[0] == ~"j"); -} - -#[test] -fn should_not_add_impl_trait_types_if_none() { - let doc = test::mk_doc(~"impl int { fn a() { } }"); - assert!(vec::len(doc.cratemod().impls()[0].trait_types) == 0); -} - -#[test] -fn should_add_impl_self_ty() { - let doc = test::mk_doc(~"impl int { fn a() { } }"); - assert!(doc.cratemod().impls()[0].self_ty == Some(~"int")); -} - -#[test] -fn should_add_impl_method_sigs() { - let doc = test::mk_doc(~"impl int { fn a(&self) -> int { fail!() } }"); - assert!(doc.cratemod().impls()[0].methods[0].sig - == Some(~"fn a(&self) -> int")); -} - fn fold_type( fold: &fold::Fold, doc: doc::TyDoc @@ -369,12 +305,6 @@ fn fold_type( } } -#[test] -fn should_add_type_signatures() { - let doc = test::mk_doc(~"type t = int;"); - assert!(doc.cratemod().types()[0].sig == Some(~"type t = int")); -} - fn fold_struct( fold: &fold::Fold, doc: doc::StructDoc @@ -422,38 +352,109 @@ fn strip_struct_extra_stuff(item: @ast::item) -> @ast::item { } } -#[test] -fn should_add_struct_defs() { - let doc = test::mk_doc(~"struct S { field: () }"); - assert!((&doc.cratemod().structs()[0].sig).get().contains( - "struct S {")); -} - -#[test] -fn should_not_serialize_struct_drop_blocks() { - // All we care about are the fields - let doc = test::mk_doc(~"struct S { field: (), drop { } }"); - assert!(!(&doc.cratemod().structs()[0].sig).get().contains("drop")); -} - -#[test] -fn should_not_serialize_struct_attrs() { - // All we care about are the fields - let doc = test::mk_doc(~"#[wut] struct S { field: () }"); - assert!(!(&doc.cratemod().structs()[0].sig).get().contains("wut")); -} - #[cfg(test)] -pub mod test { +mod test { use astsrv; use doc; use extract; use tystr_pass::run; + use core::prelude::*; - pub fn mk_doc(source: ~str) -> doc::Doc { + fn mk_doc(source: ~str) -> doc::Doc { do astsrv::from_str(copy source) |srv| { let doc = extract::from_srv(srv.clone(), ~""); run(srv.clone(), doc) } } + + #[test] + fn should_add_fn_sig() { + let doc = mk_doc(~"fn a() -> int { }"); + assert!(doc.cratemod().fns()[0].sig == Some(~"fn a() -> int")); + } + + #[test] + fn should_add_foreign_fn_sig() { + let doc = mk_doc(~"extern mod a { fn a() -> int; }"); + assert!(doc.cratemod().nmods()[0].fns[0].sig == + Some(~"fn a() -> int")); + } + + #[test] + fn should_add_const_types() { + let doc = mk_doc(~"static a: bool = true;"); + assert!(doc.cratemod().consts()[0].sig == Some(~"bool")); + } + + #[test] + fn should_add_variant_sigs() { + let doc = mk_doc(~"enum a { b(int) }"); + assert!(doc.cratemod().enums()[0].variants[0].sig == + Some(~"b(int)")); + } + + #[test] + fn should_add_trait_method_sigs() { + let doc = mk_doc(~"trait i { fn a(&mut self) -> int; }"); + assert!(doc.cratemod().traits()[0].methods[0].sig + == Some(~"fn a(&mut self) -> int")); + } + + #[test] + fn should_add_impl_bounds() { + let doc = mk_doc(~"impl Option { }"); + assert!(doc.cratemod().impls()[0].bounds_str == Some(~"")); + } + + #[test] + fn should_add_impl_trait_types() { + let doc = mk_doc(~"impl j for int { fn a() { } }"); + assert!(doc.cratemod().impls()[0].trait_types[0] == ~"j"); + } + + #[test] + fn should_not_add_impl_trait_types_if_none() { + let doc = mk_doc(~"impl int { fn a() { } }"); + assert!(vec::len(doc.cratemod().impls()[0].trait_types) == 0); + } + + #[test] + fn should_add_impl_self_ty() { + let doc = mk_doc(~"impl int { fn a() { } }"); + assert!(doc.cratemod().impls()[0].self_ty == Some(~"int")); + } + + #[test] + fn should_add_impl_method_sigs() { + let doc = mk_doc(~"impl int { fn a(&self) -> int { fail!() } }"); + assert!(doc.cratemod().impls()[0].methods[0].sig + == Some(~"fn a(&self) -> int")); + } + + #[test] + fn should_add_type_signatures() { + let doc = mk_doc(~"type t = int;"); + assert!(doc.cratemod().types()[0].sig == Some(~"type t = int")); + } + + #[test] + fn should_add_struct_defs() { + let doc = mk_doc(~"struct S { field: () }"); + assert!((&doc.cratemod().structs()[0].sig).get().contains( + "struct S {")); + } + + #[test] + fn should_not_serialize_struct_drop_blocks() { + // All we care about are the fields + let doc = mk_doc(~"struct S { field: (), drop { } }"); + assert!(!(&doc.cratemod().structs()[0].sig).get().contains("drop")); + } + + #[test] + fn should_not_serialize_struct_attrs() { + // All we care about are the fields + let doc = mk_doc(~"#[wut] struct S { field: () }"); + assert!(!(&doc.cratemod().structs()[0].sig).get().contains("wut")); + } } diff --git a/src/librusti/rusti.rc b/src/librusti/rusti.rc index 6b91377b67485..8e4a58c766e53 100644 --- a/src/librusti/rusti.rc +++ b/src/librusti/rusti.rc @@ -11,7 +11,7 @@ // rusti - REPL using the JIT backend #[link(name = "rusti", - vers = "0.6", + vers = "0.7-pre", uuid = "7fb5bf52-7d45-4fee-8325-5ad3311149fc", url = "https://github.com/mozilla/rust/tree/master/src/rusti")]; @@ -23,13 +23,13 @@ #[allow(vecs_implicitly_copyable, non_implicitly_copyable_typarams)]; -extern mod core(vers = "0.6"); -extern mod std(vers = "0.6"); -extern mod rustc(vers = "0.6"); -extern mod syntax(vers = "0.6"); +extern mod core(vers = "0.7-pre"); +extern mod std(vers = "0.7-pre"); +extern mod rustc(vers = "0.7-pre"); +extern mod syntax(vers = "0.7-pre"); use core::*; -use core::io::WriterUtil; +use core::io::{ReaderUtil, WriterUtil}; use rustc::driver::{driver, session}; use syntax::{ast, diagnostic}; use syntax::ast_util::*; @@ -241,23 +241,29 @@ fn compile_crate(src_filename: ~str, binary: ~str) -> Option { /// Tries to get a line from rl after outputting a prompt. Returns /// None if no input was read (e.g. EOF was reached). -fn get_line(prompt: ~str) -> Option<~str> { - let result = unsafe { rl::read(prompt) }; +fn get_line(use_rl: bool, prompt: ~str) -> Option<~str> { + if use_rl { + let result = unsafe { rl::read(prompt) }; - if result.is_none() { - return None; + match result { + None => None, + Some(line) => { + unsafe { rl::add_history(line) }; + Some(line) + } + } + } else { + if io::stdin().eof() { + None + } else { + Some(io::stdin().read_line()) + } } - - let line = result.get(); - - unsafe { rl::add_history(line) }; - - return Some(line); } /// Run a command, e.g. :clear, :exit, etc. fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, - cmd: ~str, args: ~[~str]) -> CmdAction { + cmd: ~str, args: ~[~str], use_rl: bool) -> CmdAction { let mut action = action_none; match cmd { ~"exit" => repl.running = false, @@ -273,7 +279,7 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, ~":{\\n ..lines.. \\n:}\\n - execute multiline command\n" + ~":load ... - \ loads given crates as dynamic libraries\n" + - ~":clear - clear the screen\n" + + ~":clear - clear the bindings\n" + ~":exit - exit from the repl\n" + ~":help - show this message"); } @@ -313,7 +319,7 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, let mut multiline_cmd = ~""; let mut end_multiline = false; while (!end_multiline) { - match get_line(~"rusti| ") { + match get_line(use_rl, ~"rusti| ") { None => fail!(~"unterminated multiline command :{ .. :}"), Some(line) => { if str::trim(line) == ~":}" { @@ -333,7 +339,8 @@ fn run_cmd(repl: &mut Repl, _in: @io::Reader, _out: @io::Writer, /// Executes a line of input, which may either be rust code or a /// :command. Returns a new Repl if it has changed. -fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str) +fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str, + use_rl: bool) -> Option { if line.starts_with(~":") { let full = line.substr(1, line.len() - 1); @@ -349,11 +356,11 @@ fn run_line(repl: &mut Repl, in: @io::Reader, out: @io::Writer, line: ~str) vec::slice(split, 1, len).to_vec() } else { ~[] }; - match run_cmd(repl, in, out, cmd, args) { + match run_cmd(repl, in, out, cmd, args, use_rl) { action_none => { } action_run_line(multiline_cmd) => { if !multiline_cmd.is_empty() { - return run_line(repl, in, out, multiline_cmd); + return run_line(repl, in, out, multiline_cmd, use_rl); } } } @@ -386,30 +393,37 @@ pub fn main() { stmts: ~"" }; - io::println("WARNING: The Rust REPL is experimental and may be"); - io::println("unstable. If you encounter problems, please use the"); - io::println("compiler instead."); - - unsafe { - do rl::complete |line, suggest| { - if line.starts_with(":") { - suggest(~":clear"); - suggest(~":exit"); - suggest(~":help"); - suggest(~":load"); + let istty = unsafe { libc::isatty(libc::STDIN_FILENO as i32) } != 0; + + // only print this stuff if the user is actually typing into rusti + if istty { + io::println("WARNING: The Rust REPL is experimental and may be"); + io::println("unstable. If you encounter problems, please use the"); + io::println("compiler instead."); + + unsafe { + do rl::complete |line, suggest| { + if line.starts_with(":") { + suggest(~":clear"); + suggest(~":exit"); + suggest(~":help"); + suggest(~":load"); + } } } } while repl.running { - match get_line(repl.prompt) { + match get_line(istty, repl.prompt) { None => break, Some(line) => { if line.is_empty() { - io::println(~"()"); + if istty { + io::println(~"()"); + } loop; } - match run_line(&mut repl, in, out, line) { + match run_line(&mut repl, in, out, line, istty) { Some(new_repl) => repl = new_repl, None => { } } diff --git a/src/librustpkg/README.txt b/src/librustpkg/README.txt new file mode 100644 index 0000000000000..eacf07e01ea57 --- /dev/null +++ b/src/librustpkg/README.txt @@ -0,0 +1,4 @@ +Right now (2013-04-11), only one package works, the branch of rust-sdl at: +https://github.com/catamorphism/rust-sdl/tree/new-rustpkg + +and only one command works, "build". diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs new file mode 100644 index 0000000000000..353995a816e37 --- /dev/null +++ b/src/librustpkg/conditions.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Useful conditions + +pub use core::path::Path; + +condition! { + bad_path: (super::Path, ~str) -> super::Path; +} diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs new file mode 100644 index 0000000000000..c821281184d3b --- /dev/null +++ b/src/librustpkg/path_util.rs @@ -0,0 +1,83 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustpkg utilities having to do with paths and directories + +use core::path::*; +use core::os; +use util::PkgId; + +/// Returns the output directory to use. +/// Right now is always the default, should +/// support changing it. +pub fn dest_dir(pkgid: PkgId) -> Path { + default_dest_dir(&pkgid.path) +} + +/// Returns the default output directory for compilation. +/// Creates that directory if it doesn't exist. +pub fn default_dest_dir(pkg_dir: &Path) -> Path { + use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use conditions::bad_path::cond; + + // For now: assumes that pkg_dir exists and is relative + // to the CWD. Change this later when we do path searching. + let rslt = pkg_dir.push("build"); + let is_dir = os::path_is_dir(&rslt); + if os::path_exists(&rslt) { + if is_dir { + rslt + } + else { + cond.raise((rslt, ~"Path names a file that isn't a directory")) + } + } + else { + // Create it + if os::make_dir(&rslt, (S_IRUSR | S_IWUSR | S_IXUSR) as i32) { + rslt + } + else { + cond.raise((rslt, ~"Could not create directory")) + } + } +} + +#[cfg(test)] +mod test { + use core::{os, rand}; + use core::path::Path; + use core::rand::RngUtil; + use path_util::*; + + // Helper function to create a directory name that doesn't exist + pub fn mk_nonexistent(tmpdir: &Path, suffix: &str) -> Path { + let r = rand::Rng(); + for 1000.times { + let p = tmpdir.push(r.gen_str(16) + suffix); + if !os::path_exists(&p) { + return p; + } + } + fail!(~"Couldn't compute a non-existent path name; this is worrisome") + } + + #[test] + fn default_dir_ok() { + let the_path = os::tmpdir(); + let substitute_path = Path("xyzzy"); + assert!(default_dest_dir(&the_path) == the_path.push(~"build")); + let nonexistent_path = mk_nonexistent(&the_path, "quux"); + let bogus = do ::conditions::bad_path::cond.trap(|_| { + substitute_path + }).in { default_dest_dir(&nonexistent_path) }; + assert!(bogus == substitute_path); + } +} diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index ff549ad2c2261..f8805142769c1 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// rustpkg - a purely function package manager and build system +// rustpkg - a package manager and build system for Rust #[link(name = "rustpkg", - vers = "0.6", + vers = "0.7-pre", uuid = "25de5e6e-279e-4a20-845c-4cabae92daaf", url = "https://github.com/mozilla/rust/tree/master/src/librustpkg")]; @@ -21,48 +21,60 @@ #[allow(vecs_implicitly_copyable, non_implicitly_copyable_typarams)]; -extern mod core(vers = "0.6"); -extern mod std(vers = "0.6"); -extern mod rustc(vers = "0.6"); -extern mod syntax(vers = "0.6"); +extern mod core(vers = "0.7-pre"); +extern mod std(vers = "0.7-pre"); +extern mod rustc(vers = "0.7-pre"); +extern mod syntax(vers = "0.7-pre"); use core::*; +pub use core::path::Path; use core::container::Map; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::io::WriterUtil; use rustc::driver::{driver, session}; use rustc::metadata::filesearch; use std::net::url; -use std::{json, semver, getopts}; -use syntax::codemap::spanned; +use std::{getopts}; use syntax::{ast, diagnostic}; -use util::Package; +use util::{ExitCode, Pkg, PkgId}; +use path_util::dest_dir; +mod conditions; mod usage; +mod path_util; mod util; -struct PackageScript { - id: ~str, - name: ~str, - vers: semver::Version, - crates: ~[~str], - deps: ~[(~str, Option<~str>)], +/// A PkgScript represents user-supplied custom logic for +/// special build hooks. This only exists for packages with +/// an explicit package script. +struct PkgScript { + /// Uniquely identifies this package + id: PkgId, + // Used to have this field: deps: ~[(~str, Option<~str>)] + // but I think it shouldn't be stored here + /// The contents of the package script: either a file path, + /// or a string containing the text of the input input: driver::input, + /// The session to use *only* for compiling the custom + /// build script sess: session::Session, + /// The config for compiling the custom build script cfg: ast::crate_cfg, + /// The crate for the custom build script crate: @ast::crate, - custom: bool + /// Directory in which to store build output + build_dir: Path } -impl PackageScript { - fn parse(parent: &Path) -> Result { - let script = parent.push(~"pkg.rs"); - - if !os::path_exists(&script) { - return result::Err(~"no pkg.rs file"); - } - +impl PkgScript { + /// Given the path name for a package script + /// and a package ID, parse the package script into + /// a PkgScript that we can then execute + fn parse(script: Path, id: PkgId) -> PkgScript { + // Get the executable name that was invoked let binary = os::args()[0]; + // Build the rustc session data structures to pass + // to the compiler let options = @session::options { binary: binary, crate_type: session::bin_crate, @@ -73,190 +85,81 @@ impl PackageScript { let cfg = driver::build_configuration(sess, binary, input); let (crate, _) = driver::compile_upto(sess, cfg, input, driver::cu_parse, None); - let mut id = None; - let mut vers = None; - let mut crates = ~[]; - let mut deps = ~[]; - - fn load_pkg_attr(mis: ~[@ast::meta_item]) -> (Option<~str>, - Option<~str>) { - let mut id = None; - let mut vers = None; - - for mis.each |a| { - match a.node { - ast::meta_name_value(v, spanned { - node: ast::lit_str(s), - span: _}) => { - match *v { - ~"id" => id = Some(*s), - ~"vers" => vers = Some(*s), - _ => () - } - } - _ => {} - } - } + let work_dir = dest_dir(id); - (id, vers) - } + debug!("Returning package script with id %?", id); - fn load_pkg_dep_attr(mis: ~[@ast::meta_item]) -> (Option<~str>, - Option<~str>) { - let mut url = None; - let mut target = None; - - for mis.each |a| { - match a.node { - ast::meta_name_value(v, spanned { - node: ast::lit_str(s), - span: _}) => { - match *v { - ~"url" => url = Some(*s), - ~"target" => target = Some(*s), - _ => () - } - } - _ => {} - } - } - - (url, target) - } - - fn load_pkg_crate_attr(mis: ~[@ast::meta_item]) -> Option<~str> { - let mut file = None; - - for mis.each |a| { - match a.node { - ast::meta_name_value(v, spanned { - node: ast::lit_str(s), - span: _}) => { - match *v { - ~"file" => file = Some(*s), - _ => () - } - } - _ => {} - } - } - - file - } - - for crate.node.attrs.each |a| { - match a.node.value.node { - ast::meta_list(v, mis) => { - match *v { - ~"pkg" => { - let (i, v) = load_pkg_attr(mis); - - id = i; - vers = v; - } - ~"pkg_dep" => { - let (u, t) = load_pkg_dep_attr(mis); - - if u.is_none() { - fail!(~"pkg_dep attr without a url value"); - } - - deps.push((u.get(), t)); - } - ~"pkg_crate" => { - let f = load_pkg_crate_attr(mis); - - if f.is_none() { - fail!(~"pkg_file attr without a file value"); - } - - crates.push(f.get()); - } - _ => {} - } - } - _ => {} - } - } - - let mut custom = false; - - // If we hit a function, we assume they want to use - // the build API. - for crate.node.module.items.each |i| { - match i.node { - ast::item_fn(*) => { - custom = true; - - break; - } - _ => {} - } - } - - if id.is_none() || vers.is_none() { - return result::Err(~"pkg attr without (id, vers) values"); - } - - let id = id.get(); - let name = match util::parse_name(id) { - result::Ok(name) => name, - result::Err(err) => return result::Err(err) - }; - let vers = match util::parse_vers(vers.get()) { - result::Ok(vers) => vers, - result::Err(err) => return result::Err(err) - }; - - result::Ok(PackageScript { + PkgScript { id: id, - name: name, - vers: vers, - crates: crates, - deps: deps, input: input, sess: sess, cfg: cfg, crate: crate, - custom: custom - }) + build_dir: work_dir + } } - // Build the bootstrap and run a command + /// Run the contents of this package script, where + /// is the command to pass to it (e.g., "build", "clean", "install") + /// Returns a pair of an exit code and list of configs (obtained by + /// calling the package script's configs() function if it exists // FIXME (#4432): Use workcache to only compile the script when changed - fn run(&self, cmd: ~str, test: bool) -> int { - let work_dir = self.work_dir(); - let input = self.input; + fn run_custom(&self, what: ~str) -> (~[~str], ExitCode) { + debug!("run_custom: %s", what); let sess = self.sess; - let cfg = self.cfg; + + debug!("Working directory = %s", self.build_dir.to_str()); + // Collect together any user-defined commands in the package script let crate = util::ready_crate(sess, self.crate); - let outputs = driver::build_output_filenames(input, &Some(work_dir), - &None, sess); - let exe = work_dir.push(~"pkg" + util::exe_suffix()); - let root = filesearch::get_rustpkg_sysroot().get().pop().pop(); - - driver::compile_rest(sess, cfg, driver::cu_parse, - Some(outputs), Some(crate)); - run::run_program(exe.to_str(), ~[root.to_str(), cmd, test.to_str()]) + debug!("Building output filenames with script name %s", + driver::source_name(self.input)); + match filesearch::get_rustpkg_sysroot() { + Ok(r) => { + let root = r.pop().pop().pop().pop(); // :-\ + debug!("Root is %s, calling compile_rest", root.to_str()); + util::compile_crate_from_input(self.input, Some(self.build_dir), + sess, Some(crate), os::args()[0]); + let exe = self.build_dir.push(~"pkg" + util::exe_suffix()); + debug!("Running program: %s %s %s", exe.to_str(), root.to_str(), what); + let status = run::run_program(exe.to_str(), ~[root.to_str(), what]); + if status != 0 { + return (~[], status); + } + else { + debug!("Running program (configs): %s %s %s", + exe.to_str(), root.to_str(), ~"configs"); + let output = run::program_output(exe.to_str(), ~[root.to_str(), ~"configs"]); + // Run the configs() function to get the configs + let mut cfgs = ~[]; + for str::each_word(output.out) |w| { + cfgs.push(w.to_owned()); + } + (cfgs, output.status) + } + } + Err(e) => { + fail!(fmt!("Running package script, couldn't find rustpkg sysroot (%s)", + e)) + } + } } fn hash(&self) -> ~str { - fmt!("%s-%s-%s", self.name, util::hash(self.id + self.vers.to_str()), - self.vers.to_str()) + self.id.hash() } - fn work_dir(&self) -> Path { - util::root().push(~"work").push(self.hash()) - } } struct Ctx { - cfgs: ~[~str], + // I'm not sure what this is for json: bool, - dep_cache: @mut LinearMap<~str, bool> + // Cache of hashes of things already installed + // though I'm not sure why the value is a bool + dep_cache: @mut HashMap<~str, bool>, } impl Ctx { + fn run(&self, cmd: ~str, args: ~[~str]) { let root = util::root(); @@ -281,17 +184,64 @@ impl Ctx { match cmd { ~"build" => { - self.build(&os::getcwd(), true, false, false); + if args.len() < 1 { + return usage::build(); + } + // The package id is presumed to be the first command-line + // argument + let pkgid = PkgId::new(args[0]); + // Should allow the build directory to be configured. + // Right now it's always the "build" subdirectory in + // the package directory + let dst_dir = dest_dir(pkgid); + debug!("Destination dir = %s", dst_dir.to_str()); + // Right now, we assume the pkgid path is a valid dir + // relative to the CWD. In the future, we should search + // paths + let cwd = os::getcwd().normalize(); + debug!("Current working directory = %?", cwd); + + // Find crates inside the workspace + let mut src = PkgSrc::new(&cwd, &dst_dir, &pkgid); + debug!("Package src = %?", src); + src.find_crates(); + + // Is there custom build logic? If so, use it + let pkg_src_dir = cwd.push_rel(&pkgid.path); + debug!("Package source directory = %s", pkg_src_dir.to_str()); + let cfgs = match src.package_script_option(&pkg_src_dir) { + Some(package_script_path) => { + let pscript = PkgScript::parse(package_script_path, + pkgid); + // Limited right now -- we're only running the post_build + // hook and probably fail otherwise + // also post_build should be called pre_build + let (cfgs, hook_result) = pscript.run_custom(~"post_build"); + debug!("Command return code = %?", hook_result); + if hook_result != 0 { + fail!(fmt!("Error running custom build command")) + } + // otherwise, the package script succeeded + cfgs + } + None => { + debug!("No package script, continuing"); + ~[] + } + }; + src.build(&dst_dir, cfgs); } ~"clean" => { self.clean(); } ~"do" => { - if args.len() < 1 { + if args.len() < 2 { return usage::do_cmd(); } - self.do_cmd(args[0]); + if !self.do_cmd(args[0], args[1]) { + fail!(~"a command failed!"); + } } ~"info" => { self.info(); @@ -336,7 +286,7 @@ impl Ctx { } } - fn do_cmd(&self, cmd: ~str) -> bool { + fn do_cmd(&self, cmd: ~str, pkgname: ~str) -> bool { match cmd { ~"build" | ~"test" => { util::error(~"that command cannot be manually called"); @@ -347,230 +297,85 @@ impl Ctx { } let cwd = &os::getcwd(); - let script = match PackageScript::parse(cwd) { - result::Ok(script) => script, - result::Err(err) => { - util::error(err); - - return false; - } - }; - let status = script.run(cmd, false); - - if status == 42 { - util::error(~"no fns are listening for that cmd"); - - return false; - } - - status == 0 - } - - fn build(&self, dir: &Path, verbose: bool, opt: bool, - test: bool) -> Option { - let cwd = &os::getcwd(); - let script = match PackageScript::parse(dir) { - result::Ok(script) => script, - result::Err(err) => { - util::error(err); - - return None; - } - }; - let work_dir = script.work_dir(); - let mut success = true; - - util::need_dir(&work_dir); - - if script.deps.len() >= 1 { - util::note(~"installing dependencies"); - - for script.deps.each |&dep| { - let (url, target) = dep; - - success = self.install(Some(url), target, true); - - if !success { break; } - } - - - if !success { - util::error( - fmt!("building %s v%s failed: a dep wasn't installed", - script.name, script.vers.to_str())); - - return None; + let pkgid = PkgId::new(pkgname); + // Always use the "build" subdirectory of the package dir, + // but we should allow this to be configured + let dst_dir = dest_dir(pkgid); + + let mut src = PkgSrc::new(cwd, &dst_dir, &pkgid); + match src.package_script_option(cwd) { + Some(script_path) => { + let script = PkgScript::parse(script_path, pkgid); + let (_, status) = script.run_custom(cmd); // Ignore cfgs? + if status == 42 { // ??? + util::error(~"no fns are listening for that cmd"); + return false; + } + status == 0 } - - util::note(~"installed dependencies"); - } - - // Build imperative crates - os::change_dir(dir); - - if script.custom { - let status = script.run(~"build", test); - - if status != 0 && status != 42 { - util::error( - fmt!("building %s v%s failed: custom logic failed (%d)", - script.name, script.vers.to_str(), status)); - - return None; + None => { + util::error(fmt!("invoked `do`, but there is no package script in %s", + cwd.to_str())); + false } } + } - os::change_dir(cwd); - - for script.crates.each |&crate| { - let crate = &dir.push_rel(&Path(crate)).normalize(); - - util::note(fmt!("compiling %s", crate.to_str())); - - success = self.compile(crate, &work_dir, ~[], - ~[], opt, test); - - if !success { break; } - } - - if !success { - util::error( - fmt!("building %s v%s failed: a crate failed to compile", - script.name, script.vers.to_str())); - - return None; - } - - if verbose { - util::note(fmt!("built %s v%s", script.name, - script.vers.to_str())); - } - - Some(script) + fn build(&self, _dir: &Path, _verbose: bool, _opt: bool, + _test: bool) -> Option { + // either not needed anymore, + // or needed only when we don't have a package script. Not sure which one. + fail!(); } - fn compile(&self, crate: &Path, dir: &Path, flags: ~[~str], - cfgs: ~[~str], opt: bool, test: bool) -> bool { - util::compile_crate(None, crate, dir, flags, cfgs, opt, test) + fn compile(&self, _crate: &Path, _dir: &Path, _flags: ~[~str], + _cfgs: ~[~str], _opt: bool, _test: bool) -> bool { + // What's the difference between build and compile? + fail!(~"compile not yet implemented"); } fn clean(&self) -> bool { - let script = match PackageScript::parse(&os::getcwd()) { - result::Ok(script) => script, - result::Err(err) => { - util::error(err); - - return false; - } - }; - let dir = script.work_dir(); - - util::note(fmt!("cleaning %s v%s (%s)", script.name, - script.vers.to_str(), script.id)); - - if os::path_exists(&dir) { - util::remove_dir_r(&dir); - util::note(fmt!("removed %s", dir.to_str())); - } - - util::note(fmt!("cleaned %s v%s", script.name, - script.vers.to_str())); - - true + // stub + fail!(); } fn info(&self) { - if self.json { - match PackageScript::parse(&os::getcwd()) { - result::Ok(script) => { - let mut map = ~LinearMap::new(); - - map.insert(~"id", json::String(script.id)); - map.insert(~"name", json::String(script.name)); - map.insert(~"vers", json::String(script.vers.to_str())); - map.insert(~"deps", json::List(do script.deps.map |&dep| { - let (url, target) = dep; - let mut inner = ~LinearMap::new(); - - inner.insert(~"url", json::String(url)); - - if !target.is_none() { - inner.insert(~"target", - json::String(target.get())); - } - - json::Object(inner) - })); - - io::println(json::to_pretty_str(&json::Object(map))); - } - result::Err(_) => io::println(~"{}") - } - } else { - let script = match PackageScript::parse(&os::getcwd()) { - result::Ok(script) => script, - result::Err(err) => { - util::error(err); - - return; - } - }; - - util::note(fmt!("id: %s", script.id)); - util::note(fmt!("name: %s", script.name)); - util::note(fmt!("vers: %s", script.vers.to_str())); - util::note(fmt!("deps: %s", - if script.deps.len() > 0 { - ~"" - } else { - ~"none" - })); - - for script.deps.each |&dep| { - let (url, target) = dep; - - util::note(fmt!(" <%s> (%s)", url, match target { - Some(target) => target, - None => ~"" - })); - } - } + // stub + fail!(); } fn install(&self, url: Option<~str>, target: Option<~str>, cache: bool) -> bool { - let mut success; - let mut dir; - - if url.is_none() { - util::note(~"installing from the cwd"); - - dir = os::getcwd(); - } else { - let url = url.get(); - let hash = util::hash(if !target.is_none() { url + target.get() } - else { url }); - - if self.dep_cache.contains_key(&hash) { - util::warn(~"already installed dep this run"); - - return true; + let dir = match url { + None => { + util::note(~"installing from the cwd"); + os::getcwd() } + Some(url) => { + let hash = util::hash(if !target.is_none() { + url + target.get() + } + else { url }); - self.dep_cache.insert(hash, true); + if self.dep_cache.contains_key(&hash) { + util::warn(~"already installed dep this run"); + return true; + } - dir = util::root().push(~"tmp").push(hash); + self.dep_cache.insert(hash, true); - if cache && os::path_exists(&dir) { - return true; - } + let dir = util::root().push(~"tmp").push(hash); - success = self.fetch(&dir, url, target); + if cache && os::path_exists(&dir) { + return true; + } - if !success { - return false; + if !self.fetch(&dir, url, target) { + return false; + } + dir } - } + }; let script = match self.build(&dir, false, true, false) { Some(script) => script, @@ -578,7 +383,7 @@ impl Ctx { return false; } }; - let work_dir = script.work_dir(); + let work_dir = script.build_dir; let from_bin_dir = work_dir.push(~"bin"); let from_lib_dir = work_dir.push(~"lib"); let to_bin_dir = util::root().push(~"bin"); @@ -600,15 +405,13 @@ impl Ctx { libs.push(to.to_str()); } - let package = Package { + let package = Pkg { id: script.id, - vers: script.vers, bins: bins, libs: libs }; - util::note(fmt!("installed %s v%s", script.name, - script.vers.to_str())); + util::note(fmt!("installed %s", script.id.to_str())); util::add_pkg(&package); true @@ -713,17 +516,9 @@ impl Ctx { return false; } }; - let name = match util::parse_name(package.id) { - result::Ok(name) => name, - result::Err(err) => { - util::error(err); - - return false; - } - }; + let name = package.id.path.to_str(); // ??? - util::note(fmt!("preferring %s v%s (%s)", name, package.vers.to_str(), - package.id)); + util::note(fmt!("preferring %s v%s", name, package.id.version.to_str())); let bin_dir = util::root().push(~"bin"); @@ -740,7 +535,7 @@ impl Ctx { util::note(fmt!("linked %s", out.to_str())); } - util::note(fmt!("preferred %s v%s", name, package.vers.to_str())); + util::note(fmt!("preferred %s v%s", name, package.id.version.to_str())); true } @@ -752,126 +547,24 @@ impl Ctx { return false; } }; - let work_dir = script.work_dir(); - let test_dir = work_dir.push(~"test"); - - for os::walk_dir(&test_dir) |test| { - util::note(fmt!("running %s", test.to_str())); - - let status = run::run_program(test.to_str(), ~[]); - if status != 0 { - os::set_exit_status(status); - } - } - - // Run custom test listener - if script.custom { - let status = script.run(~"test", false); - - if status != 0 && status != 42 { - util::error( - fmt!("testing %s v%s failed: custom logic failed (%d)", - script.name, script.vers.to_str(), status)); - - os::set_exit_status(status); - } - } - - util::note(fmt!("tested %s v%s", script.name, script.vers.to_str())); - - true + // To do + util::note(fmt!("Would test %s, but this is a dry run", + script.id.to_str())); + false } - fn uninstall(&self, id: ~str, vers: Option<~str>) -> bool { - let package = match util::get_pkg(id, vers) { - result::Ok(package) => package, - result::Err(err) => { - util::error(err); - - return false; - } - }; - let name = match util::parse_name(package.id) { - result::Ok(name) => name, - result::Err(err) => { - util::error(err); - - return false; - } - }; - - util::note(fmt!("uninstalling %s v%s (%s)", name, - package.vers.to_str(), package.id)); - - for vec::append(package.bins, package.libs).each |&file| { - let path = Path(file); - - if os::path_exists(&path) { - if os::remove_file(&path) { - util::note(fmt!("removed %s", path.to_str())); - } else { - util::error(fmt!("could not remove %s", path.to_str())); - } - } - } - - util::note(fmt!("uninstalled %s v%s", name, package.vers.to_str())); - util::remove_pkg(&package); - - true + fn uninstall(&self, _id: ~str, _vers: Option<~str>) -> bool { + fail!(~"uninstall not yet implemented"); } - fn unprefer(&self, id: ~str, vers: Option<~str>) -> bool { - let package = match util::get_pkg(id, vers) { - result::Ok(package) => package, - result::Err(err) => { - util::error(err); - - return false; - } - }; - let name = match util::parse_name(package.id) { - result::Ok(name) => name, - result::Err(err) => { - util::error(err); - - return false; - } - }; - - util::note(fmt!("unpreferring %s v%s (%s)", name, - package.vers.to_str(), package.id)); - - 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()); - - if os::path_exists(&out) { - if os::remove_file(&out) { - util::note(fmt!("unlinked %s", out.to_str())); - } else { - util::error(fmt!("could not unlink %s", out.to_str())); - } - } - } - - util::note(fmt!("unpreferred %s v%s", name, package.vers.to_str())); - - true + fn unprefer(&self, _id: ~str, _vers: Option<~str>) -> bool { + fail!(~"unprefer not yet implemented"); } } pub fn main() { - io::println("WARNING: The Rust package manager is experimental and may"); - io::println("be unstable."); + io::println("WARNING: The Rust package manager is experimental and may be unstable"); let args = os::args(); let opts = ~[getopts::optflag(~"h"), getopts::optflag(~"help"), @@ -889,8 +582,6 @@ pub fn main() { getopts::opt_present(matches, ~"help"); let json = getopts::opt_present(matches, ~"j") || getopts::opt_present(matches, ~"json"); - let cfgs = vec::append(getopts::opt_strs(matches, ~"cfg"), - getopts::opt_strs(matches, ~"c")); let mut args = copy matches.free; args.shift(); @@ -919,15 +610,14 @@ pub fn main() { } Ctx { - cfgs: cfgs, json: json, - dep_cache: @mut LinearMap::new() + dep_cache: @mut HashMap::new() }.run(cmd, args); } /// A crate is a unit of Rust code to be compiled into a binary or library pub struct Crate { - file: ~str, + file: Path, flags: ~[~str], cfgs: ~[~str] } @@ -959,28 +649,37 @@ pub fn run(listeners: ~[Listener]) { } pub impl Crate { - pub fn flag(&self, flag: ~str) -> Crate { + + fn new(p: &Path) -> Crate { + Crate { + file: copy *p, + flags: ~[], + cfgs: ~[] + } + } + + fn flag(&self, flag: ~str) -> Crate { Crate { flags: vec::append(copy self.flags, ~[flag]), .. copy *self } } - pub fn flags(&self, flags: ~[~str]) -> Crate { + fn flags(&self, flags: ~[~str]) -> Crate { Crate { flags: vec::append(copy self.flags, flags), .. copy *self } } - pub fn cfg(&self, cfg: ~str) -> Crate { + fn cfg(&self, cfg: ~str) -> Crate { Crate { cfgs: vec::append(copy self.cfgs, ~[cfg]), .. copy *self } } - pub fn cfgs(&self, cfgs: ~[~str]) -> Crate { + fn cfgs(&self, cfgs: ~[~str]) -> Crate { Crate { cfgs: vec::append(copy self.cfgs, cfgs), .. copy *self @@ -988,15 +687,6 @@ pub impl Crate { } } -/// Create a crate target from a source file -pub fn Crate(file: ~str) -> Crate { - Crate { - file: file, - flags: ~[], - cfgs: ~[] - } -} - /** * Get the working directory of the package script. * Assumes that the package script has been compiled @@ -1016,30 +706,204 @@ pub fn src_dir() -> Path { os::getcwd() } -/// Build a set of crates, should be called once -pub fn build(crates: ~[Crate]) -> bool { - let args = os::args(); - let dir = src_dir(); - let work_dir = work_dir(); - let mut success = true; - let sysroot = Path(args[1]); - let test = args[3] == ~"true"; +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 { + root: Path, // root of where the package source code lives + dst_dir: Path, // directory where we will put the compiled output + id: PkgId, + libs: ~[Crate], + mains: ~[Crate], + tests: ~[Crate], + benchs: ~[Crate], +} + +condition! { + build_err: (~str) -> (); +} + +impl PkgSrc { + - for crates.each |&crate| { - let path = &dir.push_rel(&Path(crate.file)).normalize(); + fn new(src_dir: &Path, dst_dir: &Path, + id: &PkgId) -> PkgSrc { + PkgSrc { + root: copy *src_dir, + dst_dir: copy *dst_dir, + id: copy *id, + libs: ~[], + mains: ~[], + tests: ~[], + benchs: ~[] + } + } + + + fn check_dir(&self) -> Path { + use conditions::bad_path::cond; + + debug!("Pushing onto root: %s | %s", self.id.path.to_str(), + self.root.to_str()); + + let dir = self.root.push_rel(&self.id.path).normalize(); + + debug!("Checking dir: %s", dir.to_str()); + + if !os::path_exists(&dir) { + return cond.raise((dir, ~"missing package dir")); + } + + if !os::path_is_dir(&dir) { + return cond.raise((dir, ~"supplied path for package dir is a \ + non-directory")); + } + + dir + } + + + fn has_pkg_file(&self) -> bool { + let dir = self.check_dir(); + dir.push("pkg.rs").exists() + } + + // 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 { + let maybe_path = cwd.push("pkg.rs"); + if os::path_exists(&maybe_path) { + Some(maybe_path) + } + else { + None + } + } - util::note(fmt!("compiling %s", path.to_str())); + /// True if the given path's stem is self's pkg ID's stem + /// or if the pkg ID's stem is and the given path's + /// stem is foo + fn stem_matches(&self, p: &Path) -> bool { + let self_id = self.id.path.filestem(); + if self_id == p.filestem() { + return true; + } + else { + for self_id.each |pth| { + if pth.starts_with("rust-") + && match p.filestem() { + Some(s) => str::eq_slice(s, pth.slice(5, pth.len())), + None => false + } { return true; } + } + } + false + } - success = util::compile_crate(Some(sysroot), path, &work_dir, - crate.flags, crate.cfgs, - false, test); + fn push_crate(cs: &mut ~[Crate], prefix: uint, p: &Path) { + assert!(p.components.len() > prefix); + let mut sub = Path(""); + for vec::slice(p.components, prefix, + p.components.len()).each |c| { + sub = sub.push(*c); + } + debug!("found crate %s", sub.to_str()); + cs.push(Crate::new(&sub)); + } - if !success { break; } + fn find_crates(&mut self) { + use PkgSrc::push_crate; + + let dir = self.check_dir(); + let prefix = dir.components.len(); + // This is ugly, but can go away once we get rid + // of .rc files + let mut saw_rs = false; + let mut saw_rc = false; + debug!("Matching against %?", + self.id.path.filestem()); + for os::walk_dir(&dir) |pth| { + match pth.filename() { + Some(~"lib.rs") => push_crate(&mut self.libs, + prefix, pth), + Some(~"main.rs") => push_crate(&mut self.mains, + prefix, pth), + Some(~"test.rs") => push_crate(&mut self.tests, + prefix, pth), + Some(~"bench.rs") => push_crate(&mut self.benchs, + prefix, pth), + _ => { + // If the file stem is the same as the + // package ID, with an .rs or .rc extension, + // consider it to be a crate + let ext = pth.filetype(); + let matches = |p: &Path| { + self.stem_matches(p) && (ext == Some(~".rc") + || ext == Some(~".rs")) + }; + debug!("Checking %? which %s and ext = %? %? %?", pth.filestem(), + if matches(pth) { "matches" } else { "does not match" }, + ext, saw_rs, saw_rc); + if matches(pth) && + // Avoid pushing foo.rc *and* foo.rs + !((ext == Some(~".rc") && saw_rs) || + (ext == Some(~".rs") && saw_rc)) { + push_crate(&mut self.libs, // ???? + prefix, pth); + if ext == Some(~".rc") { + saw_rc = true; + } + else if ext == Some(~".rs") { + saw_rs = true; + } + } + } + } + } + debug!("found %u libs, %u mains, %u tests, %u benchs", + self.libs.len(), + self.mains.len(), + self.tests.len(), + self.benchs.len()) } - if !success { - os::set_exit_status(101); + fn build_crates(dst_dir: &Path, + src_dir: &Path, + crates: &[Crate], + cfgs: ~[~str], + test: bool) { + + for crates.each |&crate| { + let path = &src_dir.push_rel(&crate.file).normalize(); + util::note(fmt!("build_crates: compiling %s", path.to_str())); + util::note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); + + let result = util::compile_crate(None, path, + dst_dir, + crate.flags, + crate.cfgs + cfgs, + false, test); + if !result { + build_err::cond.raise(fmt!("build failure on %s", + path.to_str())); + } + debug!("Result of compiling %s was %?", + path.to_str(), result); + } } - success + fn build(&self, dst_dir: &Path, cfgs: ~[~str]) { + let dir = self.check_dir(); + debug!("Building libs"); + PkgSrc::build_crates(dst_dir, &dir, self.libs, cfgs, false); + debug!("Building mains"); + PkgSrc::build_crates(dst_dir, &dir, self.mains, cfgs, false); + debug!("Building tests"); + PkgSrc::build_crates(dst_dir, &dir, self.tests, cfgs, true); + debug!("Building benches"); + PkgSrc::build_crates(dst_dir, &dir, self.benchs, cfgs, true); + } } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs new file mode 100644 index 0000000000000..f594860607255 --- /dev/null +++ b/src/librustpkg/tests.rs @@ -0,0 +1,11 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// rustpkg unit tests diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index cd64061af0392..19938e8c5f178 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -9,26 +9,125 @@ // except according to those terms. use core::*; +use core::cmp::Ord; use core::hash::Streaming; -use core::hashmap::linear::LinearMap; use rustc::driver::{driver, session}; use rustc::metadata::filesearch; use std::getopts::groups::getopts; use std::semver; -use std::{json, term, sort, getopts}; +use std::{json, term, getopts}; use syntax::ast_util::*; -use syntax::codemap::{dummy_sp, spanned}; +use syntax::codemap::{dummy_sp}; use syntax::ext::base::{mk_ctxt, ext_ctxt}; use syntax::ext::build; use syntax::{ast, attr, codemap, diagnostic, fold}; +use rustc::back::link::output_type_exe; -pub struct Package { - id: ~str, - vers: semver::Version, +pub type ExitCode = int; // For now + +/// A version is either an exact revision, +/// or a semantic version +pub enum Version { + ExactRevision(float), + SemVersion(semver::Version) +} + +impl Ord for Version { + fn lt(&self, other: &Version) -> bool { + match (self, other) { + (&ExactRevision(f1), &ExactRevision(f2)) => f1 < f2, + (&SemVersion(v1), &SemVersion(v2)) => v1 < v2, + _ => false // incomparable, really + } + } + fn le(&self, other: &Version) -> bool { + match (self, other) { + (&ExactRevision(f1), &ExactRevision(f2)) => f1 <= f2, + (&SemVersion(v1), &SemVersion(v2)) => v1 <= v2, + _ => false // incomparable, really + } + } + fn ge(&self, other: &Version) -> bool { + match (self, other) { + (&ExactRevision(f1), &ExactRevision(f2)) => f1 > f2, + (&SemVersion(v1), &SemVersion(v2)) => v1 > v2, + _ => false // incomparable, really + } + } + fn gt(&self, other: &Version) -> bool { + match (self, other) { + (&ExactRevision(f1), &ExactRevision(f2)) => f1 >= f2, + (&SemVersion(v1), &SemVersion(v2)) => v1 >= v2, + _ => false // incomparable, really + } + } + +} + +impl ToStr for Version { + fn to_str(&self) -> ~str { + match *self { + ExactRevision(n) => n.to_str(), + SemVersion(v) => v.to_str() + } + } +} + +/// Placeholder +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. +pub struct PkgId { + path: Path, + version: Version +} + +pub impl PkgId { + fn new(s: &str) -> PkgId { + use bad_pkg_id::cond; + + let p = Path(s); + if p.is_absolute { + return cond.raise((p, ~"absolute pkgid")); + } + if p.components.len() < 1 { + return cond.raise((p, ~"0-length pkgid")); + } + PkgId { + path: p, + version: default_version() + } + } + + fn hash(&self) -> ~str { + fmt!("%s-%s-%s", self.path.to_str(), + hash(self.path.to_str() + self.version.to_str()), + 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-v%s", self.path.to_str(), self.version.to_str()) + } +} + +pub struct Pkg { + id: PkgId, bins: ~[~str], libs: ~[~str], } +impl ToStr for Pkg { + fn to_str(&self) -> ~str { + self.id.to_str() + } +} + pub fn root() -> Path { match filesearch::get_rustpkg_root() { result::Ok(path) => path, @@ -140,7 +239,7 @@ fn add_pkg_module(ctx: @mut ReadyCtx, m: ast::_mod) -> ast::_mod { let ext_cx = ctx.ext_cx; let item = quote_item! ( mod __pkg { - extern mod rustpkg (vers="0.6"); + extern mod rustpkg (vers="0.7-pre"); static listeners : &[rustpkg::Listener] = $listeners; #[main] fn main() { @@ -309,306 +408,65 @@ pub fn wait_for_lock(path: &Path) { } } -fn _add_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { - for packages.each |&package| { - match &package { - &json::Object(ref map) => { - let mut has_id = false; - - match map.get(&~"id") { - &json::String(ref str) => { - if pkg.id == *str { - has_id = true; - } - } - _ => {} - } - - match map.get(&~"vers") { - &json::String(ref str) => { - if has_id && pkg.vers.to_str() == *str { - return copy packages; - } - } - _ => {} - } - } - _ => {} - } - } - - let mut map = ~LinearMap::new(); - - map.insert(~"id", json::String(pkg.id)); - map.insert(~"vers", json::String(pkg.vers.to_str())); - map.insert(~"bins", json::List(do pkg.bins.map |&bin| { - json::String(bin) - })); - map.insert(~"libs", json::List(do pkg.libs.map |&lib| { - json::String(lib) - })); - - vec::append(packages, ~[json::Object(map)]) -} - -fn _rm_pkg(packages: ~[json::Json], pkg: &Package) -> ~[json::Json] { - do packages.filter_mapped |&package| { - match &package { - &json::Object(ref map) => { - let mut has_id = false; - - match map.get(&~"id") { - &json::String(str) => { - if pkg.id == str { - has_id = true; - } - } - _ => {} - } - - match map.get(&~"vers") { - &json::String(ref str) => { - if has_id && pkg.vers.to_str() == *str { - None - } else { - Some(copy package) - } - } - _ => { Some(copy package) } - } - } - _ => { Some(copy package) } - } - } -} - pub fn load_pkgs() -> result::Result<~[json::Json], ~str> { - let root = root(); - let db = root.push(~"db.json"); - let db_lock = root.push(~"db.json.lck"); - - wait_for_lock(&db_lock); - touch(&db_lock); - - let packages = if os::path_exists(&db) { - match io::read_whole_file_str(&db) { - result::Ok(str) => { - match json::from_str(str) { - result::Ok(json) => { - match json { - json::List(list) => list, - _ => { - os::remove_file(&db_lock); - - return result::Err( - ~"package db's json is not a list"); - } - } - } - result::Err(err) => { - os::remove_file(&db_lock); - - return result::Err( - fmt!("failed to parse package db: %s", - err.to_str())); - } - } - } - result::Err(err) => { - os::remove_file(&db_lock); - - return result::Err(fmt!("failed to read package db: %s", - err)); - } - } - } else { ~[] }; - - os::remove_file(&db_lock); - - result::Ok(packages) + fail!(~"load_pkg not implemented"); } -pub fn get_pkg(id: ~str, - vers: Option<~str>) -> result::Result { - let name = match parse_name(id) { - result::Ok(name) => name, - result::Err(err) => return result::Err(err) - }; - let packages = match load_pkgs() { - result::Ok(packages) => packages, - result::Err(err) => return result::Err(err) - }; - let mut sel = None; - let mut possibs = ~[]; - let mut err = None; - - for packages.each |&package| { - match package { - json::Object(map) => { - let pid = match map.get(&~"id") { - &json::String(str) => str, - _ => loop - }; - let pname = match parse_name(pid) { - result::Ok(pname) => pname, - result::Err(perr) => { - err = Some(perr); - - break; - } - }; - let pvers = match map.get(&~"vers") { - &json::String(str) => str, - _ => loop - }; - if pid == id || pname == name { - let bins = match map.get(&~"bins") { - &json::List(ref list) => { - do list.map |&bin| { - match bin { - json::String(str) => str, - _ => ~"" - } - } - } - _ => ~[] - }; - let libs = match map.get(&~"libs") { - &json::List(ref list) => { - do list.map |&lib| { - match lib { - json::String(str) => str, - _ => ~"" - } - } - } - _ => ~[] - }; - let package = Package { - id: pid, - vers: match parse_vers(pvers) { - result::Ok(vers) => vers, - result::Err(verr) => { - err = Some(verr); - - break; - } - }, - bins: bins, - libs: libs - }; - - if !vers.is_none() && vers.get() == pvers { - sel = Some(package); - } - else { - possibs.push(package); - } - } - } - _ => {} - } - } - - if !err.is_none() { - return result::Err(err.get()); - } - if !sel.is_none() { - return result::Ok(sel.get()); - } - if !vers.is_none() || possibs.len() < 1 { - return result::Err(~"package not found"); - } - - let possibs = sort::merge_sort(possibs, |v1, v2| { - v1.vers <= v2.vers - }); - - result::Ok(copy *possibs.last()) +pub fn get_pkg(_id: ~str, + _vers: Option<~str>) -> result::Result { + fail!(~"get_pkg not implemented"); } -pub fn add_pkg(pkg: &Package) -> bool { - let root = root(); - let db = root.push(~"db.json"); - let db_lock = root.push(~"db.json.lck"); - let packages = match load_pkgs() { - result::Ok(packages) => packages, - result::Err(err) => { - error(err); - - return false; - } - }; - - wait_for_lock(&db_lock); - touch(&db_lock); - os::remove_file(&db); - - match io::mk_file_writer(&db, ~[io::Create]) { - result::Ok(writer) => { - writer.write_line(json::to_pretty_str(&json::List( - _add_pkg(packages, pkg)))); - } - result::Err(err) => { - error(fmt!("failed to dump package db: %s", err)); - os::remove_file(&db_lock); - - return false; - } - } - - os::remove_file(&db_lock); - - true +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 } -pub fn remove_pkg(pkg: &Package) -> bool { - let root = root(); - let db = root.push(~"db.json"); - let db_lock = root.push(~"db.json.lck"); - let packages = match load_pkgs() { - result::Ok(packages) => packages, - result::Err(err) => { - error(err); - - return false; - } - }; - - wait_for_lock(&db_lock); - touch(&db_lock); - os::remove_file(&db); - - match io::mk_file_writer(&db, ~[io::Create]) { - result::Ok(writer) => { - writer.write_line(json::to_pretty_str(&json::List( - _rm_pkg(packages, pkg)))); - } - result::Err(err) => { - error(fmt!("failed to dump package db: %s", err)); - os::remove_file(&db_lock); +// FIXME (#4432): Use workcache to only compile when needed +pub fn compile_input(sysroot: Option, + in_file: &Path, + out_dir: &Path, + flags: ~[~str], + cfgs: ~[~str], + opt: bool, + test: bool) -> bool { - return false; - } - } + assert!(in_file.components.len() > 1); + let input = driver::file_input(copy *in_file); + debug!("compile_input: %s", in_file.to_str()); + // tjc: by default, use the package ID name as the link name + // not sure if we should support anything else + let short_name = in_file.filestem().expect("Can't compile a directory!"); + debug!("short_name = %s", short_name.to_str()); - os::remove_file(&db_lock); +// Right now we're always assuming that we're building a library. +// What we should do is parse the crate and infer whether it's a library +// from the absence or presence of a main fn + let out_file = out_dir.push(os::dll_filename(short_name)); + let building_library = true; - true -} + debug!("compiling %s into %s", + in_file.to_str(), + out_file.to_str()); -pub fn compile_input(sysroot: Option, input: driver::input, dir: &Path, - flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool) -> bool { - let lib_dir = dir.push(~"lib"); - let bin_dir = dir.push(~"bin"); - let test_dir = dir.push(~"test"); let binary = os::args()[0]; - let matches = getopts(flags, driver::optgroups()).get(); + + debug!("flags: %s", str::connect(flags, ~" ")); + debug!("cfgs: %s", str::connect(cfgs, ~" ")); +// Again, we assume we're building a library + let matches = getopts(~[~"-Z", ~"time-passes"] + + if building_library { ~[~"--lib"] } else { ~[] } + + flags + + cfgs.flat_map(|&c| { ~[~"--cfg", c] }), + driver::optgroups()).get(); let options = @session::options { - crate_type: session::unknown_crate, + crate_type: if building_library { session::lib_crate } + else { session::bin_crate }, optimize: if opt { session::Aggressive } else { session::No }, test: test, maybe_sysroot: sysroot, + addl_lib_search_paths: ~[copy *out_dir], .. *driver::build_session_options(binary, &matches, diagnostic::emit) }; let mut crate_cfg = options.cfg; @@ -619,124 +477,42 @@ pub fn compile_input(sysroot: Option, input: driver::input, dir: &Path, let options = @session::options { cfg: vec::append(options.cfg, crate_cfg), + // output_type should be conditional + output_type: output_type_exe, // Use this to get a library? That's weird .. *options }; let sess = driver::build_session(options, diagnostic::emit); - let cfg = driver::build_configuration(sess, binary, input); - let mut outputs = driver::build_output_filenames(input, &None, &None, - sess); - let (crate, _) = driver::compile_upto(sess, cfg, input, driver::cu_parse, - Some(outputs)); - - let mut name = None; - let mut vers = None; - let mut uuid = None; - let mut crate_type = None; - - fn load_link_attr(mis: ~[@ast::meta_item]) -> (Option<~str>, - Option<~str>, - Option<~str>) { - let mut name = None; - let mut vers = None; - let mut uuid = None; - - for mis.each |a| { - match a.node { - ast::meta_name_value(v, spanned {node: ast::lit_str(s), - span: _}) => { - match *v { - ~"name" => name = Some(*s), - ~"vers" => vers = Some(*s), - ~"uuid" => uuid = Some(*s), - _ => { } - } - } - _ => {} - } - } - - (name, vers, uuid) - } - for crate.node.attrs.each |a| { - match a.node.value.node { - ast::meta_name_value(v, spanned {node: ast::lit_str(s), - span: _}) => { - match *v { - ~"crate_type" => crate_type = Some(*s), - _ => {} - } - } - ast::meta_list(v, mis) => { - match *v { - ~"link" => { - let (n, v, u) = load_link_attr(mis); - - name = n; - vers = v; - uuid = u; - } - _ => {} - } - } - _ => {} - } - } - - if name.is_none() || vers.is_none() || uuid.is_none() { - error(~"link attr without (name, vers, uuid) values"); - - return false; - } - - let name = name.get(); - let vers = vers.get(); - let uuid = uuid.get(); - - let is_bin = match crate_type { - Some(crate_type) => { - match crate_type { - ~"bin" => true, - ~"lib" => false, - _ => { - warn(~"unknown crate_type, falling back to lib"); + debug!("calling compile_crate_from_input, out_dir = %s, + building_library = %?", out_dir.to_str(), sess.building_library); + compile_crate_from_input(input, Some(*out_dir), sess, None, binary); + true +} - false - } - } +// Should use workcache to avoid recompiling when not necessary +// Should also rename this to something better +// If crate_opt is present, then finish compilation. If it's None, then +// call compile_upto and return the crate +pub fn compile_crate_from_input(input: driver::input, build_dir_opt: Option, + sess: session::Session, crate_opt: Option<@ast::crate>, + binary: ~str) -> @ast::crate { + debug!("Calling build_output_filenames with %?", build_dir_opt); + let outputs = driver::build_output_filenames(input, &build_dir_opt, &None, sess); + debug!("Outputs are %? and output type = %?", outputs, sess.opts.output_type); + let cfg = driver::build_configuration(sess, binary, input); + match crate_opt { + Some(c) => { + debug!("Calling compile_rest, outputs = %?", outputs); + driver::compile_rest(sess, cfg, driver::cu_everything, Some(outputs), Some(c)); + c } None => { - warn(~"missing crate_type attr, assuming lib"); - - false + debug!("Calling compile_upto, outputs = %?", outputs); + let (crate, _) = driver::compile_upto(sess, cfg, input, driver::cu_parse, + Some(outputs)); + crate } - }; - - if test { - need_dir(&test_dir); - - outputs = driver::build_output_filenames(input, &Some(test_dir), - &None, sess) } - else if is_bin { - need_dir(&bin_dir); - - let path = bin_dir.push(fmt!("%s-%s-%s%s", name, - hash(name + uuid + vers), - vers, exe_suffix())); - outputs = driver::build_output_filenames(input, &None, &Some(path), - sess); - } else { - need_dir(&lib_dir); - - outputs = driver::build_output_filenames(input, &Some(lib_dir), - &None, sess) - } - - driver::compile_rest(sess, cfg, driver::cu_everything, - Some(outputs), Some(crate)); - - true } #[cfg(windows)] @@ -749,20 +525,19 @@ pub fn exe_suffix() -> ~str { ~".exe" } pub fn exe_suffix() -> ~str { ~"" } +// Called by build_crates // FIXME (#4432): Use workcache to only compile when needed pub fn compile_crate(sysroot: Option, crate: &Path, dir: &Path, flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool) -> bool { - compile_input(sysroot, driver::file_input(*crate), dir, flags, cfgs, - opt, test) + debug!("compile_crate: crate=%s, dir=%s", crate.to_str(), dir.to_str()); + debug!("compile_crate: flags =..."); + for flags.each |&fl| { + debug!("+++ %s", fl); + } + compile_input(sysroot, crate, dir, flags, cfgs, opt, test) } -pub fn compile_str(sysroot: Option, code: ~str, dir: &Path, - flags: ~[~str], cfgs: ~[~str], opt: bool, - test: bool) -> bool { - compile_input(sysroot, driver::str_input(code), dir, flags, cfgs, - opt, test) -} #[cfg(windows)] pub fn link_exe(_src: &Path, _dest: &Path) -> bool { @@ -788,21 +563,26 @@ pub fn link_exe(src: &Path, dest: &Path) -> bool { } } -#[test] -fn test_is_cmd() { - assert!(is_cmd(~"build")); - assert!(is_cmd(~"clean")); - assert!(is_cmd(~"do")); - assert!(is_cmd(~"info")); - assert!(is_cmd(~"install")); - assert!(is_cmd(~"prefer")); - assert!(is_cmd(~"test")); - assert!(is_cmd(~"uninstall")); - assert!(is_cmd(~"unprefer")); -} +#[cfg(test)] +mod test { + use super::{is_cmd, parse_name}; + + #[test] + fn test_is_cmd() { + assert!(is_cmd(~"build")); + assert!(is_cmd(~"clean")); + assert!(is_cmd(~"do")); + assert!(is_cmd(~"info")); + assert!(is_cmd(~"install")); + assert!(is_cmd(~"prefer")); + assert!(is_cmd(~"test")); + assert!(is_cmd(~"uninstall")); + 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()); + #[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/libstd/arc.rs b/src/libstd/arc.rs index ac8dd1a5d6523..da1e4688939cc 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -259,7 +259,7 @@ struct RWARCInner { lock: RWlock, failed: bool, data: T } */ struct RWARC { x: SharedMutableState>, - mut cant_nest: () + cant_nest: () } /// Create a reader/writer ARC with the supplied data. @@ -492,7 +492,7 @@ mod tests { use core::vec; #[test] - pub fn manually_share_arc() { + fn manually_share_arc() { let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = arc::ARC(v); @@ -517,7 +517,7 @@ mod tests { } #[test] - pub fn test_mutex_arc_condvar() { + fn test_mutex_arc_condvar() { let arc = ~MutexARC(false); let arc2 = ~arc.clone(); let (p,c) = comm::oneshot(); @@ -539,7 +539,7 @@ mod tests { } } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_arc_condvar_poison() { + fn test_arc_condvar_poison() { let arc = ~MutexARC(1); let arc2 = ~arc.clone(); let (p, c) = comm::stream(); @@ -561,7 +561,7 @@ mod tests { } } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_mutex_arc_poison() { + fn test_mutex_arc_poison() { let arc = ~MutexARC(1); let arc2 = ~arc.clone(); do task::try || { @@ -574,7 +574,7 @@ mod tests { } } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_rw_arc_poison_wr() { + fn test_rw_arc_poison_wr() { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { @@ -587,7 +587,7 @@ mod tests { } } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_rw_arc_poison_ww() { + fn test_rw_arc_poison_ww() { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { @@ -600,7 +600,7 @@ mod tests { } } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_rw_arc_poison_dw() { + fn test_rw_arc_poison_dw() { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { @@ -615,7 +615,7 @@ mod tests { } } #[test] #[ignore(cfg(windows))] - pub fn test_rw_arc_no_poison_rr() { + fn test_rw_arc_no_poison_rr() { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { @@ -628,7 +628,7 @@ mod tests { } } #[test] #[ignore(cfg(windows))] - pub fn test_rw_arc_no_poison_rw() { + fn test_rw_arc_no_poison_rw() { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { @@ -641,7 +641,7 @@ mod tests { } } #[test] #[ignore(cfg(windows))] - pub fn test_rw_arc_no_poison_dr() { + fn test_rw_arc_no_poison_dr() { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { @@ -657,7 +657,7 @@ mod tests { } } #[test] - pub fn test_rw_arc() { + fn test_rw_arc() { let arc = ~RWARC(0); let arc2 = (*arc).clone(); let (p,c) = comm::stream(); @@ -694,7 +694,7 @@ mod tests { do arc.read |num| { assert!(*num == 10); } } #[test] - pub fn test_rw_downgrade() { + fn test_rw_downgrade() { // (1) A downgrader gets in write mode and does cond.wait. // (2) A writer gets in write mode, sets state to 42, and does signal. // (3) Downgrader wakes, sets state to 31337. diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index 81c28f94d9f27..3d2c3ac70b610 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -171,7 +171,7 @@ unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) { pub impl Arena { // Functions for the POD part of the arena - fn alloc_pod_grow(&self, n_bytes: uint, align: uint) -> *u8 { + priv fn alloc_pod_grow(&self, n_bytes: uint, align: uint) -> *u8 { // Allocate a new chunk. let chunk_size = at_vec::capacity(self.pod_head.data); let new_min_chunk_size = uint::max(n_bytes, chunk_size); @@ -183,7 +183,7 @@ pub impl Arena { } #[inline(always)] - fn alloc_pod_inner(&self, n_bytes: uint, align: uint) -> *u8 { + priv fn alloc_pod_inner(&self, n_bytes: uint, align: uint) -> *u8 { let head = &mut self.pod_head; let start = round_up_to(head.fill, align); @@ -202,7 +202,22 @@ pub impl Arena { } #[inline(always)] - fn alloc_pod(&self, op: &fn() -> T) -> &'self T { + #[cfg(stage0)] + priv fn alloc_pod(&self, op: &fn() -> T) -> &'self T { + unsafe { + let tydesc = sys::get_type_desc::(); + let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); + let ptr: *mut T = reinterpret_cast(&ptr); + rusti::move_val_init(&mut (*ptr), op()); + return reinterpret_cast(&ptr); + } + } + + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + priv fn alloc_pod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); @@ -213,7 +228,7 @@ pub impl Arena { } // Functions for the non-POD part of the arena - fn alloc_nonpod_grow(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { + priv fn alloc_nonpod_grow(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { // Allocate a new chunk. let chunk_size = at_vec::capacity(self.head.data); let new_min_chunk_size = uint::max(n_bytes, chunk_size); @@ -225,7 +240,7 @@ pub impl Arena { } #[inline(always)] - fn alloc_nonpod_inner(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { + priv fn alloc_nonpod_inner(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { let head = &mut self.head; let tydesc_start = head.fill; @@ -247,7 +262,32 @@ pub impl Arena { } #[inline(always)] - fn alloc_nonpod(&self, op: &fn() -> T) -> &'self T { + #[cfg(stage0)] + priv fn alloc_nonpod(&self, op: &fn() -> T) -> &'self T { + unsafe { + let tydesc = sys::get_type_desc::(); + let (ty_ptr, ptr) = + self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align); + let ty_ptr: *mut uint = reinterpret_cast(&ty_ptr); + let ptr: *mut T = reinterpret_cast(&ptr); + // Write in our tydesc along with a bit indicating that it + // has *not* been initialized yet. + *ty_ptr = reinterpret_cast(&tydesc); + // Actually initialize it + rusti::move_val_init(&mut(*ptr), op()); + // Now that we are done, update the tydesc to indicate that + // the object is there. + *ty_ptr = bitpack_tydesc_ptr(tydesc, true); + + return reinterpret_cast(&ptr); + } + } + + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + priv fn alloc_nonpod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); let (ty_ptr, ptr) = @@ -269,6 +309,7 @@ pub impl Arena { // The external interface #[inline(always)] + #[cfg(stage0)] fn alloc(&self, op: &fn() -> T) -> &'self T { unsafe { if !rusti::needs_drop::() { @@ -278,6 +319,21 @@ pub impl Arena { } } } + + // The external interface + #[inline(always)] + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn alloc<'a, T>(&'a self, op: &fn() -> T) -> &'a T { + unsafe { + if !rusti::needs_drop::() { + self.alloc_pod(op) + } else { + self.alloc_nonpod(op) + } + } + } } #[test] diff --git a/src/libstd/base64.rs b/src/libstd/base64.rs index 0266f2d8631cf..e90f0fb3c81d4 100644 --- a/src/libstd/base64.rs +++ b/src/libstd/base64.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -27,55 +27,85 @@ static CHARS: [char, ..64] = [ ]; impl<'self> ToBase64 for &'self [u8] { + /** + * Turn a vector of `u8` bytes into a base64 string. + * + * *Example*: + * + * ~~~~ + * extern mod std; + * use std::base64::ToBase64; + * + * fn main () { + * let str = [52,32].to_base64(); + * println(fmt!("%s", str)); + * } + * ~~~~ + */ fn to_base64(&self) -> ~str { let mut s = ~""; - unsafe { - let len = self.len(); - str::reserve(&mut s, ((len + 3u) / 4u) * 3u); - - let mut i = 0u; - - while i < len - (len % 3u) { - let n = (self[i] as uint) << 16u | - (self[i + 1u] as uint) << 8u | - (self[i + 2u] as uint); - - // This 24-bit number gets separated into four 6-bit numbers. - str::push_char(&mut s, CHARS[(n >> 18u) & 63u]); - str::push_char(&mut s, CHARS[(n >> 12u) & 63u]); - str::push_char(&mut s, CHARS[(n >> 6u) & 63u]); - str::push_char(&mut s, CHARS[n & 63u]); - - i += 3u; - } - - // Heh, would be cool if we knew this was exhaustive - // (the dream of bounded integer types) - match len % 3 { - 0 => (), - 1 => { - let n = (self[i] as uint) << 16u; - str::push_char(&mut s, CHARS[(n >> 18u) & 63u]); - str::push_char(&mut s, CHARS[(n >> 12u) & 63u]); - str::push_char(&mut s, '='); - str::push_char(&mut s, '='); - } - 2 => { - let n = (self[i] as uint) << 16u | - (self[i + 1u] as uint) << 8u; - str::push_char(&mut s, CHARS[(n >> 18u) & 63u]); - str::push_char(&mut s, CHARS[(n >> 12u) & 63u]); - str::push_char(&mut s, CHARS[(n >> 6u) & 63u]); - str::push_char(&mut s, '='); - } - _ => fail!(~"Algebra is broken, please alert the math police") - } + let len = self.len(); + str::reserve(&mut s, ((len + 3u) / 4u) * 3u); + + let mut i = 0u; + + while i < len - (len % 3u) { + let n = (self[i] as uint) << 16u | + (self[i + 1u] as uint) << 8u | + (self[i + 2u] as uint); + + // This 24-bit number gets separated into four 6-bit numbers. + str::push_char(&mut s, CHARS[(n >> 18u) & 63u]); + str::push_char(&mut s, CHARS[(n >> 12u) & 63u]); + str::push_char(&mut s, CHARS[(n >> 6u) & 63u]); + str::push_char(&mut s, CHARS[n & 63u]); + + i += 3u; + } + + // Heh, would be cool if we knew this was exhaustive + // (the dream of bounded integer types) + match len % 3 { + 0 => (), + 1 => { + let n = (self[i] as uint) << 16u; + str::push_char(&mut s, CHARS[(n >> 18u) & 63u]); + str::push_char(&mut s, CHARS[(n >> 12u) & 63u]); + str::push_char(&mut s, '='); + str::push_char(&mut s, '='); + } + 2 => { + let n = (self[i] as uint) << 16u | + (self[i + 1u] as uint) << 8u; + str::push_char(&mut s, CHARS[(n >> 18u) & 63u]); + str::push_char(&mut s, CHARS[(n >> 12u) & 63u]); + str::push_char(&mut s, CHARS[(n >> 6u) & 63u]); + str::push_char(&mut s, '='); + } + _ => fail!(~"Algebra is broken, please alert the math police") } s } } impl<'self> ToBase64 for &'self str { + /** + * Convert any string (literal, `@`, `&`, or `~`) to base64 encoding. + * + * + * *Example*: + * + * ~~~~ + * extern mod std; + * use std::base64::ToBase64; + * + * fn main () { + * let str = "Hello, World".to_base64(); + * println(fmt!("%s",str)); + * } + * ~~~~ + * + */ fn to_base64(&self) -> ~str { str::to_bytes(*self).to_base64() } @@ -86,6 +116,25 @@ pub trait FromBase64 { } impl FromBase64 for ~[u8] { + /** + * Convert base64 `u8` vector into u8 byte values. + * Every 4 encoded characters is converted into 3 octets, modulo padding. + * + * *Example*: + * + * ~~~~ + * extern mod std; + * use std::base64::ToBase64; + * use std::base64::FromBase64; + * + * fn main () { + * let str = [52,32].to_base64(); + * println(fmt!("%s", str)); + * let bytes = str.from_base64(); + * println(fmt!("%?",bytes)); + * } + * ~~~~ + */ fn from_base64(&self) -> ~[u8] { if self.len() % 4u != 0u { fail!(~"invalid base64 length"); } @@ -99,55 +148,80 @@ impl FromBase64 for ~[u8] { let mut r = vec::with_capacity((len / 4u) * 3u - padding); - unsafe { - let mut i = 0u; - while i < len { - let mut n = 0u; - - for iter::repeat(4u) { - let ch = self[i] as char; - n <<= 6u; - - if ch >= 'A' && ch <= 'Z' { - n |= (ch as uint) - 0x41u; - } else if ch >= 'a' && ch <= 'z' { - n |= (ch as uint) - 0x47u; - } else if ch >= '0' && ch <= '9' { - n |= (ch as uint) + 0x04u; - } else if ch == '+' { - n |= 0x3Eu; - } else if ch == '/' { - n |= 0x3Fu; - } else if ch == '=' { - match len - i { - 1u => { - r.push(((n >> 16u) & 0xFFu) as u8); - r.push(((n >> 8u ) & 0xFFu) as u8); - return copy r; - } - 2u => { - r.push(((n >> 10u) & 0xFFu) as u8); - return copy r; - } - _ => fail!(~"invalid base64 padding") - } - } else { - fail!(~"invalid base64 character"); + let mut i = 0u; + while i < len { + let mut n = 0u; + + for iter::repeat(4u) { + let ch = self[i] as char; + n <<= 6u; + + if ch >= 'A' && ch <= 'Z' { + n |= (ch as uint) - 0x41u; + } else if ch >= 'a' && ch <= 'z' { + n |= (ch as uint) - 0x47u; + } else if ch >= '0' && ch <= '9' { + n |= (ch as uint) + 0x04u; + } else if ch == '+' { + n |= 0x3Eu; + } else if ch == '/' { + n |= 0x3Fu; + } else if ch == '=' { + match len - i { + 1u => { + r.push(((n >> 16u) & 0xFFu) as u8); + r.push(((n >> 8u ) & 0xFFu) as u8); + return copy r; + } + 2u => { + r.push(((n >> 10u) & 0xFFu) as u8); + return copy r; + } + _ => fail!(~"invalid base64 padding") } + } else { + fail!(~"invalid base64 character"); + } - i += 1u; - }; + i += 1u; + }; - r.push(((n >> 16u) & 0xFFu) as u8); - r.push(((n >> 8u ) & 0xFFu) as u8); - r.push(((n ) & 0xFFu) as u8); - } + r.push(((n >> 16u) & 0xFFu) as u8); + r.push(((n >> 8u ) & 0xFFu) as u8); + r.push(((n ) & 0xFFu) as u8); } r } } impl FromBase64 for ~str { + /** + * Convert any base64 encoded string (literal, `@`, `&`, or `~`) + * to the byte values it encodes. + * + * You can use the `from_bytes` function in `core::str` + * to turn a `[u8]` into a string with characters corresponding to those values. + * + * *Example*: + * + * This converts a string literal to base64 and back. + * + * ~~~~ + * extern mod std; + * use std::base64::ToBase64; + * use std::base64::FromBase64; + * use core::str; + * + * fn main () { + * let hello_str = "Hello, World".to_base64(); + * println(fmt!("%s",hello_str)); + * let bytes = hello_str.from_base64(); + * println(fmt!("%?",bytes)); + * let result_str = str::from_bytes(bytes); + * println(fmt!("%s",result_str)); + * } + * ~~~~ + */ fn from_base64(&self) -> ~[u8] { str::to_bytes(*self).from_base64() } @@ -158,7 +232,7 @@ mod tests { use core::str; #[test] - pub fn test_to_base64() { + fn test_to_base64() { assert!((~"").to_base64() == ~""); assert!((~"f").to_base64() == ~"Zg=="); assert!((~"fo").to_base64() == ~"Zm8="); @@ -169,7 +243,7 @@ mod tests { } #[test] - pub fn test_from_base64() { + fn test_from_base64() { assert!((~"").from_base64() == str::to_bytes(~"")); assert!((~"Zg==").from_base64() == str::to_bytes(~"f")); assert!((~"Zm8=").from_base64() == str::to_bytes(~"fo")); diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index f69e2130e7141..d89ce4232b175 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -437,8 +437,7 @@ pub impl Bitv { if offset >= bitv.nbits { 0 } else { - // NOTE cannot use bitv[offset] until snapshot - bitv.index(&offset) as u8 << (7 - bit) + bitv[offset] as u8 << (7 - bit) } } @@ -460,8 +459,7 @@ pub impl Bitv { * Transform self into a [bool] by turning each bit into a bool */ fn to_bools(&self) -> ~[bool] { - // NOTE cannot use self[i] until snapshot - vec::from_fn(self.nbits, |i| self.index(&i)) + vec::from_fn(self.nbits, |i| self[i]) } /** @@ -882,7 +880,7 @@ mod tests { static bench_bits : uint = 1 << 14; #[test] - pub fn test_to_str() { + fn test_to_str() { let zerolen = Bitv::new(0u, false); assert!(zerolen.to_str() == ~""); @@ -891,7 +889,7 @@ mod tests { } #[test] - pub fn test_0_elements() { + fn test_0_elements() { let mut act; let mut exp; act = Bitv::new(0u, false); @@ -900,7 +898,7 @@ mod tests { } #[test] - pub fn test_1_element() { + fn test_1_element() { let mut act; act = Bitv::new(1u, false); assert!(act.eq_vec(~[0u])); @@ -909,7 +907,7 @@ mod tests { } #[test] - pub fn test_2_elements() { + fn test_2_elements() { let mut b = bitv::Bitv::new(2, false); b.set(0, true); b.set(1, false); @@ -917,7 +915,7 @@ mod tests { } #[test] - pub fn test_10_elements() { + fn test_10_elements() { let mut act; // all 0 @@ -956,7 +954,7 @@ mod tests { } #[test] - pub fn test_31_elements() { + fn test_31_elements() { let mut act; // all 0 @@ -1029,7 +1027,7 @@ mod tests { } #[test] - pub fn test_32_elements() { + fn test_32_elements() { let mut act; // all 0 @@ -1104,7 +1102,7 @@ mod tests { } #[test] - pub fn test_33_elements() { + fn test_33_elements() { let mut act; // all 0 @@ -1180,21 +1178,21 @@ mod tests { } #[test] - pub fn test_equal_differing_sizes() { + fn test_equal_differing_sizes() { let v0 = Bitv::new(10u, false); let v1 = Bitv::new(11u, false); assert!(!v0.equal(&v1)); } #[test] - pub fn test_equal_greatly_differing_sizes() { + fn test_equal_greatly_differing_sizes() { let v0 = Bitv::new(10u, false); let v1 = Bitv::new(110u, false); assert!(!v0.equal(&v1)); } #[test] - pub fn test_equal_sneaky_small() { + fn test_equal_sneaky_small() { let mut a = bitv::Bitv::new(1, false); a.set(0, true); @@ -1205,7 +1203,7 @@ mod tests { } #[test] - pub fn test_equal_sneaky_big() { + fn test_equal_sneaky_big() { let mut a = bitv::Bitv::new(100, false); for uint::range(0, 100) |i| { a.set(i, true); @@ -1220,14 +1218,14 @@ mod tests { } #[test] - pub fn test_from_bytes() { + fn test_from_bytes() { let bitv = from_bytes([0b10110110, 0b00000000, 0b11111111]); let str = ~"10110110" + ~"00000000" + ~"11111111"; assert!(bitv.to_str() == str); } #[test] - pub fn test_to_bytes() { + fn test_to_bytes() { let mut bv = Bitv::new(3, true); bv.set(1, false); assert!(bv.to_bytes() == ~[0b10100000]); @@ -1239,19 +1237,19 @@ mod tests { } #[test] - pub fn test_from_bools() { + fn test_from_bools() { assert!(from_bools([true, false, true, true]).to_str() == ~"1011"); } #[test] - pub fn test_to_bools() { + fn test_to_bools() { let bools = ~[false, false, true, false, false, true, true, false]; assert!(from_bytes([0b00100110]).to_bools() == bools); } #[test] - pub fn test_small_difference() { + fn test_small_difference() { let mut b1 = Bitv::new(3, false); let mut b2 = Bitv::new(3, false); b1.set(0, true); @@ -1265,7 +1263,7 @@ mod tests { } #[test] - pub fn test_big_difference() { + fn test_big_difference() { let mut b1 = Bitv::new(100, false); let mut b2 = Bitv::new(100, false); b1.set(0, true); @@ -1279,7 +1277,7 @@ mod tests { } #[test] - pub fn test_small_clear() { + fn test_small_clear() { let mut b = Bitv::new(14, true); b.clear(); for b.ones |i| { @@ -1288,7 +1286,7 @@ mod tests { } #[test] - pub fn test_big_clear() { + fn test_big_clear() { let mut b = Bitv::new(140, true); b.clear(); for b.ones |i| { @@ -1297,7 +1295,7 @@ mod tests { } #[test] - pub fn test_bitv_set_basic() { + fn test_bitv_set_basic() { let mut b = BitvSet::new(); assert!(b.insert(3)); assert!(!b.insert(3)); @@ -1384,7 +1382,7 @@ mod tests { } #[test] - pub fn test_bitv_set_union() { + fn test_bitv_set_union() { let mut a = BitvSet::new(); let mut b = BitvSet::new(); assert!(a.insert(1)); @@ -1412,7 +1410,7 @@ mod tests { } #[test] - pub fn test_bitv_remove() { + fn test_bitv_remove() { let mut a = BitvSet::new(); assert!(a.insert(1)); @@ -1432,7 +1430,7 @@ mod tests { } #[bench] - pub fn bench_uint_small(b: &mut BenchHarness) { + fn bench_uint_small(b: &mut BenchHarness) { let r = rng(); let mut bitv = 0 as uint; do b.iter { @@ -1441,7 +1439,7 @@ mod tests { } #[bench] - pub fn bench_small_bitv_small(b: &mut BenchHarness) { + fn bench_small_bitv_small(b: &mut BenchHarness) { let r = rng(); let mut bitv = SmallBitv::new(uint::bits); do b.iter { @@ -1450,7 +1448,7 @@ mod tests { } #[bench] - pub fn bench_big_bitv_small(b: &mut BenchHarness) { + fn bench_big_bitv_small(b: &mut BenchHarness) { let r = rng(); let mut bitv = BigBitv::new(~[0]); do b.iter { @@ -1459,7 +1457,7 @@ mod tests { } #[bench] - pub fn bench_big_bitv_big(b: &mut BenchHarness) { + fn bench_big_bitv_big(b: &mut BenchHarness) { let r = rng(); let mut storage = ~[]; storage.grow(bench_bits / uint::bits, &0); @@ -1470,7 +1468,7 @@ mod tests { } #[bench] - pub fn bench_bitv_big(b: &mut BenchHarness) { + fn bench_bitv_big(b: &mut BenchHarness) { let r = rng(); let mut bitv = Bitv::new(bench_bits, false); do b.iter { @@ -1479,7 +1477,7 @@ mod tests { } #[bench] - pub fn bench_bitv_small(b: &mut BenchHarness) { + fn bench_bitv_small(b: &mut BenchHarness) { let r = rng(); let mut bitv = Bitv::new(uint::bits, false); do b.iter { @@ -1488,7 +1486,7 @@ mod tests { } #[bench] - pub fn bench_bitv_set_small(b: &mut BenchHarness) { + fn bench_bitv_set_small(b: &mut BenchHarness) { let r = rng(); let mut bitv = BitvSet::new(); do b.iter { @@ -1497,7 +1495,7 @@ mod tests { } #[bench] - pub fn bench_bitv_set_big(b: &mut BenchHarness) { + fn bench_bitv_set_big(b: &mut BenchHarness) { let r = rng(); let mut bitv = BitvSet::new(); do b.iter { @@ -1506,7 +1504,7 @@ mod tests { } #[bench] - pub fn bench_bitv_big_union(b: &mut BenchHarness) { + fn bench_bitv_big_union(b: &mut BenchHarness) { let mut b1 = Bitv::new(bench_bits, false); let mut b2 = Bitv::new(bench_bits, false); do b.iter { diff --git a/src/libstd/c_vec.rs b/src/libstd/c_vec.rs index 113c8130349ff..a59c76c809b13 100644 --- a/src/libstd/c_vec.rs +++ b/src/libstd/c_vec.rs @@ -57,11 +57,9 @@ struct DtorRes { #[unsafe_destructor] impl Drop for DtorRes { fn finalize(&self) { - unsafe { - match self.dtor { - option::None => (), - option::Some(f) => f() - } + match self.dtor { + option::None => (), + option::Some(f) => f() } } } @@ -84,7 +82,7 @@ fn DtorRes(dtor: Option<@fn()>) -> DtorRes { * * base - A foreign pointer to a buffer * * len - The number of elements in the buffer */ -pub unsafe fn CVec(base: *mut T, len: uint) -> CVec { +pub fn CVec(base: *mut T, len: uint) -> CVec { return CVec{ base: base, len: len, @@ -103,7 +101,7 @@ pub unsafe fn CVec(base: *mut T, len: uint) -> CVec { * * dtor - A function to run when the value is destructed, useful * for freeing the buffer, etc. */ -pub unsafe fn c_vec_with_dtor(base: *mut T, len: uint, dtor: @fn()) +pub fn c_vec_with_dtor(base: *mut T, len: uint, dtor: @fn()) -> CVec { return CVec{ base: base, @@ -144,7 +142,7 @@ pub fn set(t: CVec, ofs: uint, v: T) { pub fn len(t: CVec) -> uint { t.len } /// Returns a pointer to the first element of the vector -pub unsafe fn ptr(t: CVec) -> *mut T { t.base } +pub fn ptr(t: CVec) -> *mut T { t.base } #[cfg(test)] mod tests { diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index e7ec86963eeb5..a88d13fda6621 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -41,6 +41,7 @@ impl Mutable for Deque { } } +#[cfg(stage0)] pub impl Deque { /// Create an empty Deque fn new() -> Deque { @@ -51,21 +52,142 @@ pub impl Deque { /// Return a reference to the first element in the deque /// /// Fails if the deque is empty + #[cfg(stage0)] fn peek_front(&self) -> &'self T { get(self.elts, self.lo) } + /// Return a reference to the first element in the deque + /// + /// Fails if the deque is empty + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn peek_front<'a>(&'a self) -> &'a T { get(self.elts, self.lo) } + /// Return a reference to the last element in the deque /// /// Fails if the deque is empty + #[cfg(stage0)] fn peek_back(&self) -> &'self T { get(self.elts, self.hi - 1u) } + /// Return a reference to the last element in the deque + /// + /// Fails if the deque is empty + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn peek_back<'a>(&'a self) -> &'a T { get(self.elts, self.hi - 1u) } + /// Retrieve an element in the deque by index /// /// Fails if there is no element with the given index + #[cfg(stage0)] fn get(&self, i: int) -> &'self T { let idx = (self.lo + (i as uint)) % self.elts.len(); get(self.elts, idx) } + /// Retrieve an element in the deque by index + /// + /// Fails if there is no element with the given index + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get<'a>(&'a self, i: int) -> &'a T { + let idx = (self.lo + (i as uint)) % self.elts.len(); + get(self.elts, idx) + } + + /// Iterate over the elements in the deque + fn each(&self, f: &fn(&T) -> bool) { + self.eachi(|_i, e| f(e)) + } + + /// Iterate over the elements in the deque by index + fn eachi(&self, f: &fn(uint, &T) -> bool) { + for uint::range(0, self.nelts) |i| { + if !f(i, self.get(i as int)) { return; } + } + } + + /// Remove and return the first element in the deque + /// + /// Fails if the deque is empty + fn pop_front(&mut self) -> T { + let mut result = self.elts[self.lo].swap_unwrap(); + self.lo = (self.lo + 1u) % self.elts.len(); + self.nelts -= 1u; + result + } + + /// Remove and return the last element in the deque + /// + /// Fails if the deque is empty + fn pop_back(&mut self) -> T { + if self.hi == 0u { + self.hi = self.elts.len() - 1u; + } else { self.hi -= 1u; } + let mut result = self.elts[self.hi].swap_unwrap(); + self.elts[self.hi] = None; + self.nelts -= 1u; + result + } + + /// Prepend an element to the deque + fn add_front(&mut self, t: T) { + let oldlo = self.lo; + if self.lo == 0u { + self.lo = self.elts.len() - 1u; + } else { self.lo -= 1u; } + if self.lo == self.hi { + self.elts = grow(self.nelts, oldlo, self.elts); + self.lo = self.elts.len() - 1u; + self.hi = self.nelts; + } + self.elts[self.lo] = Some(t); + self.nelts += 1u; + } + + /// Append an element to the deque + fn add_back(&mut self, t: T) { + if self.lo == self.hi && self.nelts != 0u { + self.elts = grow(self.nelts, self.lo, self.elts); + self.lo = 0u; + self.hi = self.nelts; + } + self.elts[self.hi] = Some(t); + self.hi = (self.hi + 1u) % self.elts.len(); + self.nelts += 1u; + } +} + +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] +pub impl Deque { + /// Create an empty Deque + fn new() -> Deque { + Deque{nelts: 0, lo: 0, hi: 0, + elts: vec::from_fn(initial_capacity, |_| None)} + } + + /// Return a reference to the first element in the deque + /// + /// Fails if the deque is empty + fn peek_front<'a>(&'a self) -> &'a T { get(self.elts, self.lo) } + + /// Return a reference to the last element in the deque + /// + /// Fails if the deque is empty + fn peek_back<'a>(&'a self) -> &'a T { get(self.elts, self.hi - 1u) } + + /// Retrieve an element in the deque by index + /// + /// Fails if there is no element with the given index + fn get<'a>(&'a self, i: int) -> &'a T { + let idx = (self.lo + (i as uint)) % self.elts.len(); + get(self.elts, idx) + } + /// Iterate over the elements in the deque fn each(&self, f: &fn(&T) -> bool) { self.eachi(|_i, e| f(e)) diff --git a/src/libstd/dlist.rs b/src/libstd/dlist.rs index e7701974097b3..f9de2e0f58ad0 100644 --- a/src/libstd/dlist.rs +++ b/src/libstd/dlist.rs @@ -99,7 +99,7 @@ pub fn DList() -> @mut DList { /// Creates a new dlist with a single element pub fn from_elem(data: T) -> @mut DList { let list = DList(); - unsafe { list.push(data); } + list.push(data); list } @@ -484,11 +484,8 @@ pub impl DList { /// Get the elements of the list as a vector. O(n). fn to_vec(@mut self) -> ~[T] { let mut v = vec::with_capacity(self.size); - unsafe { - // Take this out of the unchecked when iter's functions are pure - for iter::eachi(&self) |index,data| { - v[index] = *data; - } + for iter::eachi(&self) |index,data| { + v[index] = *data; } v } @@ -540,7 +537,7 @@ mod tests { use core::prelude::*; #[test] - pub fn test_dlist_concat() { + fn test_dlist_concat() { let a = from_vec(~[1,2]); let b = from_vec(~[3,4]); let c = from_vec(~[5,6]); @@ -560,7 +557,7 @@ mod tests { abcd.assert_consistent(); assert!(abcd.is_empty()); } #[test] - pub fn test_dlist_append() { + fn test_dlist_append() { let a = from_vec(~[1,2,3]); let b = from_vec(~[4,5,6]); a.append(b); @@ -576,7 +573,7 @@ mod tests { a.assert_consistent(); assert!(a.is_empty()); } #[test] - pub fn test_dlist_append_empty() { + fn test_dlist_append_empty() { let a = from_vec(~[1,2,3]); let b = DList::(); a.append(b); @@ -589,7 +586,7 @@ mod tests { a.assert_consistent(); assert!(a.is_empty()); } #[test] - pub fn test_dlist_append_to_empty() { + fn test_dlist_append_to_empty() { let a = DList::(); let b = from_vec(~[4,5,6]); a.append(b); @@ -602,7 +599,7 @@ mod tests { a.assert_consistent(); assert!(a.is_empty()); } #[test] - pub fn test_dlist_append_two_empty() { + fn test_dlist_append_two_empty() { let a = DList::(); let b = DList::(); a.append(b); @@ -614,19 +611,19 @@ mod tests { #[test] #[ignore(cfg(windows))] #[should_fail] - pub fn test_dlist_append_self() { + fn test_dlist_append_self() { let a = DList::(); a.append(a); } #[test] #[ignore(cfg(windows))] #[should_fail] - pub fn test_dlist_prepend_self() { + fn test_dlist_prepend_self() { let a = DList::(); a.prepend(a); } #[test] - pub fn test_dlist_prepend() { + fn test_dlist_prepend() { let a = from_vec(~[1,2,3]); let b = from_vec(~[4,5,6]); b.prepend(a); @@ -642,7 +639,7 @@ mod tests { b.assert_consistent(); assert!(b.is_empty()); } #[test] - pub fn test_dlist_reverse() { + fn test_dlist_reverse() { let a = from_vec(~[5,4,3,2,1]); a.reverse(); assert_eq!(a.len(), 5); @@ -654,14 +651,14 @@ mod tests { a.assert_consistent(); assert!(a.is_empty()); } #[test] - pub fn test_dlist_reverse_empty() { + fn test_dlist_reverse_empty() { let a = DList::(); a.reverse(); assert_eq!(a.len(), 0); a.assert_consistent(); } #[test] - pub fn test_dlist_each_node() { + fn test_dlist_each_node() { let a = from_vec(~[1,2,4,5]); for a.each_node |nobe| { if nobe.data > 3 { @@ -678,28 +675,28 @@ mod tests { a.assert_consistent(); assert!(a.is_empty()); } #[test] - pub fn test_dlist_clear() { + fn test_dlist_clear() { let a = from_vec(~[5,4,3,2,1]); a.clear(); assert_eq!(a.len(), 0); a.assert_consistent(); } #[test] - pub fn test_dlist_is_empty() { + fn test_dlist_is_empty() { let empty = DList::(); let full1 = from_vec(~[1,2,3]); assert!(empty.is_empty()); assert!(!full1.is_empty()); } #[test] - pub fn test_dlist_head_tail() { + fn test_dlist_head_tail() { let l = from_vec(~[1,2,3]); assert_eq!(l.head(), 1); assert_eq!(l.tail(), 3); assert_eq!(l.len(), 3); } #[test] - pub fn test_dlist_pop() { + fn test_dlist_pop() { let l = from_vec(~[1,2,3]); assert_eq!(l.pop().get(), 1); assert_eq!(l.tail(), 3); @@ -712,7 +709,7 @@ mod tests { assert!(l.pop().is_none()); } #[test] - pub fn test_dlist_pop_tail() { + fn test_dlist_pop_tail() { let l = from_vec(~[1,2,3]); assert_eq!(l.pop_tail().get(), 3); assert_eq!(l.tail(), 2); @@ -725,7 +722,7 @@ mod tests { assert!(l.pop_tail().is_none()); } #[test] - pub fn test_dlist_push() { + fn test_dlist_push() { let l = DList::(); l.push(1); assert_eq!(l.head(), 1); @@ -739,7 +736,7 @@ mod tests { assert_eq!(l.len(), 3); } #[test] - pub fn test_dlist_push_head() { + fn test_dlist_push_head() { let l = DList::(); l.push_head(3); assert_eq!(l.head(), 3); @@ -753,12 +750,12 @@ mod tests { assert_eq!(l.len(), 3); } #[test] - pub fn test_dlist_foldl() { + fn test_dlist_foldl() { let l = from_vec(vec::from_fn(101, |x|x)); assert_eq!(iter::foldl(&l, 0, |accum,elem| *accum+*elem), 5050); } #[test] - pub fn test_dlist_break_early() { + fn test_dlist_break_early() { let l = from_vec(~[1,2,3,4,5]); let mut x = 0; for l.each |i| { @@ -768,7 +765,7 @@ mod tests { assert_eq!(x, 3); } #[test] - pub fn test_dlist_remove_head() { + fn test_dlist_remove_head() { let l = DList::(); l.assert_consistent(); let one = l.push_n(1); l.assert_consistent(); let _two = l.push_n(2); @@ -783,7 +780,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_remove_mid() { + fn test_dlist_remove_mid() { let l = DList::(); l.assert_consistent(); let _one = l.push_n(1); l.assert_consistent(); let two = l.push_n(2); @@ -798,7 +795,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_remove_tail() { + fn test_dlist_remove_tail() { let l = DList::(); l.assert_consistent(); let _one = l.push_n(1); l.assert_consistent(); let _two = l.push_n(2); @@ -813,7 +810,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_remove_one_two() { + fn test_dlist_remove_one_two() { let l = DList::(); l.assert_consistent(); let one = l.push_n(1); l.assert_consistent(); let two = l.push_n(2); @@ -829,7 +826,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_remove_one_three() { + fn test_dlist_remove_one_three() { let l = DList::(); l.assert_consistent(); let one = l.push_n(1); l.assert_consistent(); let _two = l.push_n(2); @@ -844,7 +841,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_remove_two_three() { + fn test_dlist_remove_two_three() { let l = DList::(); l.assert_consistent(); let _one = l.push_n(1); l.assert_consistent(); let two = l.push_n(2); @@ -859,7 +856,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_remove_all() { + fn test_dlist_remove_all() { let l = DList::(); l.assert_consistent(); let one = l.push_n(1); l.assert_consistent(); let two = l.push_n(2); @@ -872,7 +869,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_insert_n_before() { + fn test_dlist_insert_n_before() { let l = DList::(); l.assert_consistent(); let _one = l.push_n(1); l.assert_consistent(); let two = l.push_n(2); @@ -888,7 +885,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_insert_n_after() { + fn test_dlist_insert_n_after() { let l = DList::(); l.assert_consistent(); let one = l.push_n(1); l.assert_consistent(); let _two = l.push_n(2); @@ -904,7 +901,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_insert_before_head() { + fn test_dlist_insert_before_head() { let l = DList::(); l.assert_consistent(); let one = l.push_n(1); l.assert_consistent(); let _two = l.push_n(2); @@ -919,7 +916,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] - pub fn test_dlist_insert_after_tail() { + fn test_dlist_insert_after_tail() { let l = DList::(); l.assert_consistent(); let _one = l.push_n(1); l.assert_consistent(); let two = l.push_n(2); @@ -934,7 +931,7 @@ mod tests { l.assert_consistent(); assert!(l.is_empty()); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_dlist_asymmetric_link() { + fn test_dlist_asymmetric_link() { let l = DList::(); let _one = l.push_n(1); let two = l.push_n(2); @@ -942,7 +939,7 @@ mod tests { l.assert_consistent(); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_dlist_cyclic_list() { + fn test_dlist_cyclic_list() { let l = DList::(); let one = l.push_n(1); let _two = l.push_n(2); @@ -952,32 +949,32 @@ mod tests { l.assert_consistent(); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_dlist_headless() { + fn test_dlist_headless() { DList::().head(); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_dlist_insert_already_present_before() { + fn test_dlist_insert_already_present_before() { let l = DList::(); let one = l.push_n(1); let two = l.push_n(2); l.insert_n_before(two, one); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_dlist_insert_already_present_after() { + fn test_dlist_insert_already_present_after() { let l = DList::(); let one = l.push_n(1); let two = l.push_n(2); l.insert_n_after(one, two); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_dlist_insert_before_orphan() { + fn test_dlist_insert_before_orphan() { let l = DList::(); let one = new_dlist_node(1); let two = new_dlist_node(2); l.insert_n_before(one, two); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_dlist_insert_after_orphan() { + fn test_dlist_insert_after_orphan() { let l = DList::(); let one = new_dlist_node(1); let two = new_dlist_node(2); diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index b117c8d9882ba..4a3447700bc8f 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -335,18 +335,18 @@ pub mod reader { f() } - fn read_seq(&self, f: &fn(uint) -> T) -> T { - debug!("read_seq()"); - do self.push_doc(self.next_doc(EsVec)) { - let len = self._next_uint(EsVecLen); - debug!(" len=%u", len); - f(len) + fn read_enum_struct_variant(&self, _names: &[&str], f: &fn(uint) -> T) -> T { + debug!("read_enum_struct_variant()"); + let idx = self._next_uint(EsEnumVid); + debug!(" idx=%u", idx); + do self.push_doc(self.next_doc(EsEnumBody)) { + f(idx) } } - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_seq_elt(idx=%u)", idx); - self.push_doc(self.next_doc(EsVecElt), f) + fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_enum_struct_variant_arg(name=%?, idx=%u)", name, idx); + f() } fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T { @@ -354,12 +354,42 @@ pub mod reader { f() } + #[cfg(stage0)] fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%s, idx=%u)", name, idx); + debug!("read_field(name=%?, idx=%u)", name, idx); self._check_label(name); f() } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_struct_field(name=%?, idx=%u)", name, idx); + self._check_label(name); + f() + } + + fn read_tuple(&self, f: &fn(uint) -> T) -> T { + debug!("read_tuple()"); + self.read_seq(f) + } + + fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_arg(idx=%u)", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { + debug!("read_tuple_struct(name=%?)", name); + self.read_tuple(f) + } + + fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_struct_arg(idx=%u)", idx); + self.read_tuple_arg(idx, f) + } + fn read_option(&self, f: &fn(bool) -> T) -> T { debug!("read_option()"); do self.read_enum("Option") || { @@ -373,6 +403,20 @@ pub mod reader { } } + fn read_seq(&self, f: &fn(uint) -> T) -> T { + debug!("read_seq()"); + do self.push_doc(self.next_doc(EsVec)) { + let len = self._next_uint(EsVecLen); + debug!(" len=%u", len); + f(len) + } + } + + fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_seq_elt(idx=%u)", idx); + self.push_doc(self.next_doc(EsVecElt), f) + } + fn read_map(&self, _f: &fn(uint) -> T) -> T { debug!("read_map()"); fail!(~"read_map is unimplemented"); @@ -606,29 +650,42 @@ pub mod writer { self._emit_label(name); self.wr_tag(EsEnum as uint, f) } + fn emit_enum_variant(&self, _v_name: &str, v_id: uint, _cnt: uint, f: &fn()) { self._emit_tagged_uint(EsEnumVid, v_id); self.wr_tag(EsEnumBody as uint, f) } + fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) { f() } - fn emit_seq(&self, len: uint, f: &fn()) { - do self.wr_tag(EsVec as uint) { - self._emit_tagged_uint(EsVecLen, len); - f() - } + fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(v_name, v_id, cnt, f) } - fn emit_seq_elt(&self, _idx: uint, f: &fn()) { - self.wr_tag(EsVecElt as uint, f) + fn emit_enum_struct_variant_field(&self, _f_name: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) } fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { f() } + #[cfg(stage0)] fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { self._emit_label(name); f() } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, name: &str, _idx: uint, f: &fn()) { + self._emit_label(name); + f() + } + + fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } fn emit_option(&self, f: &fn()) { self.emit_enum("Option", f); @@ -640,6 +697,17 @@ pub mod writer { self.emit_enum_variant("Some", 1, 1, f) } + fn emit_seq(&self, len: uint, f: &fn()) { + do self.wr_tag(EsVec as uint) { + self._emit_tagged_uint(EsVecLen, len); + f() + } + } + + fn emit_seq_elt(&self, _idx: uint, f: &fn()) { + self.wr_tag(EsVecElt as uint, f) + } + fn emit_map(&self, _len: uint, _f: &fn()) { fail!(~"emit_map is unimplemented"); } diff --git a/src/libstd/fileinput.rs b/src/libstd/fileinput.rs new file mode 100644 index 0000000000000..4ac3e0b174729 --- /dev/null +++ b/src/libstd/fileinput.rs @@ -0,0 +1,611 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! +A library for iterating through the lines in a series of +files. Very similar to [the Python module of the same +name](http://docs.python.org/3.3/library/fileinput.html). + +It allows the programmer to automatically take filenames from the +command line arguments (via `input` and `input_state`), as well as +specify them as a vector directly (`input_vec` and +`input_vec_state`). The files are opened as necessary, so any files +that can't be opened only cause an error when reached in the +iteration. + +On the command line, `stdin` is represented by a filename of `-` (a +single hyphen) and in the functions that take a vector directly +(e.g. `input_vec`) it is represented by `None`. Note `stdin` is *not* +reset once it has been finished, so attempting to iterate on `[None, +None]` will only take input once unless `io::stdin().seek(0, SeekSet)` +is called between. + +The `pathify` function handles converting a list of file paths as +strings to the appropriate format, including the (optional) conversion +of `"-"` to `stdin`. + +# Basic + +In many cases, one can use the `input_*` functions without having +to handle any `FileInput` structs. E.g. a simple `cat` program + + for input |line| { + io::println(line) + } + +or a program that numbers lines after concatenating two files + + for input_vec_state(pathify([~"a.txt", ~"b.txt"])) |line, state| { + io::println(fmt!("%u: %s", state.line_num, + line)); + } + +The two `input_vec*` functions take a vec of file names (where empty +means read from `stdin`), the other two functions use the command line +arguments. + +# Advanced + +For more complicated uses (e.g. if one needs to pause iteration and +resume it later), a `FileInput` instance can be constructed via the +`from_vec`, `from_vec_raw` and `from_args` functions. + +Once created, the `each_line` (from the `core::io::ReaderUtil` trait) +and `each_line_state` methods allow one to iterate on the lines; the +latter provides more information about the position within the +iteration to the caller. + +It is possible (and safe) to skip lines and files using the +`read_line` and `next_file` methods. Also, `FileInput` implements +`core::io::Reader`, and the state will be updated correctly while +using any of those methods. + +E.g. the following program reads until an empty line, pauses for user +input, skips the current file and then numbers the remaining lines +(where the numbers are from the start of each file, rather than the +total line count). + + let in = FileInput::from_vec(pathify([~"a.txt", ~"b.txt", ~"c.txt"], + true)); + + for in.each_line |line| { + if line.is_empty() { + break + } + io::println(line); + } + + io::println("Continue?"); + + if io::stdin().read_line() == ~"yes" { + in.next_file(); // skip! + + for in.each_line_state |line, state| { + io::println(fmt!("%u: %s", state.line_num_file, + line)) + } + } +*/ + +#[allow(deprecated_mutable_fields)]; + +use core::prelude::*; +use core::io::ReaderUtil; + +/** +A summary of the internal state of a `FileInput` object. `line_num` +and `line_num_file` represent the number of lines read in total and in +the current file respectively. `current_path` is `None` if the current +file is `stdin`. +*/ +pub struct FileInputState { + current_path: Option, + line_num: uint, + line_num_file: uint +} + +impl FileInputState { + fn is_stdin(&self) -> bool { + self.current_path.is_none() + } + + fn is_first_line(&self) -> bool { + self.line_num_file == 1 + } +} + +struct FileInput_ { + /** + `Some(path)` is the file represented by `path`, `None` is + `stdin`. Consumed as the files are read. + */ + priv files: ~[Option], + /** + The current file: `Some(r)` for an open file, `None` before + starting and after reading everything. + */ + priv current_reader: Option<@io::Reader>, + priv state: FileInputState, + + /** + Used to keep track of whether we need to insert the newline at the + end of a file that is missing it, which is needed to separate the + last and first lines. + */ + priv previous_was_newline: bool +} + +// XXX: remove this when Reader has &mut self. Should be removable via +// "self.fi." -> "self." and renaming FileInput_. Documentation above +// will likely have to be updated to use `let mut in = ...`. +pub struct FileInput { + priv mut fi: FileInput_ +} + +impl FileInput { + /** + Create a `FileInput` object from a vec of files. An empty + vec means lines are read from `stdin` (use `from_vec_raw` to stop + this behaviour). Any occurence of `None` represents `stdin`. + */ + pub fn from_vec(files: ~[Option]) -> FileInput { + FileInput::from_vec_raw( + if files.is_empty() { + ~[None] + } else { + files + }) + } + + /** + Identical to `from_vec`, but an empty `files` vec stays + empty. (`None` is `stdin`.) + */ + pub fn from_vec_raw(files: ~[Option]) + -> FileInput { + FileInput{ + fi: FileInput_ { + files: files, + current_reader: None, + state: FileInputState { + current_path: None, + line_num: 0, + line_num_file: 0 + }, + // there was no previous unended line + previous_was_newline: true + } + } + } + + /** + Create a `FileInput` object from the command line + arguments. `"-"` represents `stdin`. + */ + pub fn from_args() -> FileInput { + let args = os::args(), + pathed = pathify(args.tail(), true); + FileInput::from_vec(pathed) + } + + priv fn current_file_eof(&self) -> bool { + match self.fi.current_reader { + None => false, + Some(r) => r.eof() + } + } + + /** + Skip to the next file in the queue. Can `fail` when opening + a file. + + Returns `false` if there is no more files, and `true` when it + successfully opens the next file. + */ + + pub fn next_file(&self) -> bool { + // No more files + + // Compiler whines about "illegal borrow unless pure" for + // files.is_empty() + if unsafe { self.fi.files.is_empty() } { + self.fi.current_reader = None; + return false; + } + + let path_option = self.fi.files.shift(), + file = match path_option { + None => io::stdin(), + Some(ref path) => io::file_reader(path).get() + }; + + self.fi.current_reader = Some(file); + self.fi.state.current_path = path_option; + self.fi.state.line_num_file = 0; + true + } + + /** + Attempt to open the next file if there is none currently open, + or if the current one is EOF'd. + + Returns `true` if it had to move to the next file and did + so successfully. + */ + priv fn next_file_if_eof(&self) -> bool { + match self.fi.current_reader { + None => self.next_file(), + Some(r) => { + if r.eof() { + self.next_file() + } else { + false + } + } + } + } + + /** + Apply `f` to each line successively, along with some state + (line numbers and file names, see documentation for + `FileInputState`). Otherwise identical to `lines_each`. + */ + pub fn each_line_state(&self, + f: &fn(&str, FileInputState) -> bool) { + self.each_line(|line| f(line, copy self.fi.state)); + } + + + /** + Retrieve the current `FileInputState` information. + */ + pub fn state(&self) -> FileInputState { + copy self.fi.state + } +} + +impl io::Reader for FileInput { + fn read_byte(&self) -> int { + loop { + let stepped = self.next_file_if_eof(); + + // if we moved to the next file, and the previous + // character wasn't \n, then there is an unfinished line + // from the previous file. This library models + // line-by-line processing and the trailing line of the + // previous file and the leading of the current file + // should be considered different, so we need to insert a + // fake line separator + if stepped && !self.fi.previous_was_newline { + self.fi.state.line_num += 1; + self.fi.state.line_num_file += 1; + self.fi.previous_was_newline = true; + return '\n' as int; + } + + match self.fi.current_reader { + None => return -1, + Some(r) => { + let b = r.read_byte(); + + if b < 0 { + loop; + } + + if b == '\n' as int { + self.fi.state.line_num += 1; + self.fi.state.line_num_file += 1; + self.fi.previous_was_newline = true; + } else { + self.fi.previous_was_newline = false; + } + + return b; + } + } + } + } + fn read(&self, buf: &mut [u8], len: uint) -> uint { + let mut count = 0; + while count < len { + let b = self.read_byte(); + if b < 0 { break } + + buf[count] = b as u8; + count += 1; + } + + count + } + fn eof(&self) -> bool { + // we've run out of files, and current_reader is either None or eof. + + // compiler whines about illegal borrows for files.is_empty() + (unsafe { self.fi.files.is_empty() }) && + match self.fi.current_reader { None => true, Some(r) => r.eof() } + + } + fn seek(&self, offset: int, whence: io::SeekStyle) { + match self.fi.current_reader { + None => {}, + Some(r) => r.seek(offset, whence) + } + } + fn tell(&self) -> uint { + match self.fi.current_reader { + None => 0, + Some(r) => r.tell() + } + } +} + +/** +Convert a list of strings to an appropriate form for a `FileInput` +instance. `stdin_hyphen` controls whether `-` represents `stdin` or +a literal `-`. +*/ +// XXX: stupid, unclear name +pub fn pathify(vec: &[~str], stdin_hyphen : bool) -> ~[Option] { + vec::map(vec, |&str : & ~str| { + if stdin_hyphen && str == ~"-" { + None + } else { + Some(Path(str)) + } + }) +} + +/** +Iterate directly over the command line arguments (no arguments implies +reading from `stdin`). + +Fails when attempting to read from a file that can't be opened. +*/ +pub fn input(f: &fn(&str) -> bool) { + let mut i = FileInput::from_args(); + i.each_line(f); +} + +/** +Iterate directly over the command line arguments (no arguments +implies reading from `stdin`) with the current state of the iteration +provided at each call. + +Fails when attempting to read from a file that can't be opened. +*/ +pub fn input_state(f: &fn(&str, FileInputState) -> bool) { + let mut i = FileInput::from_args(); + i.each_line_state(f); +} + +/** +Iterate over a vector of files (an empty vector implies just `stdin`). + +Fails when attempting to read from a file that can't be opened. +*/ +pub fn input_vec(files: ~[Option], f: &fn(&str) -> bool) { + let mut i = FileInput::from_vec(files); + i.each_line(f); +} + +/** +Iterate over a vector of files (an empty vector implies just `stdin`) +with the current state of the iteration provided at each call. + +Fails when attempting to read from a file that can't be opened. +*/ +pub fn input_vec_state(files: ~[Option], + f: &fn(&str, FileInputState) -> bool) { + let mut i = FileInput::from_vec(files); + i.each_line_state(f); +} + +#[cfg(test)] +mod test { + use core::io::WriterUtil; + use core::prelude::*; + use super::{FileInput, pathify, input_vec, input_vec_state}; + + fn make_file(path : &Path, contents: &[~str]) { + let file = io::file_writer(path, [io::Create, io::Truncate]).get(); + + for contents.each |&str| { + file.write_str(str); + file.write_char('\n'); + } + } + + #[test] + fn test_pathify() { + let strs = [~"some/path", + ~"some/other/path"], + paths = ~[Some(Path("some/path")), + Some(Path("some/other/path"))]; + + assert_eq!(pathify(strs, true), copy paths); + assert_eq!(pathify(strs, false), paths); + + assert_eq!(pathify([~"-"], true), ~[None]); + assert_eq!(pathify([~"-"], false), ~[Some(Path("-"))]); + } + + #[test] + fn test_fileinput_read_byte() { + let filenames = pathify(vec::from_fn( + 3, + |i| fmt!("tmp/lib-fileinput-test-fileinput-read-byte-%u.tmp", i)), true); + + // 3 files containing 0\n, 1\n, and 2\n respectively + for filenames.eachi |i, &filename| { + make_file(filename.get_ref(), ~[fmt!("%u", i)]); + } + + let fi = FileInput::from_vec(copy filenames); + + for "012".each_chari |line, c| { + assert_eq!(fi.read_byte(), c as int); + assert_eq!(fi.state().line_num, line); + assert_eq!(fi.state().line_num_file, 0); + assert_eq!(fi.read_byte(), '\n' as int); + assert_eq!(fi.state().line_num, line + 1); + assert_eq!(fi.state().line_num_file, 1); + + assert_eq!(copy fi.state().current_path, copy filenames[line]); + } + + assert_eq!(fi.read_byte(), -1); + assert!(fi.eof()); + assert_eq!(fi.state().line_num, 3) + + } + + #[test] + fn test_fileinput_read() { + let filenames = pathify(vec::from_fn( + 3, + |i| fmt!("tmp/lib-fileinput-test-fileinput-read-%u.tmp", i)), true); + + // 3 files containing 1\n, 2\n, and 3\n respectively + for filenames.eachi |i, &filename| { + make_file(filename.get_ref(), ~[fmt!("%u", i)]); + } + + let fi = FileInput::from_vec(filenames); + let mut buf : ~[u8] = vec::from_elem(6, 0u8); + let count = fi.read(buf, 10); + assert_eq!(count, 6); + assert_eq!(buf, "0\n1\n2\n".to_bytes()); + assert!(fi.eof()) + assert_eq!(fi.state().line_num, 3); + } + + #[test] + fn test_input_vec() { + let mut all_lines = ~[]; + let filenames = pathify(vec::from_fn( + 3, + |i| fmt!("tmp/lib-fileinput-test-input-vec-%u.tmp", i)), true); + + for filenames.eachi |i, &filename| { + let contents = + vec::from_fn(3, |j| fmt!("%u %u", i, j)); + make_file(filename.get_ref(), contents); + all_lines.push_all(contents); + } + + let mut read_lines = ~[]; + for input_vec(filenames) |line| { + read_lines.push(line.to_owned()); + } + assert_eq!(read_lines, all_lines); + } + + #[test] + fn test_input_vec_state() { + let filenames = pathify(vec::from_fn( + 3, + |i| fmt!("tmp/lib-fileinput-test-input-vec-state-%u.tmp", i)),true); + + for filenames.eachi |i, &filename| { + let contents = + vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); + make_file(filename.get_ref(), contents); + } + + for input_vec_state(filenames) |line, state| { + let nums = do vec::build |p| { + for str::each_split_char(line, ' ') |s| { p(s.to_owned()); } + }; + let file_num = uint::from_str(nums[0]).get(); + let line_num = uint::from_str(nums[1]).get(); + assert_eq!(line_num, state.line_num_file); + assert_eq!(file_num * 3 + line_num, state.line_num); + } + } + + #[test] + fn test_empty_files() { + let filenames = pathify(vec::from_fn( + 3, + |i| fmt!("tmp/lib-fileinput-test-empty-files-%u.tmp", i)),true); + + make_file(filenames[0].get_ref(), ~[~"1", ~"2"]); + make_file(filenames[1].get_ref(), ~[]); + make_file(filenames[2].get_ref(), ~[~"3", ~"4"]); + + let mut count = 0; + for input_vec_state(copy filenames) |line, state| { + let expected_path = match line { + "1" | "2" => copy filenames[0], + "3" | "4" => copy filenames[2], + _ => fail!(~"unexpected line") + }; + assert_eq!(copy state.current_path, expected_path); + count += 1; + } + assert_eq!(count, 4); + } + + #[test] + fn test_no_trailing_newline() { + let f1 = Some(Path("tmp/lib-fileinput-test-no-trailing-newline-1.tmp")), + f2 = Some(Path("tmp/lib-fileinput-test-no-trailing-newline-2.tmp")); + + let wr = io::file_writer(f1.get_ref(), [io::Create, io::Truncate]).get(); + wr.write_str("1\n2"); + let wr = io::file_writer(f2.get_ref(), [io::Create, io::Truncate]).get(); + wr.write_str("3\n4"); + + let mut lines = ~[]; + for input_vec(~[f1, f2]) |line| { + lines.push(line.to_owned()); + } + assert_eq!(lines, ~[~"1", ~"2", ~"3", ~"4"]); + } + + + #[test] + fn test_next_file() { + let filenames = pathify(vec::from_fn( + 3, + |i| fmt!("tmp/lib-fileinput-test-next-file-%u.tmp", i)),true); + + for filenames.eachi |i, &filename| { + let contents = + vec::from_fn(3, |j| fmt!("%u %u", i, j + 1)); + make_file(&filename.get(), contents); + } + + let mut in = FileInput::from_vec(filenames); + + // read once from 0 + assert_eq!(in.read_line(), ~"0 1"); + in.next_file(); // skip the rest of 1 + + // read all lines from 1 (but don't read any from 2), + for uint::range(1, 4) |i| { + assert_eq!(in.read_line(), fmt!("1 %u", i)); + } + // 1 is finished, but 2 hasn't been started yet, so this will + // just "skip" to the beginning of 2 (Python's fileinput does + // the same) + in.next_file(); + + assert_eq!(in.read_line(), ~"2 1"); + } + + #[test] + #[should_fail] + fn test_input_vec_missing_file() { + for input_vec(pathify([~"this/file/doesnt/exist"], true)) |line| { + io::println(line); + } + } +} diff --git a/src/libstd/future.rs b/src/libstd/future.rs index a4887306d2a93..a36f67fc95a00 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -55,7 +55,7 @@ pub impl Future { } pub impl Future { - + #[cfg(stage0)] fn get_ref(&self) -> &'self A { /*! * Executes the future's closure and then returns a borrowed @@ -80,6 +80,34 @@ pub impl Future { } } } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get_ref<'a>(&'a self) -> &'a A { + /*! + * Executes the future's closure and then returns a borrowed + * pointer to the result. The borrowed pointer lasts as long as + * the future. + */ + unsafe { + match self.state { + Forced(ref mut v) => { return cast::transmute(v); } + Evaluating => fail!(~"Recursive forcing of future!"), + Pending(_) => {} + } + + let mut state = Evaluating; + self.state <-> state; + match state { + Forced(_) | Evaluating => fail!(~"Logic error."), + Pending(f) => { + self.state = Forced(f()); + self.get_ref() + } + } + } + } } pub fn from_value(val: A) -> Future { @@ -144,7 +172,7 @@ pub fn spawn(blk: ~fn() -> A) -> Future { #[allow(non_implicitly_copyable_typarams)] #[cfg(test)] -pub mod test { +mod test { use core::prelude::*; use future::*; @@ -153,13 +181,13 @@ pub mod test { use core::task; #[test] - pub fn test_from_value() { + fn test_from_value() { let f = from_value(~"snail"); assert!(f.get() == ~"snail"); } #[test] - pub fn test_from_port() { + fn test_from_port() { let (ch, po) = oneshot::init(); send_one(ch, ~"whale"); let f = from_port(po); @@ -167,25 +195,25 @@ pub mod test { } #[test] - pub fn test_from_fn() { + fn test_from_fn() { let f = from_fn(|| ~"brail"); assert!(f.get() == ~"brail"); } #[test] - pub fn test_interface_get() { + fn test_interface_get() { let f = from_value(~"fail"); assert!(f.get() == ~"fail"); } #[test] - pub fn test_get_ref_method() { + fn test_get_ref_method() { let f = from_value(22); assert!(*f.get_ref() == 22); } #[test] - pub fn test_spawn() { + fn test_spawn() { let f = spawn(|| ~"bale"); assert!(f.get() == ~"bale"); } @@ -193,13 +221,13 @@ pub mod test { #[test] #[should_fail] #[ignore(cfg(target_os = "win32"))] - pub fn test_futurefail() { + fn test_futurefail() { let f = spawn(|| fail!()); let _x: ~str = f.get(); } #[test] - pub fn test_sendable_future() { + fn test_sendable_future() { let expected = ~"schlorf"; let f = do spawn { copy expected }; do task::spawn || { diff --git a/src/libstd/getopts.rs b/src/libstd/getopts.rs index df37c48ebe8b8..d710a7b873548 100644 --- a/src/libstd/getopts.rs +++ b/src/libstd/getopts.rs @@ -223,128 +223,126 @@ pub type Result = result::Result; * Use to get an error message. */ pub fn getopts(args: &[~str], opts: &[Opt]) -> Result { - unsafe { - let n_opts = opts.len(); - fn f(_x: uint) -> ~[Optval] { return ~[]; } - let mut vals = vec::from_fn(n_opts, f); - let mut free: ~[~str] = ~[]; - let l = args.len(); - let mut i = 0; - while i < l { - let cur = args[i]; - let curlen = cur.len(); - if !is_arg(cur) { - free.push(cur); - } else if cur == ~"--" { - let mut j = i + 1; - while j < l { free.push(args[j]); j += 1; } - break; - } else { - let mut names; - let mut i_arg = None; - if cur[1] == '-' as u8 { - let tail = str::slice(cur, 2, curlen).to_owned(); - let mut tail_eq = ~[]; - for str::each_splitn_char(tail, '=', 1) |s| { tail_eq.push(s.to_owned()) } - if tail_eq.len() <= 1 { - names = ~[Long(tail)]; - } else { - names = - ~[Long(tail_eq[0])]; - i_arg = Some(tail_eq[1]); - } + let n_opts = opts.len(); + fn f(_x: uint) -> ~[Optval] { return ~[]; } + let mut vals = vec::from_fn(n_opts, f); + let mut free: ~[~str] = ~[]; + let l = args.len(); + let mut i = 0; + while i < l { + let cur = args[i]; + let curlen = cur.len(); + if !is_arg(cur) { + free.push(cur); + } else if cur == ~"--" { + let mut j = i + 1; + while j < l { free.push(args[j]); j += 1; } + break; + } else { + let mut names; + let mut i_arg = None; + if cur[1] == '-' as u8 { + let tail = str::slice(cur, 2, curlen).to_owned(); + let mut tail_eq = ~[]; + for str::each_splitn_char(tail, '=', 1) |s| { tail_eq.push(s.to_owned()) } + if tail_eq.len() <= 1 { + names = ~[Long(tail)]; } else { - let mut j = 1; - let mut last_valid_opt_id = None; - names = ~[]; - while j < curlen { - let range = str::char_range_at(cur, j); - let opt = Short(range.ch); - - /* In a series of potential options (eg. -aheJ), if we - see one which takes an argument, we assume all - subsequent characters make up the argument. This - allows options such as -L/usr/local/lib/foo to be - interpreted correctly - */ - - match find_opt(opts, opt) { - Some(id) => last_valid_opt_id = Some(id), - None => { - let arg_follows = - last_valid_opt_id.is_some() && - match opts[last_valid_opt_id.get()] - .hasarg { - - Yes | Maybe => true, - No => false - }; - if arg_follows && j < curlen { - i_arg = Some(cur.slice(j, curlen).to_owned()); - break; - } else { - last_valid_opt_id = None; - } - } - } - names.push(opt); - j = range.next; - } + names = + ~[Long(tail_eq[0])]; + i_arg = Some(tail_eq[1]); } - let mut name_pos = 0; - for names.each() |nm| { - name_pos += 1; - let optid = match find_opt(opts, *nm) { - Some(id) => id, - None => return Err(UnrecognizedOption(name_str(nm))) - }; - match opts[optid].hasarg { - No => { - if !i_arg.is_none() { - return Err(UnexpectedArgument(name_str(nm))); + } else { + let mut j = 1; + let mut last_valid_opt_id = None; + names = ~[]; + while j < curlen { + let range = str::char_range_at(cur, j); + let opt = Short(range.ch); + + /* In a series of potential options (eg. -aheJ), if we + see one which takes an argument, we assume all + subsequent characters make up the argument. This + allows options such as -L/usr/local/lib/foo to be + interpreted correctly + */ + + match find_opt(opts, opt) { + Some(id) => last_valid_opt_id = Some(id), + None => { + let arg_follows = + last_valid_opt_id.is_some() && + match opts[last_valid_opt_id.get()] + .hasarg { + + Yes | Maybe => true, + No => false + }; + if arg_follows && j < curlen { + i_arg = Some(cur.slice(j, curlen).to_owned()); + break; + } else { + last_valid_opt_id = None; } - vals[optid].push(Given); - } - Maybe => { - if !i_arg.is_none() { - vals[optid].push(Val(i_arg.get())); - } else if name_pos < names.len() || - i + 1 == l || is_arg(args[i + 1]) { - vals[optid].push(Given); - } else { i += 1; vals[optid].push(Val(args[i])); } - } - Yes => { - if !i_arg.is_none() { - vals[optid].push(Val(i_arg.get())); - } else if i + 1 == l { - return Err(ArgumentMissing(name_str(nm))); - } else { i += 1; vals[optid].push(Val(args[i])); } } } + names.push(opt); + j = range.next; } } - i += 1; - } - i = 0u; - while i < n_opts { - let n = vals[i].len(); - let occ = opts[i].occur; - if occ == Req { - if n == 0 { - return Err(OptionMissing(name_str(&(opts[i].name)))); + let mut name_pos = 0; + for names.each() |nm| { + name_pos += 1; + let optid = match find_opt(opts, *nm) { + Some(id) => id, + None => return Err(UnrecognizedOption(name_str(nm))) + }; + match opts[optid].hasarg { + No => { + if !i_arg.is_none() { + return Err(UnexpectedArgument(name_str(nm))); + } + vals[optid].push(Given); + } + Maybe => { + if !i_arg.is_none() { + vals[optid].push(Val(i_arg.get())); + } else if name_pos < names.len() || + i + 1 == l || is_arg(args[i + 1]) { + vals[optid].push(Given); + } else { i += 1; vals[optid].push(Val(args[i])); } + } + Yes => { + if !i_arg.is_none() { + vals[optid].push(Val(i_arg.get())); + } else if i + 1 == l { + return Err(ArgumentMissing(name_str(nm))); + } else { i += 1; vals[optid].push(Val(args[i])); } + } } } - if occ != Multi { - if n > 1 { - return Err(OptionDuplicated(name_str(&(opts[i].name)))); - } + } + i += 1; + } + i = 0u; + while i < n_opts { + let n = vals[i].len(); + let occ = opts[i].occur; + if occ == Req { + if n == 0 { + return Err(OptionMissing(name_str(&(opts[i].name)))); + } + } + if occ != Multi { + if n > 1 { + return Err(OptionDuplicated(name_str(&(opts[i].name)))); } - i += 1; } - return Ok(Matches {opts: vec::from_slice(opts), - vals: vals, - free: free}); + i += 1; } + return Ok(Matches {opts: vec::from_slice(opts), + vals: vals, + free: free}); } fn opt_vals(mm: &Matches, nm: &str) -> ~[Optval] { @@ -664,7 +662,7 @@ mod tests { use core::result::{Err, Ok}; use core::result; - pub fn check_fail_type(f: Fail_, ft: FailType) { + fn check_fail_type(f: Fail_, ft: FailType) { match f { ArgumentMissing(_) => assert!(ft == ArgumentMissing_), UnrecognizedOption(_) => assert!(ft == UnrecognizedOption_), @@ -677,7 +675,7 @@ mod tests { // Tests for reqopt #[test] - pub fn test_reqopt_long() { + fn test_reqopt_long() { let args = ~[~"--test=20"]; let opts = ~[reqopt(~"test")]; let rs = getopts(args, opts); @@ -691,7 +689,7 @@ mod tests { } #[test] - pub fn test_reqopt_long_missing() { + fn test_reqopt_long_missing() { let args = ~[~"blah"]; let opts = ~[reqopt(~"test")]; let rs = getopts(args, opts); @@ -702,7 +700,7 @@ mod tests { } #[test] - pub fn test_reqopt_long_no_arg() { + fn test_reqopt_long_no_arg() { let args = ~[~"--test"]; let opts = ~[reqopt(~"test")]; let rs = getopts(args, opts); @@ -713,7 +711,7 @@ mod tests { } #[test] - pub fn test_reqopt_long_multi() { + fn test_reqopt_long_multi() { let args = ~[~"--test=20", ~"--test=30"]; let opts = ~[reqopt(~"test")]; let rs = getopts(args, opts); @@ -724,7 +722,7 @@ mod tests { } #[test] - pub fn test_reqopt_short() { + fn test_reqopt_short() { let args = ~[~"-t", ~"20"]; let opts = ~[reqopt(~"t")]; let rs = getopts(args, opts); @@ -738,7 +736,7 @@ mod tests { } #[test] - pub fn test_reqopt_short_missing() { + fn test_reqopt_short_missing() { let args = ~[~"blah"]; let opts = ~[reqopt(~"t")]; let rs = getopts(args, opts); @@ -749,7 +747,7 @@ mod tests { } #[test] - pub fn test_reqopt_short_no_arg() { + fn test_reqopt_short_no_arg() { let args = ~[~"-t"]; let opts = ~[reqopt(~"t")]; let rs = getopts(args, opts); @@ -760,7 +758,7 @@ mod tests { } #[test] - pub fn test_reqopt_short_multi() { + fn test_reqopt_short_multi() { let args = ~[~"-t", ~"20", ~"-t", ~"30"]; let opts = ~[reqopt(~"t")]; let rs = getopts(args, opts); @@ -773,7 +771,7 @@ mod tests { // Tests for optopt #[test] - pub fn test_optopt_long() { + fn test_optopt_long() { let args = ~[~"--test=20"]; let opts = ~[optopt(~"test")]; let rs = getopts(args, opts); @@ -787,7 +785,7 @@ mod tests { } #[test] - pub fn test_optopt_long_missing() { + fn test_optopt_long_missing() { let args = ~[~"blah"]; let opts = ~[optopt(~"test")]; let rs = getopts(args, opts); @@ -798,7 +796,7 @@ mod tests { } #[test] - pub fn test_optopt_long_no_arg() { + fn test_optopt_long_no_arg() { let args = ~[~"--test"]; let opts = ~[optopt(~"test")]; let rs = getopts(args, opts); @@ -809,7 +807,7 @@ mod tests { } #[test] - pub fn test_optopt_long_multi() { + fn test_optopt_long_multi() { let args = ~[~"--test=20", ~"--test=30"]; let opts = ~[optopt(~"test")]; let rs = getopts(args, opts); @@ -820,7 +818,7 @@ mod tests { } #[test] - pub fn test_optopt_short() { + fn test_optopt_short() { let args = ~[~"-t", ~"20"]; let opts = ~[optopt(~"t")]; let rs = getopts(args, opts); @@ -834,7 +832,7 @@ mod tests { } #[test] - pub fn test_optopt_short_missing() { + fn test_optopt_short_missing() { let args = ~[~"blah"]; let opts = ~[optopt(~"t")]; let rs = getopts(args, opts); @@ -845,7 +843,7 @@ mod tests { } #[test] - pub fn test_optopt_short_no_arg() { + fn test_optopt_short_no_arg() { let args = ~[~"-t"]; let opts = ~[optopt(~"t")]; let rs = getopts(args, opts); @@ -856,7 +854,7 @@ mod tests { } #[test] - pub fn test_optopt_short_multi() { + fn test_optopt_short_multi() { let args = ~[~"-t", ~"20", ~"-t", ~"30"]; let opts = ~[optopt(~"t")]; let rs = getopts(args, opts); @@ -869,7 +867,7 @@ mod tests { // Tests for optflag #[test] - pub fn test_optflag_long() { + fn test_optflag_long() { let args = ~[~"--test"]; let opts = ~[optflag(~"test")]; let rs = getopts(args, opts); @@ -880,7 +878,7 @@ mod tests { } #[test] - pub fn test_optflag_long_missing() { + fn test_optflag_long_missing() { let args = ~[~"blah"]; let opts = ~[optflag(~"test")]; let rs = getopts(args, opts); @@ -891,7 +889,7 @@ mod tests { } #[test] - pub fn test_optflag_long_arg() { + fn test_optflag_long_arg() { let args = ~[~"--test=20"]; let opts = ~[optflag(~"test")]; let rs = getopts(args, opts); @@ -905,7 +903,7 @@ mod tests { } #[test] - pub fn test_optflag_long_multi() { + fn test_optflag_long_multi() { let args = ~[~"--test", ~"--test"]; let opts = ~[optflag(~"test")]; let rs = getopts(args, opts); @@ -916,7 +914,7 @@ mod tests { } #[test] - pub fn test_optflag_short() { + fn test_optflag_short() { let args = ~[~"-t"]; let opts = ~[optflag(~"t")]; let rs = getopts(args, opts); @@ -927,7 +925,7 @@ mod tests { } #[test] - pub fn test_optflag_short_missing() { + fn test_optflag_short_missing() { let args = ~[~"blah"]; let opts = ~[optflag(~"t")]; let rs = getopts(args, opts); @@ -938,7 +936,7 @@ mod tests { } #[test] - pub fn test_optflag_short_arg() { + fn test_optflag_short_arg() { let args = ~[~"-t", ~"20"]; let opts = ~[optflag(~"t")]; let rs = getopts(args, opts); @@ -953,7 +951,7 @@ mod tests { } #[test] - pub fn test_optflag_short_multi() { + fn test_optflag_short_multi() { let args = ~[~"-t", ~"-t"]; let opts = ~[optflag(~"t")]; let rs = getopts(args, opts); @@ -965,7 +963,7 @@ mod tests { // Tests for optflagmulti #[test] - pub fn test_optflagmulti_short1() { + fn test_optflagmulti_short1() { let args = ~[~"-v"]; let opts = ~[optflagmulti(~"v")]; let rs = getopts(args, opts); @@ -978,7 +976,7 @@ mod tests { } #[test] - pub fn test_optflagmulti_short2a() { + fn test_optflagmulti_short2a() { let args = ~[~"-v", ~"-v"]; let opts = ~[optflagmulti(~"v")]; let rs = getopts(args, opts); @@ -991,7 +989,7 @@ mod tests { } #[test] - pub fn test_optflagmulti_short2b() { + fn test_optflagmulti_short2b() { let args = ~[~"-vv"]; let opts = ~[optflagmulti(~"v")]; let rs = getopts(args, opts); @@ -1004,7 +1002,7 @@ mod tests { } #[test] - pub fn test_optflagmulti_long1() { + fn test_optflagmulti_long1() { let args = ~[~"--verbose"]; let opts = ~[optflagmulti(~"verbose")]; let rs = getopts(args, opts); @@ -1017,7 +1015,7 @@ mod tests { } #[test] - pub fn test_optflagmulti_long2() { + fn test_optflagmulti_long2() { let args = ~[~"--verbose", ~"--verbose"]; let opts = ~[optflagmulti(~"verbose")]; let rs = getopts(args, opts); @@ -1031,7 +1029,7 @@ mod tests { // Tests for optmulti #[test] - pub fn test_optmulti_long() { + fn test_optmulti_long() { let args = ~[~"--test=20"]; let opts = ~[optmulti(~"test")]; let rs = getopts(args, opts); @@ -1045,7 +1043,7 @@ mod tests { } #[test] - pub fn test_optmulti_long_missing() { + fn test_optmulti_long_missing() { let args = ~[~"blah"]; let opts = ~[optmulti(~"test")]; let rs = getopts(args, opts); @@ -1056,7 +1054,7 @@ mod tests { } #[test] - pub fn test_optmulti_long_no_arg() { + fn test_optmulti_long_no_arg() { let args = ~[~"--test"]; let opts = ~[optmulti(~"test")]; let rs = getopts(args, opts); @@ -1067,7 +1065,7 @@ mod tests { } #[test] - pub fn test_optmulti_long_multi() { + fn test_optmulti_long_multi() { let args = ~[~"--test=20", ~"--test=30"]; let opts = ~[optmulti(~"test")]; let rs = getopts(args, opts); @@ -1084,7 +1082,7 @@ mod tests { } #[test] - pub fn test_optmulti_short() { + fn test_optmulti_short() { let args = ~[~"-t", ~"20"]; let opts = ~[optmulti(~"t")]; let rs = getopts(args, opts); @@ -1098,7 +1096,7 @@ mod tests { } #[test] - pub fn test_optmulti_short_missing() { + fn test_optmulti_short_missing() { let args = ~[~"blah"]; let opts = ~[optmulti(~"t")]; let rs = getopts(args, opts); @@ -1109,7 +1107,7 @@ mod tests { } #[test] - pub fn test_optmulti_short_no_arg() { + fn test_optmulti_short_no_arg() { let args = ~[~"-t"]; let opts = ~[optmulti(~"t")]; let rs = getopts(args, opts); @@ -1120,7 +1118,7 @@ mod tests { } #[test] - pub fn test_optmulti_short_multi() { + fn test_optmulti_short_multi() { let args = ~[~"-t", ~"20", ~"-t", ~"30"]; let opts = ~[optmulti(~"t")]; let rs = getopts(args, opts); @@ -1137,7 +1135,7 @@ mod tests { } #[test] - pub fn test_unrecognized_option_long() { + fn test_unrecognized_option_long() { let args = ~[~"--untest"]; let opts = ~[optmulti(~"t")]; let rs = getopts(args, opts); @@ -1148,7 +1146,7 @@ mod tests { } #[test] - pub fn test_unrecognized_option_short() { + fn test_unrecognized_option_short() { let args = ~[~"-t"]; let opts = ~[optmulti(~"test")]; let rs = getopts(args, opts); @@ -1159,7 +1157,7 @@ mod tests { } #[test] - pub fn test_combined() { + fn test_combined() { let args = ~[~"prog", ~"free1", ~"-s", ~"20", ~"free2", ~"--flag", ~"--long=30", ~"-f", ~"-m", ~"40", @@ -1191,7 +1189,7 @@ mod tests { } #[test] - pub fn test_multi() { + fn test_multi() { let args = ~[~"-e", ~"foo", ~"--encrypt", ~"foo"]; let opts = ~[optopt(~"e"), optopt(~"encrypt"), optopt(~"f")]; let matches = &match getopts(args, opts) { @@ -1213,7 +1211,7 @@ mod tests { } #[test] - pub fn test_nospace() { + fn test_nospace() { let args = ~[~"-Lfoo", ~"-M."]; let opts = ~[optmulti(~"L"), optmulti(~"M")]; let matches = &match getopts(args, opts) { @@ -1228,7 +1226,7 @@ mod tests { } #[test] - pub fn test_groups_reqopt() { + fn test_groups_reqopt() { let opt = groups::reqopt(~"b", ~"banana", ~"some bananas", ~"VAL"); assert!(opt == OptGroup { short_name: ~"b", long_name: ~"banana", @@ -1239,7 +1237,7 @@ mod tests { } #[test] - pub fn test_groups_optopt() { + fn test_groups_optopt() { let opt = groups::optopt(~"a", ~"apple", ~"some apples", ~"VAL"); assert!(opt == OptGroup { short_name: ~"a", long_name: ~"apple", @@ -1250,7 +1248,7 @@ mod tests { } #[test] - pub fn test_groups_optflag() { + fn test_groups_optflag() { let opt = groups::optflag(~"k", ~"kiwi", ~"some kiwis"); assert!(opt == OptGroup { short_name: ~"k", long_name: ~"kiwi", @@ -1261,7 +1259,7 @@ mod tests { } #[test] - pub fn test_groups_optflagopt() { + fn test_groups_optflagopt() { let opt = groups::optflagopt(~"p", ~"pineapple", ~"some pineapples", ~"VAL"); assert!(opt == OptGroup { short_name: ~"p", @@ -1273,7 +1271,7 @@ mod tests { } #[test] - pub fn test_groups_optmulti() { + fn test_groups_optmulti() { let opt = groups::optmulti(~"l", ~"lime", ~"some limes", ~"VAL"); assert!(opt == OptGroup { short_name: ~"l", @@ -1285,7 +1283,7 @@ mod tests { } #[test] - pub fn test_groups_long_to_short() { + fn test_groups_long_to_short() { let short = ~[reqopt(~"b"), reqopt(~"banana")]; let verbose = groups::reqopt(~"b", ~"banana", ~"some bananas", ~"VAL"); @@ -1294,7 +1292,7 @@ mod tests { } #[test] - pub fn test_groups_getopts() { + fn test_groups_getopts() { let short = ~[ reqopt(~"b"), reqopt(~"banana"), optopt(~"a"), optopt(~"apple"), @@ -1320,7 +1318,7 @@ mod tests { } #[test] - pub fn test_groups_usage() { + fn test_groups_usage() { let optgroups = ~[ groups::reqopt(~"b", ~"banana", ~"Desc", ~"VAL"), groups::optopt(~"a", ~"012345678901234567890123456789", @@ -1351,7 +1349,7 @@ Options: } #[test] - pub fn test_groups_usage_description_wrapping() { + fn test_groups_usage_description_wrapping() { // indentation should be 24 spaces // lines wrap after 78: or rather descriptions wrap after 54 diff --git a/src/libstd/json.rs b/src/libstd/json.rs index e090d6bc036d8..f5cd8b4bd6830 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -16,7 +16,7 @@ use core::prelude::*; use core::io::{WriterUtil, ReaderUtil}; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use serialize::Encodable; use serialize; @@ -33,7 +33,7 @@ pub enum Json { } pub type List = ~[Json]; -pub type Object = LinearMap<~str, Json>; +pub type Object = HashMap<~str, Json>; #[deriving(Eq)] pub struct Error { @@ -109,6 +109,7 @@ impl serialize::Encoder for Encoder { fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)) } fn emit_enum(&self, _name: &str, f: &fn()) { f() } + fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { // enums are encoded as strings or vectors: // Bunny => "Bunny" @@ -126,19 +127,16 @@ impl serialize::Encoder for Encoder { } fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { - if (idx != 0) {self.wr.write_char(',');} + if idx != 0 {self.wr.write_char(',');} f(); } - fn emit_seq(&self, _len: uint, f: &fn()) { - self.wr.write_char('['); - f(); - self.wr.write_char(']'); + fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(name, id, cnt, f) } - fn emit_seq_elt(&self, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - f() + fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) } fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { @@ -146,17 +144,44 @@ impl serialize::Encoder for Encoder { f(); self.wr.write_char('}'); } + #[cfg(stage0)] fn emit_field(&self, name: &str, idx: uint, f: &fn()) { if idx != 0 { self.wr.write_char(','); } self.wr.write_str(escape_str(name)); self.wr.write_char(':'); f(); } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { + if idx != 0 { self.wr.write_char(','); } + self.wr.write_str(escape_str(name)); + self.wr.write_char(':'); + f(); + } + + fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } fn emit_option(&self, f: &fn()) { f(); } fn emit_option_none(&self) { self.emit_nil(); } fn emit_option_some(&self, f: &fn()) { f(); } + fn emit_seq(&self, _len: uint, f: &fn()) { + self.wr.write_char('['); + f(); + self.wr.write_char(']'); + } + + fn emit_seq_elt(&self, idx: uint, f: &fn()) { + if idx != 0 { self.wr.write_char(','); } + f() + } + fn emit_map(&self, _len: uint, f: &fn()) { self.wr.write_char('{'); f(); @@ -216,6 +241,7 @@ impl serialize::Encoder for PrettyEncoder { fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)); } fn emit_enum(&self, _name: &str, f: &fn()) { f() } + fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { if cnt == 0 { self.wr.write_str(escape_str(name)); @@ -233,6 +259,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_char(']'); } } + fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { if idx != 0 { self.wr.write_str(",\n"); @@ -241,58 +268,88 @@ impl serialize::Encoder for PrettyEncoder { f() } - fn emit_seq(&self, len: uint, f: &fn()) { + fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) + } + + + fn emit_struct(&self, _name: &str, len: uint, f: &fn()) { if len == 0 { - self.wr.write_str("[]"); + self.wr.write_str("{}"); } else { - self.wr.write_char('['); + self.wr.write_char('{'); self.indent += 2; f(); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); + self.wr.write_char('}'); } } - fn emit_seq_elt(&self, idx: uint, f: &fn()) { + #[cfg(stage0)] + fn emit_field(&self, name: &str, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); } else { self.wr.write_str(",\n"); } self.wr.write_str(spaces(self.indent)); - f() + self.wr.write_str(escape_str(name)); + self.wr.write_str(": "); + f(); + } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { + if idx == 0 { + self.wr.write_char('\n'); + } else { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + self.wr.write_str(escape_str(name)); + self.wr.write_str(": "); + f(); } - fn emit_struct(&self, _name: &str, len: uint, f: &fn()) { + fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + + fn emit_option(&self, f: &fn()) { f(); } + fn emit_option_none(&self) { self.emit_nil(); } + fn emit_option_some(&self, f: &fn()) { f(); } + + fn emit_seq(&self, len: uint, f: &fn()) { if len == 0 { - self.wr.write_str("{}"); + self.wr.write_str("[]"); } else { - self.wr.write_char('{'); + self.wr.write_char('['); self.indent += 2; f(); self.wr.write_char('\n'); self.indent -= 2; self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); + self.wr.write_char(']'); } } - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { + fn emit_seq_elt(&self, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); } else { self.wr.write_str(",\n"); } self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); - f(); + f() } - fn emit_option(&self, f: &fn()) { f(); } - fn emit_option_none(&self) { self.emit_nil(); } - fn emit_option_some(&self, f: &fn()) { f(); } - fn emit_map(&self, len: uint, f: &fn()) { if len == 0 { self.wr.write_str("{}"); @@ -342,10 +399,7 @@ pub fn to_writer(wr: @io::Writer, json: &Json) { /// Encodes a json value into a string pub fn to_str(json: &Json) -> ~str { - unsafe { - // ugh, should be safe - io::with_str_writer(|wr| to_writer(wr, json)) - } + io::with_str_writer(|wr| to_writer(wr, json)) } /// Encodes a json value into a io::writer @@ -360,9 +414,9 @@ pub fn to_pretty_str(json: &Json) -> ~str { pub struct Parser { priv rdr: @io::Reader, - priv mut ch: char, - priv mut line: uint, - priv mut col: uint, + priv ch: char, + priv line: uint, + priv col: uint, } /// Decode a json value from an io::reader @@ -376,7 +430,7 @@ pub fn Parser(rdr: @io::Reader) -> Parser { } pub impl Parser { - fn parse(&self) -> Result { + fn parse(&mut self) -> Result { match self.parse_value() { Ok(value) => { // Skip trailing whitespaces. @@ -396,7 +450,7 @@ pub impl Parser { priv impl Parser { fn eof(&self) -> bool { self.ch == -1 as char } - fn bump(&self) { + fn bump(&mut self) { self.ch = self.rdr.read_char(); if self.ch == '\n' { @@ -407,7 +461,7 @@ priv impl Parser { } } - fn next_char(&self) -> char { + fn next_char(&mut self) -> char { self.bump(); self.ch } @@ -416,7 +470,7 @@ priv impl Parser { Err(Error { line: self.line, col: self.col, msg: @msg }) } - fn parse_value(&self) -> Result { + fn parse_value(&mut self) -> Result { self.parse_whitespace(); if self.eof() { return self.error(~"EOF while parsing value"); } @@ -437,11 +491,11 @@ priv impl Parser { } } - fn parse_whitespace(&self) { + fn parse_whitespace(&mut self) { while char::is_whitespace(self.ch) { self.bump(); } } - fn parse_ident(&self, ident: &str, value: Json) -> Result { + fn parse_ident(&mut self, ident: &str, value: Json) -> Result { if str::all(ident, |c| c == self.next_char()) { self.bump(); Ok(value) @@ -450,7 +504,7 @@ priv impl Parser { } } - fn parse_number(&self) -> Result { + fn parse_number(&mut self) -> Result { let mut neg = 1f; if self.ch == '-' { @@ -480,7 +534,7 @@ priv impl Parser { Ok(Number(neg * res)) } - fn parse_integer(&self) -> Result { + fn parse_integer(&mut self) -> Result { let mut res = 0f; match self.ch { @@ -512,7 +566,7 @@ priv impl Parser { Ok(res) } - fn parse_decimal(&self, res: float) -> Result { + fn parse_decimal(&mut self, res: float) -> Result { self.bump(); // Make sure a digit follows the decimal place. @@ -538,10 +592,9 @@ priv impl Parser { Ok(res) } - fn parse_exponent(&self, res: float) -> Result { + fn parse_exponent(&mut self, mut res: float) -> Result { self.bump(); - let mut res = res; let mut exp = 0u; let mut neg_exp = false; @@ -579,7 +632,7 @@ priv impl Parser { Ok(res) } - fn parse_str(&self) -> Result<~str, Error> { + fn parse_str(&mut self) -> Result<~str, Error> { let mut escape = false; let mut res = ~""; @@ -643,7 +696,7 @@ priv impl Parser { self.error(~"EOF while parsing string") } - fn parse_list(&self) -> Result { + fn parse_list(&mut self) -> Result { self.bump(); self.parse_whitespace(); @@ -673,11 +726,11 @@ priv impl Parser { }; } - fn parse_object(&self) -> Result { + fn parse_object(&mut self) -> Result { self.bump(); self.parse_whitespace(); - let mut values = ~LinearMap::new(); + let mut values = ~HashMap::new(); if self.ch == '}' { self.bump(); @@ -726,7 +779,8 @@ priv impl Parser { /// Decodes a json value from an @io::Reader pub fn from_reader(rdr: @io::Reader) -> Result { - Parser(rdr).parse() + let mut parser = Parser(rdr); + parser.parse() } /// Decodes a json value from a string @@ -830,24 +884,15 @@ impl serialize::Decoder for Decoder { f() } - fn read_seq(&self, f: &fn(uint) -> T) -> T { - debug!("read_seq()"); - let len = match self.stack.pop() { - List(list) => { - let len = list.len(); - do vec::consume_reverse(list) |_i, v| { - self.stack.push(v); - } - len - } - _ => fail!(~"not a list"), - }; - f(len) + fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T { + debug!("read_enum_struct_variant(names=%?)", names); + self.read_enum_variant(names, f) } - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_seq_elt(idx=%u)", idx); - f() + + fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_enum_struct_variant_field(name=%?, idx=%u)", name, idx); + self.read_enum_variant_arg(idx, f) } fn read_struct(&self, name: &str, len: uint, f: &fn() -> T) -> T { @@ -857,8 +902,31 @@ impl serialize::Decoder for Decoder { value } + #[cfg(stage0)] fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(%s, idx=%u)", name, idx); + debug!("read_field(name=%?, idx=%u)", name, idx); + match self.stack.pop() { + Object(obj) => { + let mut obj = obj; + let value = match obj.pop(&name.to_owned()) { + None => fail!(fmt!("no such field: %s", name)), + Some(json) => { + self.stack.push(json); + f() + } + }; + self.stack.push(Object(obj)); + value + } + value => fail!(fmt!("not an object: %?", value)) + } + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_struct_field(name=%?, idx=%u)", name, idx); match self.stack.pop() { Object(obj) => { let mut obj = obj; @@ -876,6 +944,26 @@ impl serialize::Decoder for Decoder { } } + fn read_tuple(&self, f: &fn(uint) -> T) -> T { + debug!("read_tuple()"); + self.read_seq(f) + } + + fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_arg(idx=%u)", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { + debug!("read_tuple_struct(name=%?)", name); + self.read_tuple(f) + } + + fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_tuple_struct_arg(idx=%u)", idx); + self.read_tuple_arg(idx, f) + } + fn read_option(&self, f: &fn(bool) -> T) -> T { match self.stack.pop() { Null => f(false), @@ -883,6 +971,26 @@ impl serialize::Decoder for Decoder { } } + fn read_seq(&self, f: &fn(uint) -> T) -> T { + debug!("read_seq()"); + let len = match self.stack.pop() { + List(list) => { + let len = list.len(); + do vec::consume_reverse(list) |_i, v| { + self.stack.push(v); + } + len + } + _ => fail!(~"not a list"), + }; + f(len) + } + + fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { + debug!("read_seq_elt(idx=%u)", idx); + f() + } + fn read_map(&self, f: &fn(uint) -> T) -> T { debug!("read_map()"); let len = match self.stack.pop() { @@ -929,7 +1037,7 @@ impl Eq for Json { &Object(ref d1) => { if d0.len() == d1.len() { let mut equal = true; - for d0.each |&(k, v0)| { + for d0.each |k, v0| { match d1.find(k) { Some(v1) if v0 == v1 => { }, _ => { equal = false; break } @@ -988,23 +1096,21 @@ impl Ord for Json { match *other { Number(_) | String(_) | Boolean(_) | List(_) => false, Object(ref d1) => { - unsafe { - let mut d0_flat = ~[]; - let mut d1_flat = ~[]; - - // FIXME #4430: this is horribly inefficient... - for d0.each |&(k, v)| { - d0_flat.push((@copy *k, @copy *v)); - } - d0_flat.qsort(); - - for d1.each |&(k, v)| { - d1_flat.push((@copy *k, @copy *v)); - } - d1_flat.qsort(); - - d0_flat < d1_flat + let mut d0_flat = ~[]; + let mut d1_flat = ~[]; + + // FIXME #4430: this is horribly inefficient... + for d0.each |k, v| { + d0_flat.push((@copy *k, @copy *v)); + } + d0_flat.qsort(); + + for d1.each |k, v| { + d1_flat.push((@copy *k, @copy *v)); } + d1_flat.qsort(); + + d0_flat < d1_flat } Null => true } @@ -1127,10 +1233,10 @@ impl ToJson for ~[A] { fn to_json(&self) -> Json { List(self.map(|elt| elt.to_json())) } } -impl ToJson for LinearMap<~str, A> { +impl ToJson for HashMap<~str, A> { fn to_json(&self) -> Json { - let mut d = LinearMap::new(); - for self.each |&(key, value)| { + let mut d = HashMap::new(); + for self.each |key, value| { d.insert(copy *key, value.to_json()); } Object(~d) @@ -1161,7 +1267,7 @@ mod tests { use super::*; use core::prelude::*; - use core::hashmap::linear::LinearMap; + use core::hashmap::HashMap; use std::serialize::Decodable; @@ -1190,7 +1296,7 @@ mod tests { } fn mk_object(items: &[(~str, Json)]) -> Json { - let mut d = ~LinearMap::new(); + let mut d = ~HashMap::new(); for items.each |item| { match *item { @@ -1755,7 +1861,7 @@ mod tests { fn test_decode_map() { let s = ~"{\"a\": \"Dog\", \"b\": [\"Frog\", \"Henry\", 349]}"; let decoder = Decoder(from_str(s).unwrap()); - let mut map: LinearMap<~str, Animal> = Decodable::decode(&decoder); + let mut map: HashMap<~str, Animal> = Decodable::decode(&decoder); assert_eq!(map.pop(&~"a"), Some(Dog)); assert_eq!(map.pop(&~"b"), Some(Frog(~"Henry", 349))); diff --git a/src/libstd/list.rs b/src/libstd/list.rs index 63d461ed4d3bf..8e173ff8a9c6a 100644 --- a/src/libstd/list.rs +++ b/src/libstd/list.rs @@ -160,7 +160,7 @@ mod tests { use core::option; #[test] - pub fn test_is_empty() { + fn test_is_empty() { let empty : @list::List = from_vec(~[]); let full1 = from_vec(~[1]); let full2 = from_vec(~['r', 'u']); @@ -171,7 +171,7 @@ mod tests { } #[test] - pub fn test_from_vec() { + fn test_from_vec() { let l = from_vec(~[0, 1, 2]); assert!((head(l) == 0)); @@ -184,13 +184,13 @@ mod tests { } #[test] - pub fn test_from_vec_empty() { + fn test_from_vec_empty() { let empty : @list::List = from_vec(~[]); assert!((empty == @list::Nil::)); } #[test] - pub fn test_foldl() { + fn test_foldl() { fn add(a: &uint, b: &int) -> uint { return *a + (*b as uint); } let l = from_vec(~[0, 1, 2, 3, 4]); let empty = @list::Nil::; @@ -199,7 +199,7 @@ mod tests { } #[test] - pub fn test_foldl2() { + fn test_foldl2() { fn sub(a: &int, b: &int) -> int { *a - *b } @@ -208,14 +208,14 @@ mod tests { } #[test] - pub fn test_find_success() { + fn test_find_success() { fn match_(i: &int) -> bool { return *i == 2; } let l = from_vec(~[0, 1, 2]); assert!((list::find(l, match_) == option::Some(2))); } #[test] - pub fn test_find_fail() { + fn test_find_fail() { fn match_(_i: &int) -> bool { return false; } let l = from_vec(~[0, 1, 2]); let empty = @list::Nil::; @@ -224,7 +224,7 @@ mod tests { } #[test] - pub fn test_has() { + fn test_has() { let l = from_vec(~[5, 8, 6]); let empty = @list::Nil::; assert!((list::has(l, 5))); @@ -234,7 +234,7 @@ mod tests { } #[test] - pub fn test_len() { + fn test_len() { let l = from_vec(~[0, 1, 2]); let empty = @list::Nil::; assert!((list::len(l) == 3u)); @@ -242,7 +242,7 @@ mod tests { } #[test] - pub fn test_append() { + fn test_append() { assert!(from_vec(~[1,2,3,4]) == list::append(list::from_vec(~[1,2]), list::from_vec(~[3,4]))); } diff --git a/src/libstd/md4.rs b/src/libstd/md4.rs index 8f35376a6f1f1..24dd08c362e99 100644 --- a/src/libstd/md4.rs +++ b/src/libstd/md4.rs @@ -29,14 +29,14 @@ pub fn md4(msg: &[u8]) -> Quad { let mut msg = vec::append(vec::from_slice(msg), ~[0x80u8]); let mut bitlen = orig_len + 8u64; while (bitlen + 64u64) % 512u64 > 0u64 { - unsafe {msg.push(0u8);} + msg.push(0u8); bitlen += 8u64; } // append length let mut i = 0u64; while i < 8u64 { - unsafe {msg.push((orig_len >> (i * 8u64)) as u8);} + msg.push((orig_len >> (i * 8u64)) as u8); i += 1u64; } diff --git a/src/libstd/net_ip.rs b/src/libstd/net_ip.rs index 6403e0eb5c47a..e920ff20ac5dc 100644 --- a/src/libstd/net_ip.rs +++ b/src/libstd/net_ip.rs @@ -116,35 +116,33 @@ pub fn get_addr(node: &str, iotask: &iotask) let mut output_ch = Some(SharedChan(output_ch)); do str::as_buf(node) |node_ptr, len| { let output_ch = output_ch.swap_unwrap(); - unsafe { - debug!("slice len %?", len); - let handle = create_uv_getaddrinfo_t(); - let handle_ptr = ptr::addr_of(&handle); - let handle_data = GetAddrData { - output_ch: output_ch.clone() - }; - let handle_data_ptr = ptr::addr_of(&handle_data); - do interact(iotask) |loop_ptr| { - unsafe { - let result = uv_getaddrinfo( - loop_ptr, - handle_ptr, - get_addr_cb, - node_ptr, - ptr::null(), - ptr::null()); - match result { - 0i32 => { - set_data_for_req(handle_ptr, handle_data_ptr); - } - _ => { - output_ch.send(result::Err(GetAddrUnknownError)); - } + debug!("slice len %?", len); + let handle = create_uv_getaddrinfo_t(); + let handle_ptr = ptr::addr_of(&handle); + let handle_data = GetAddrData { + output_ch: output_ch.clone() + }; + let handle_data_ptr = ptr::addr_of(&handle_data); + do interact(iotask) |loop_ptr| { + unsafe { + let result = uv_getaddrinfo( + loop_ptr, + handle_ptr, + get_addr_cb, + node_ptr, + ptr::null(), + ptr::null()); + match result { + 0i32 => { + set_data_for_req(handle_ptr, handle_data_ptr); + } + _ => { + output_ch.send(result::Err(GetAddrUnknownError)); } } - }; - output_po.recv() - } + } + }; + output_po.recv() } } diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 9630351b5c9be..b32df75063d97 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -57,9 +57,7 @@ pub struct TcpSocket { #[unsafe_destructor] impl Drop for TcpSocket { fn finalize(&self) { - unsafe { - tear_down_socket_data(self.socket_data) - } + tear_down_socket_data(self.socket_data) } } @@ -302,11 +300,10 @@ pub fn connect(input_ip: ip::IpAddr, port: uint, * `TcpErrData` value as the `Err` variant */ pub fn write(sock: &TcpSocket, raw_write_data: ~[u8]) - -> result::Result<(), TcpErrData> { - unsafe { - let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data))); - write_common_impl(socket_data_ptr, raw_write_data) - } + -> result::Result<(), TcpErrData> +{ + let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data))); + write_common_impl(socket_data_ptr, raw_write_data) } /** @@ -341,13 +338,12 @@ pub fn write(sock: &TcpSocket, raw_write_data: ~[u8]) * value as the `Err` variant */ pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8]) - -> future::Future> { - unsafe { - let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data))); - do future_spawn { - let data_copy = copy(raw_write_data); - write_common_impl(socket_data_ptr, data_copy) - } + -> future::Future> +{ + let socket_data_ptr = ptr::addr_of(&(*(sock.socket_data))); + do future_spawn { + let data_copy = copy(raw_write_data); + write_common_impl(socket_data_ptr, data_copy) } } @@ -369,10 +365,8 @@ pub fn write_future(sock: &TcpSocket, raw_write_data: ~[u8]) pub fn read_start(sock: &TcpSocket) -> result::Result<@Port< result::Result<~[u8], TcpErrData>>, TcpErrData> { - unsafe { - let socket_data = ptr::addr_of(&(*(sock.socket_data))); - read_start_common_impl(socket_data) - } + let socket_data = ptr::addr_of(&(*(sock.socket_data))); + read_start_common_impl(socket_data) } /** @@ -382,12 +376,9 @@ pub fn read_start(sock: &TcpSocket) * * * `sock` - a `net::tcp::TcpSocket` that you wish to stop reading on */ -pub fn read_stop(sock: &TcpSocket) -> - result::Result<(), TcpErrData> { - unsafe { - let socket_data = ptr::addr_of(&(*sock.socket_data)); - read_stop_common_impl(socket_data) - } +pub fn read_stop(sock: &TcpSocket) -> result::Result<(), TcpErrData> { + let socket_data = ptr::addr_of(&(*sock.socket_data)); + read_stop_common_impl(socket_data) } /** @@ -654,150 +645,148 @@ fn listen_common(host_ip: ip::IpAddr, on_establish_cb: ~fn(SharedChan>), on_connect_cb: ~fn(*uv::ll::uv_tcp_t)) -> result::Result<(), TcpListenErrData> { - unsafe { - let (stream_closed_po, stream_closed_ch) = stream::<()>(); - let stream_closed_ch = SharedChan(stream_closed_ch); - let (kill_po, kill_ch) = stream::>(); - let kill_ch = SharedChan(kill_ch); - let server_stream = uv::ll::tcp_t(); - let server_stream_ptr = ptr::addr_of(&server_stream); - let server_data: TcpListenFcData = TcpListenFcData { - server_stream_ptr: server_stream_ptr, - stream_closed_ch: stream_closed_ch, - kill_ch: kill_ch.clone(), - on_connect_cb: on_connect_cb, - iotask: iotask.clone(), - ipv6: match &host_ip { - &ip::Ipv4(_) => { false } - &ip::Ipv6(_) => { true } - }, - mut active: true - }; - let server_data_ptr = ptr::addr_of(&server_data); - - let (setup_po, setup_ch) = stream(); - - // this is to address a compiler warning about - // an implicit copy.. it seems that double nested - // will defeat a move sigil, as is done to the host_ip - // arg above.. this same pattern works w/o complaint in - // tcp::connect (because the iotask::interact cb isn't - // nested within a core::comm::listen block) - let loc_ip = copy(host_ip); - do iotask::interact(iotask) |loop_ptr| { - unsafe { - match uv::ll::tcp_init(loop_ptr, server_stream_ptr) { - 0i32 => { - uv::ll::set_data_for_uv_handle( - server_stream_ptr, - server_data_ptr); - let addr_str = ip::format_addr(&loc_ip); - let bind_result = match loc_ip { - ip::Ipv4(ref addr) => { - debug!("addr: %?", addr); - let in_addr = uv::ll::ip4_addr( - addr_str, - port as int); - uv::ll::tcp_bind(server_stream_ptr, - ptr::addr_of(&in_addr)) - } - ip::Ipv6(ref addr) => { - debug!("addr: %?", addr); - let in_addr = uv::ll::ip6_addr( - addr_str, - port as int); - uv::ll::tcp_bind6(server_stream_ptr, - ptr::addr_of(&in_addr)) - } - }; - match bind_result { - 0i32 => { - match uv::ll::listen( - server_stream_ptr, - backlog as libc::c_int, - tcp_lfc_on_connection_cb) { - 0i32 => setup_ch.send(None), - _ => { - debug!( - "failure to uv_tcp_init"); - let err_data = - uv::ll::get_last_err_data( - loop_ptr); - setup_ch.send(Some(err_data)); - } + let (stream_closed_po, stream_closed_ch) = stream::<()>(); + let stream_closed_ch = SharedChan(stream_closed_ch); + let (kill_po, kill_ch) = stream::>(); + let kill_ch = SharedChan(kill_ch); + let server_stream = uv::ll::tcp_t(); + let server_stream_ptr = ptr::addr_of(&server_stream); + let server_data: TcpListenFcData = TcpListenFcData { + server_stream_ptr: server_stream_ptr, + stream_closed_ch: stream_closed_ch, + kill_ch: kill_ch.clone(), + on_connect_cb: on_connect_cb, + iotask: iotask.clone(), + ipv6: match &host_ip { + &ip::Ipv4(_) => { false } + &ip::Ipv6(_) => { true } + }, + mut active: true + }; + let server_data_ptr = ptr::addr_of(&server_data); + + let (setup_po, setup_ch) = stream(); + + // this is to address a compiler warning about + // an implicit copy.. it seems that double nested + // will defeat a move sigil, as is done to the host_ip + // arg above.. this same pattern works w/o complaint in + // tcp::connect (because the iotask::interact cb isn't + // nested within a core::comm::listen block) + let loc_ip = copy(host_ip); + do iotask::interact(iotask) |loop_ptr| { + unsafe { + match uv::ll::tcp_init(loop_ptr, server_stream_ptr) { + 0i32 => { + uv::ll::set_data_for_uv_handle( + server_stream_ptr, + server_data_ptr); + let addr_str = ip::format_addr(&loc_ip); + let bind_result = match loc_ip { + ip::Ipv4(ref addr) => { + debug!("addr: %?", addr); + let in_addr = uv::ll::ip4_addr( + addr_str, + port as int); + uv::ll::tcp_bind(server_stream_ptr, + ptr::addr_of(&in_addr)) + } + ip::Ipv6(ref addr) => { + debug!("addr: %?", addr); + let in_addr = uv::ll::ip6_addr( + addr_str, + port as int); + uv::ll::tcp_bind6(server_stream_ptr, + ptr::addr_of(&in_addr)) + } + }; + match bind_result { + 0i32 => { + match uv::ll::listen( + server_stream_ptr, + backlog as libc::c_int, + tcp_lfc_on_connection_cb) { + 0i32 => setup_ch.send(None), + _ => { + debug!( + "failure to uv_tcp_init"); + let err_data = + uv::ll::get_last_err_data( + loop_ptr); + setup_ch.send(Some(err_data)); } } - _ => { - debug!("failure to uv_tcp_bind"); - let err_data = uv::ll::get_last_err_data( - loop_ptr); - setup_ch.send(Some(err_data)); - } } - } - _ => { - debug!("failure to uv_tcp_bind"); - let err_data = uv::ll::get_last_err_data( - loop_ptr); - setup_ch.send(Some(err_data)); + _ => { + debug!("failure to uv_tcp_bind"); + let err_data = uv::ll::get_last_err_data( + loop_ptr); + setup_ch.send(Some(err_data)); + } } } + _ => { + debug!("failure to uv_tcp_bind"); + let err_data = uv::ll::get_last_err_data( + loop_ptr); + setup_ch.send(Some(err_data)); + } } } + } - let setup_result = setup_po.recv(); + let setup_result = setup_po.recv(); - match setup_result { - Some(ref err_data) => { - do iotask::interact(iotask) |loop_ptr| { - unsafe { - debug!( - "tcp::listen post-kill recv hl interact %?", - loop_ptr); - (*server_data_ptr).active = false; - uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); - } - }; - stream_closed_po.recv(); - match err_data.err_name { - ~"EACCES" => { - debug!("Got EACCES error"); - result::Err(AccessDenied) - } - ~"EADDRINUSE" => { - debug!("Got EADDRINUSE error"); - result::Err(AddressInUse) - } - _ => { - debug!("Got '%s' '%s' libuv error", - err_data.err_name, err_data.err_msg); - result::Err( - GenericListenErr(err_data.err_name, - err_data.err_msg)) - } + match setup_result { + Some(ref err_data) => { + do iotask::interact(iotask) |loop_ptr| { + unsafe { + debug!( + "tcp::listen post-kill recv hl interact %?", + loop_ptr); + (*server_data_ptr).active = false; + uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); + } + }; + stream_closed_po.recv(); + match err_data.err_name { + ~"EACCES" => { + debug!("Got EACCES error"); + result::Err(AccessDenied) + } + ~"EADDRINUSE" => { + debug!("Got EADDRINUSE error"); + result::Err(AddressInUse) + } + _ => { + debug!("Got '%s' '%s' libuv error", + err_data.err_name, err_data.err_msg); + result::Err( + GenericListenErr(err_data.err_name, + err_data.err_msg)) } } - None => { - on_establish_cb(kill_ch.clone()); - let kill_result = kill_po.recv(); - do iotask::interact(iotask) |loop_ptr| { - unsafe { - debug!( - "tcp::listen post-kill recv hl interact %?", - loop_ptr); - (*server_data_ptr).active = false; - uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); - } - }; - stream_closed_po.recv(); - match kill_result { - // some failure post bind/listen - Some(ref err_data) => result::Err(GenericListenErr( - err_data.err_name, - err_data.err_msg)), - // clean exit - None => result::Ok(()) + } + None => { + on_establish_cb(kill_ch.clone()); + let kill_result = kill_po.recv(); + do iotask::interact(iotask) |loop_ptr| { + unsafe { + debug!( + "tcp::listen post-kill recv hl interact %?", + loop_ptr); + (*server_data_ptr).active = false; + uv::ll::close(server_stream_ptr, tcp_lfc_close_cb); } + }; + stream_closed_po.recv(); + match kill_result { + // some failure post bind/listen + Some(ref err_data) => result::Err(GenericListenErr( + err_data.err_name, + err_data.err_msg)), + // clean exit + None => result::Ok(()) } } } @@ -1382,9 +1371,7 @@ extern fn stream_error_close_cb(handle: *uv::ll::uv_tcp_t) { } extern fn tcp_connect_close_cb(handle: *uv::ll::uv_tcp_t) { - unsafe { - debug!("closed client tcp handle %?", handle); - } + debug!("closed client tcp handle %?", handle); } extern fn tcp_connect_on_connect_cb(connect_req_ptr: *uv::ll::uv_connect_t, @@ -1439,7 +1426,7 @@ struct TcpBufferedSocketData { } #[cfg(test)] -pub mod test { +mod test { use net::ip; use net::tcp::{GenericListenErr, TcpConnectErrData, TcpListenErrData}; use net::tcp::{connect, accept, read, listen, TcpSocket, socket_buf}; @@ -1460,9 +1447,9 @@ pub mod test { #[cfg(target_os="darwin")] #[cfg(target_os="linux")] #[cfg(target_os="android")] - pub mod tcp_ipv4_server_and_client_test { + mod tcp_ipv4_server_and_client_test { #[cfg(target_arch="x86_64")] - pub mod impl64 { + mod impl64 { use net::tcp::test::*; #[test] @@ -1510,7 +1497,7 @@ pub mod test { #[cfg(target_arch="x86")] #[cfg(target_arch="arm")] #[cfg(target_arch="mips")] - pub mod impl32 { + mod impl32 { use net::tcp::test::*; #[test] diff --git a/src/libstd/net_url.rs b/src/libstd/net_url.rs index d23784953ef99..4cb9a98036b19 100644 --- a/src/libstd/net_url.rs +++ b/src/libstd/net_url.rs @@ -17,7 +17,7 @@ use core::from_str::FromStr; use core::io::{Reader, ReaderUtil}; use core::io; use core::prelude::*; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::str; use core::to_bytes::IterBytes; use core::to_bytes; @@ -25,7 +25,7 @@ use core::to_str::ToStr; use core::to_str; use core::uint; -#[deriving(Eq)] +#[deriving(Clone, Eq)] struct Url { scheme: ~str, user: Option, @@ -36,7 +36,7 @@ struct Url { fragment: Option<~str> } -#[deriving(Eq)] +#[deriving(Clone, Eq)] struct UserInfo { user: ~str, pass: Option<~str> @@ -118,8 +118,7 @@ fn encode_inner(s: &str, full_url: bool) -> ~str { * This function is compliant with RFC 3986. */ pub fn encode(s: &str) -> ~str { - // FIXME(#3722): unsafe only because encode_inner does (string) IO - unsafe {encode_inner(s, true)} + encode_inner(s, true) } /** @@ -130,8 +129,7 @@ pub fn encode(s: &str) -> ~str { */ pub fn encode_component(s: &str) -> ~str { - // FIXME(#3722): unsafe only because encode_inner does (string) IO - unsafe {encode_inner(s, false)} + encode_inner(s, false) } fn decode_inner(s: &str, full_url: bool) -> ~str { @@ -178,16 +176,14 @@ fn decode_inner(s: &str, full_url: bool) -> ~str { * This will only decode escape sequences generated by encode. */ pub fn decode(s: &str) -> ~str { - // FIXME(#3722): unsafe only because decode_inner does (string) IO - unsafe {decode_inner(s, true)} + decode_inner(s, true) } /** * Decode a string encoded with percent encoding. */ pub fn decode_component(s: &str) -> ~str { - // FIXME(#3722): unsafe only because decode_inner does (string) IO - unsafe {decode_inner(s, false)} + decode_inner(s, false) } fn encode_plus(s: &str) -> ~str { @@ -212,11 +208,11 @@ fn encode_plus(s: &str) -> ~str { /** * Encode a hashmap to the 'application/x-www-form-urlencoded' media type. */ -pub fn encode_form_urlencoded(m: &LinearMap<~str, ~[~str]>) -> ~str { +pub fn encode_form_urlencoded(m: &HashMap<~str, ~[~str]>) -> ~str { let mut out = ~""; let mut first = true; - for m.each |&(key, values)| { + for m.each |key, values| { let key = encode_plus(*key); for values.each |value| { @@ -238,9 +234,9 @@ pub fn encode_form_urlencoded(m: &LinearMap<~str, ~[~str]>) -> ~str { * Decode a string encoded with the 'application/x-www-form-urlencoded' media * type into a hashmap. */ -pub fn decode_form_urlencoded(s: &[u8]) -> LinearMap<~str, ~[~str]> { +pub fn decode_form_urlencoded(s: &[u8]) -> HashMap<~str, ~[~str]> { do io::with_bytes_reader(s) |rdr| { - let mut m = LinearMap::new(); + let mut m = HashMap::new(); let mut key = ~""; let mut value = ~""; let mut parsing_key = true; @@ -301,18 +297,15 @@ fn split_char_first(s: &str, c: char) -> (~str, ~str) { let len = str::len(s); let mut index = len; let mut mat = 0; - // FIXME(#3722): unsafe only because decode_inner does (string) IO - unsafe { - do io::with_str_reader(s) |rdr| { - let mut ch; - while !rdr.eof() { - ch = rdr.read_byte() as char; - if ch == c { - // found a match, adjust markers - index = rdr.tell()-1; - mat = 1; - break; - } + do io::with_str_reader(s) |rdr| { + let mut ch; + while !rdr.eof() { + ch = rdr.read_byte() as char; + if ch == c { + // found a match, adjust markers + index = rdr.tell()-1; + mat = 1; + break; } } } @@ -346,29 +339,25 @@ fn query_from_str(rawquery: &str) -> Query { if str::len(rawquery) != 0 { for str::each_split_char(rawquery, '&') |p| { let (k, v) = split_char_first(p, '='); - // FIXME(#3722): unsafe only because decode_inner does (string) IO - unsafe {query.push((decode_component(k), decode_component(v)));} + query.push((decode_component(k), decode_component(v))); }; } return query; } pub fn query_to_str(query: &Query) -> ~str { - unsafe { - // FIXME(#3722): unsafe only because decode_inner does (string) IO - let mut strvec = ~[]; - for query.each |kv| { - match kv { - &(ref k, ref v) => { - strvec.push(fmt!("%s=%s", - encode_component(*k), - encode_component(*v)) - ); - } + let mut strvec = ~[]; + for query.each |kv| { + match kv { + &(ref k, ref v) => { + strvec.push(fmt!("%s=%s", + encode_component(*k), + encode_component(*v)) + ); } } - return str::connect(strvec, ~"&"); } + return str::connect(strvec, ~"&"); } // returns the scheme and the rest of the url, or a parsing error @@ -398,7 +387,7 @@ pub fn get_scheme(rawurl: &str) -> Result<(~str, ~str), ~str> { return Err(~"url: Scheme must be terminated with a colon."); } -#[deriving(Eq)] +#[deriving(Clone, Eq)] enum Input { Digit, // all digits Hex, // digits and letters a-f @@ -818,10 +807,10 @@ mod tests { use net_url::*; - use core::hashmap::linear::LinearMap; + use core::hashmap::HashMap; #[test] - pub fn test_url_parse() { + fn test_url_parse() { let url = ~"http://user:pass@rust-lang.org/doc?s=v#something"; let up = from_str(url); @@ -837,7 +826,7 @@ mod tests { } #[test] - pub fn test_url_parse_host_slash() { + fn test_url_parse_host_slash() { let urlstr = ~"http://0.42.42.42/"; let url = from_str(urlstr).unwrap(); assert!(url.host == ~"0.42.42.42"); @@ -845,87 +834,87 @@ mod tests { } #[test] - pub fn test_url_with_underscores() { + fn test_url_with_underscores() { let urlstr = ~"http://dotcom.com/file_name.html"; let url = from_str(urlstr).unwrap(); assert!(url.path == ~"/file_name.html"); } #[test] - pub fn test_url_with_dashes() { + fn test_url_with_dashes() { let urlstr = ~"http://dotcom.com/file-name.html"; let url = from_str(urlstr).unwrap(); assert!(url.path == ~"/file-name.html"); } #[test] - pub fn test_no_scheme() { + fn test_no_scheme() { assert!(get_scheme("noschemehere.html").is_err()); } #[test] - pub fn test_invalid_scheme_errors() { + fn test_invalid_scheme_errors() { assert!(from_str("99://something").is_err()); assert!(from_str("://something").is_err()); } #[test] - pub fn test_full_url_parse_and_format() { + fn test_full_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc?s=v#something"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_userless_url_parse_and_format() { + fn test_userless_url_parse_and_format() { let url = ~"http://rust-lang.org/doc?s=v#something"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_queryless_url_parse_and_format() { + fn test_queryless_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc#something"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_empty_query_url_parse_and_format() { + fn test_empty_query_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc?#something"; let should_be = ~"http://user:pass@rust-lang.org/doc#something"; assert!(from_str(url).unwrap().to_str() == should_be); } #[test] - pub fn test_fragmentless_url_parse_and_format() { + fn test_fragmentless_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org/doc?q=v"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_minimal_url_parse_and_format() { + fn test_minimal_url_parse_and_format() { let url = ~"http://rust-lang.org/doc"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_scheme_host_only_url_parse_and_format() { + fn test_scheme_host_only_url_parse_and_format() { let url = ~"http://rust-lang.org"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_pathless_url_parse_and_format() { + fn test_pathless_url_parse_and_format() { let url = ~"http://user:pass@rust-lang.org?q=v#something"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_scheme_host_fragment_only_url_parse_and_format() { + fn test_scheme_host_fragment_only_url_parse_and_format() { let url = ~"http://rust-lang.org#something"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_url_component_encoding() { + fn test_url_component_encoding() { let url = ~"http://rust-lang.org/doc%20uments?ba%25d%20=%23%26%2B"; let u = from_str(url).unwrap(); assert!(u.path == ~"/doc uments"); @@ -933,13 +922,13 @@ mod tests { } #[test] - pub fn test_url_without_authority() { + fn test_url_without_authority() { let url = ~"mailto:test@email.com"; assert!(from_str(url).unwrap().to_str() == url); } #[test] - pub fn test_encode() { + fn test_encode() { assert!(encode("") == ~""); assert!(encode("http://example.com") == ~"http://example.com"); assert!(encode("foo bar% baz") == ~"foo%20bar%25%20baz"); @@ -967,7 +956,7 @@ mod tests { } #[test] - pub fn test_encode_component() { + fn test_encode_component() { assert!(encode_component("") == ~""); assert!(encode_component("http://example.com") == ~"http%3A%2F%2Fexample.com"); @@ -996,7 +985,7 @@ mod tests { } #[test] - pub fn test_decode() { + fn test_decode() { assert!(decode("") == ~""); assert!(decode("abc/def 123") == ~"abc/def 123"); assert!(decode("abc%2Fdef%20123") == ~"abc%2Fdef 123"); @@ -1024,7 +1013,7 @@ mod tests { } #[test] - pub fn test_decode_component() { + fn test_decode_component() { assert!(decode_component("") == ~""); assert!(decode_component("abc/def 123") == ~"abc/def 123"); assert!(decode_component("abc%2Fdef%20123") == ~"abc/def 123"); @@ -1052,26 +1041,26 @@ mod tests { } #[test] - pub fn test_encode_form_urlencoded() { - let mut m = LinearMap::new(); + fn test_encode_form_urlencoded() { + let mut m = HashMap::new(); assert!(encode_form_urlencoded(&m) == ~""); m.insert(~"", ~[]); m.insert(~"foo", ~[]); assert!(encode_form_urlencoded(&m) == ~""); - let mut m = LinearMap::new(); + let mut m = HashMap::new(); m.insert(~"foo", ~[~"bar", ~"123"]); assert!(encode_form_urlencoded(&m) == ~"foo=bar&foo=123"); - let mut m = LinearMap::new(); + let mut m = HashMap::new(); m.insert(~"foo bar", ~[~"abc", ~"12 = 34"]); assert!(encode_form_urlencoded(&m) == ~"foo+bar=abc&foo+bar=12+%3D+34"); } #[test] - pub fn test_decode_form_urlencoded() { + fn test_decode_form_urlencoded() { // FIXME #4449: Commented out because this causes an ICE, but only // on FreeBSD /* diff --git a/src/libstd/bigint.rs b/src/libstd/num/bigint.rs similarity index 90% rename from src/libstd/bigint.rs rename to src/libstd/num/bigint.rs index 35b1a28a465cd..ec5d2cded8d56 100644 --- a/src/libstd/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -16,8 +16,8 @@ A BigUint is represented as an array of BigDigits. A BigInt is a combination of BigUint and Sign. */ -use core::cmp::{Eq, Ord}; -use core::num::{IntConvertible, Zero, One}; +use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; +use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix}; use core::*; /** @@ -78,15 +78,46 @@ pub struct BigUint { } impl Eq for BigUint { - fn eq(&self, other: &BigUint) -> bool { self.cmp(other) == 0 } - fn ne(&self, other: &BigUint) -> bool { self.cmp(other) != 0 } + fn eq(&self, other: &BigUint) -> bool { self.equals(other) } + fn ne(&self, other: &BigUint) -> bool { !self.equals(other) } +} + +impl TotalEq for BigUint { + fn equals(&self, other: &BigUint) -> bool { + match self.cmp(other) { Equal => true, _ => false } + } } impl Ord for BigUint { - fn lt(&self, other: &BigUint) -> bool { self.cmp(other) < 0 } - fn le(&self, other: &BigUint) -> bool { self.cmp(other) <= 0 } - fn ge(&self, other: &BigUint) -> bool { self.cmp(other) >= 0 } - fn gt(&self, other: &BigUint) -> bool { self.cmp(other) > 0 } + fn lt(&self, other: &BigUint) -> bool { + match self.cmp(other) { Less => true, _ => false} + } + fn le(&self, other: &BigUint) -> bool { + match self.cmp(other) { Less | Equal => true, _ => false } + } + fn ge(&self, other: &BigUint) -> bool { + match self.cmp(other) { Greater | Equal => true, _ => false } + } + fn gt(&self, other: &BigUint) -> bool { + match self.cmp(other) { Greater => true, _ => false } + } +} + +impl TotalOrd for BigUint { + fn cmp(&self, other: &BigUint) -> Ordering { + let s_len = self.data.len(), o_len = other.data.len(); + if s_len < o_len { return Less; } + if s_len > o_len { return Greater; } + + for self.data.eachi_reverse |i, elm| { + match (*elm, other.data[i]) { + (l, r) if l < r => return Less, + (l, r) if l > r => return Greater, + _ => loop + }; + } + return Equal; + } } impl ToStr for BigUint { @@ -95,7 +126,7 @@ impl ToStr for BigUint { impl from_str::FromStr for BigUint { fn from_str(s: &str) -> Option { - BigUint::from_str_radix(s, 10) + FromStrRadix::from_str_radix(s, 10) } } @@ -189,12 +220,10 @@ impl Mul for BigUint { let mm = { let (s1, n1) = sub_sign(sHi, sLo); let (s2, n2) = sub_sign(oHi, oLo); - if s1 * s2 < 0 { - hh + ll + (n1 * n2) - } else if s1 * s2 > 0 { - hh + ll - (n1 * n2) - } else { - hh + ll + match (s1, s2) { + (Equal, _) | (_, Equal) => hh + ll, + (Less, Greater) | (Greater, Less) => hh + ll + (n1 * n2), + (Less, Less) | (Greater, Greater) => hh + ll - (n1 * n2) } }; @@ -223,11 +252,11 @@ impl Mul for BigUint { BigUint::from_slice(vec::slice(a.data, 0, mid))); } - fn sub_sign(a: BigUint, b: BigUint) -> (int, BigUint) { + fn sub_sign(a: BigUint, b: BigUint) -> (Ordering, BigUint) { match a.cmp(&b) { - s if s < 0 => (s, b - a), - s if s > 0 => (s, a - b), - _ => (0, Zero::zero()) + Less => (Less, b - a), + Greater => (Greater, a - b), + _ => (Equal, Zero::zero()) } } } @@ -261,6 +290,49 @@ impl IntConvertible for BigUint { } } +impl ToStrRadix for BigUint { + fn to_str_radix(&self, radix: uint) -> ~str { + assert!(1 < radix && radix <= 16); + let (base, max_len) = get_radix_base(radix); + if base == BigDigit::base { + return fill_concat(self.data, radix, max_len) + } + return fill_concat(convert_base(copy *self, base), radix, max_len); + + fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] { + let divider = BigUint::from_uint(base); + let mut result = ~[]; + let mut r = n; + while r > divider { + let (d, r0) = r.divmod(÷r); + result += [r0.to_uint() as BigDigit]; + r = d; + } + if r.is_not_zero() { + result += [r.to_uint() as BigDigit]; + } + return result; + } + + fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str { + if v.is_empty() { return ~"0" } + let s = str::concat(vec::reversed(v).map(|n| { + let s = uint::to_str_radix(*n as uint, radix); + str::from_chars(vec::from_elem(l - s.len(), '0')) + s + })); + str::trim_left_chars(s, ['0']).to_owned() + } + } +} + +impl FromStrRadix for BigUint { + /// Creates and initializes an BigUint. + pub fn from_str_radix(s: &str, radix: uint) + -> Option { + BigUint::parse_bytes(str::to_bytes(s), radix) + } +} + pub impl BigUint { /// Creates and initializes an BigUint. pub fn new(v: ~[BigDigit]) -> BigUint { @@ -269,7 +341,7 @@ pub impl BigUint { if new_len == v.len() { return BigUint { data: v }; } let mut v = v; - unsafe { v.truncate(new_len); } + v.truncate(new_len); return BigUint { data: v }; } @@ -287,12 +359,6 @@ pub impl BigUint { return BigUint::new(vec::from_slice(slice)); } - /// Creates and initializes an BigUint. - pub fn from_str_radix(s: &str, radix: uint) - -> Option { - BigUint::parse_bytes(str::to_bytes(s), radix) - } - /// Creates and initializes an BigUint. pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { @@ -318,31 +384,15 @@ pub impl BigUint { fn abs(&self) -> BigUint { copy *self } - /// Compare two BigUint value. - fn cmp(&self, other: &BigUint) -> int { - let s_len = self.data.len(), o_len = other.data.len(); - if s_len < o_len { return -1; } - if s_len > o_len { return 1; } - - for self.data.eachi_reverse |i, elm| { - match (*elm, other.data[i]) { - (l, r) if l < r => return -1, - (l, r) if l > r => return 1, - _ => loop - }; - } - return 0; - } - fn divmod(&self, other: &BigUint) -> (BigUint, BigUint) { if other.is_zero() { fail!() } if self.is_zero() { return (Zero::zero(), Zero::zero()); } if *other == One::one() { return (copy *self, Zero::zero()); } match self.cmp(other) { - s if s < 0 => return (Zero::zero(), copy *self), - 0 => return (One::one(), Zero::zero()), - _ => {} // Do nothing + Less => return (Zero::zero(), copy *self), + Equal => return (One::one(), Zero::zero()), + Greater => {} // Do nothing } let mut shift = 0; @@ -433,39 +483,6 @@ pub impl BigUint { } } - fn to_str_radix(&self, radix: uint) -> ~str { - assert!(1 < radix && radix <= 16); - let (base, max_len) = get_radix_base(radix); - if base == BigDigit::base { - return fill_concat(self.data, radix, max_len) - } - return fill_concat(convert_base(copy *self, base), radix, max_len); - - fn convert_base(n: BigUint, base: uint) -> ~[BigDigit] { - let divider = BigUint::from_uint(base); - let mut result = ~[]; - let mut r = n; - while r > divider { - let (d, r0) = r.divmod(÷r); - result += [r0.to_uint() as BigDigit]; - r = d; - } - if r.is_not_zero() { - result += [r.to_uint() as BigDigit]; - } - return result; - } - - fn fill_concat(v: &[BigDigit], radix: uint, l: uint) -> ~str { - if v.is_empty() { return ~"0" } - let s = str::concat(vec::reversed(v).map(|n| { - let s = uint::to_str_radix(*n as uint, radix); - str::from_chars(vec::from_elem(l - s.len(), '0')) + s - })); - str::trim_left_chars(s, ['0']).to_owned() - } - } - priv fn shl_unit(self, n_unit: uint) -> BigUint { if n_unit == 0 || self.is_zero() { return self; } @@ -561,22 +578,31 @@ priv fn get_radix_base(radix: uint) -> (uint, uint) { pub enum Sign { Minus, Zero, Plus } impl Ord for Sign { - fn lt(&self, other: &Sign) -> bool { self.cmp(other) < 0 } - fn le(&self, other: &Sign) -> bool { self.cmp(other) <= 0 } - fn ge(&self, other: &Sign) -> bool { self.cmp(other) >= 0 } - fn gt(&self, other: &Sign) -> bool { self.cmp(other) > 0 } + fn lt(&self, other: &Sign) -> bool { + match self.cmp(other) { Less => true, _ => false} + } + fn le(&self, other: &Sign) -> bool { + match self.cmp(other) { Less | Equal => true, _ => false } + } + fn ge(&self, other: &Sign) -> bool { + match self.cmp(other) { Greater | Equal => true, _ => false } + } + fn gt(&self, other: &Sign) -> bool { + match self.cmp(other) { Greater => true, _ => false } + } } -pub impl Sign { - /// Compare two Sign. - fn cmp(&self, other: &Sign) -> int { +impl TotalOrd for Sign { + fn cmp(&self, other: &Sign) -> Ordering { match (*self, *other) { - (Minus, Minus) | (Zero, Zero) | (Plus, Plus) => 0, - (Minus, Zero) | (Minus, Plus) | (Zero, Plus) => -1, - _ => 1 + (Minus, Minus) | (Zero, Zero) | (Plus, Plus) => Equal, + (Minus, Zero) | (Minus, Plus) | (Zero, Plus) => Less, + _ => Greater } } +} +impl Neg for Sign { /// Negate Sign value. fn neg(&self) -> Sign { match *self { @@ -594,15 +620,42 @@ pub struct BigInt { } impl Eq for BigInt { - fn eq(&self, other: &BigInt) -> bool { self.cmp(other) == 0 } - fn ne(&self, other: &BigInt) -> bool { self.cmp(other) != 0 } + fn eq(&self, other: &BigInt) -> bool { self.equals(other) } + fn ne(&self, other: &BigInt) -> bool { !self.equals(other) } +} + +impl TotalEq for BigInt { + fn equals(&self, other: &BigInt) -> bool { + match self.cmp(other) { Equal => true, _ => false } + } } impl Ord for BigInt { - fn lt(&self, other: &BigInt) -> bool { self.cmp(other) < 0 } - fn le(&self, other: &BigInt) -> bool { self.cmp(other) <= 0 } - fn ge(&self, other: &BigInt) -> bool { self.cmp(other) >= 0 } - fn gt(&self, other: &BigInt) -> bool { self.cmp(other) > 0 } + fn lt(&self, other: &BigInt) -> bool { + match self.cmp(other) { Less => true, _ => false} + } + fn le(&self, other: &BigInt) -> bool { + match self.cmp(other) { Less | Equal => true, _ => false } + } + fn ge(&self, other: &BigInt) -> bool { + match self.cmp(other) { Greater | Equal => true, _ => false } + } + fn gt(&self, other: &BigInt) -> bool { + match self.cmp(other) { Greater => true, _ => false } + } +} + +impl TotalOrd for BigInt { + fn cmp(&self, other: &BigInt) -> Ordering { + let scmp = self.sign.cmp(&other.sign); + if scmp != Equal { return scmp; } + + match self.sign { + Zero => Equal, + Plus => self.data.cmp(&other.data), + Minus => other.data.cmp(&self.data), + } + } } impl ToStr for BigInt { @@ -611,7 +664,7 @@ impl ToStr for BigInt { impl from_str::FromStr for BigInt { fn from_str(s: &str) -> Option { - BigInt::from_str_radix(s, 10) + FromStrRadix::from_str_radix(s, 10) } } @@ -659,12 +712,9 @@ impl Sub for BigInt { (Zero, _) => -other, (_, Zero) => copy *self, (Plus, Plus) => match self.data.cmp(&other.data) { - s if s < 0 => - BigInt::from_biguint(Minus, other.data - self.data), - s if s > 0 => - BigInt::from_biguint(Plus, self.data - other.data), - _ => - Zero::zero() + Less => BigInt::from_biguint(Minus, other.data - self.data), + Greater => BigInt::from_biguint(Plus, self.data - other.data), + Equal => Zero::zero() }, (Plus, Minus) => self + (-*other), (Minus, Plus) => -((-self) + *other), @@ -730,6 +780,24 @@ impl IntConvertible for BigInt { } } +impl ToStrRadix for BigInt { + fn to_str_radix(&self, radix: uint) -> ~str { + match self.sign { + Plus => self.data.to_str_radix(radix), + Zero => ~"0", + Minus => ~"-" + self.data.to_str_radix(radix) + } + } +} + +impl FromStrRadix for BigInt { + /// Creates and initializes an BigInt. + pub fn from_str_radix(s: &str, radix: uint) + -> Option { + BigInt::parse_bytes(str::to_bytes(s), radix) + } +} + pub impl BigInt { /// Creates and initializes an BigInt. pub fn new(sign: Sign, v: ~[BigDigit]) -> BigInt { @@ -755,12 +823,6 @@ pub impl BigInt { BigInt::from_biguint(sign, BigUint::from_slice(slice)) } - /// Creates and initializes an BigInt. - pub fn from_str_radix(s: &str, radix: uint) - -> Option { - BigInt::parse_bytes(str::to_bytes(s), radix) - } - /// Creates and initializes an BigInt. pub fn parse_bytes(buf: &[u8], radix: uint) -> Option { @@ -779,19 +841,6 @@ pub impl BigInt { BigInt::from_biguint(Plus, copy self.data) } - fn cmp(&self, other: &BigInt) -> int { - let ss = self.sign, os = other.sign; - if ss < os { return -1; } - if ss > os { return 1; } - - assert!(ss == os); - match ss { - Zero => 0, - Plus => self.data.cmp(&other.data), - Minus => self.data.cmp(&other.data).neg(), - } - } - fn divmod(&self, other: &BigInt) -> (BigInt, BigInt) { // m.sign == other.sign let (d_ui, m_ui) = self.data.divmod(&other.data); @@ -851,21 +900,14 @@ pub impl BigInt { Minus => 0 } } - - fn to_str_radix(&self, radix: uint) -> ~str { - match self.sign { - Plus => self.data.to_str_radix(radix), - Zero => ~"0", - Minus => ~"-" + self.data.to_str_radix(radix) - } - } } #[cfg(test)] mod biguint_tests { use core::*; - use core::num::{IntConvertible, Zero, One}; + use core::num::{IntConvertible, Zero, One, FromStrRadix}; + use core::cmp::{Less, Equal, Greater}; use super::{BigUint, BigDigit}; #[test] @@ -889,8 +931,8 @@ mod biguint_tests { for vec::slice(data, i, data.len()).eachi |j0, nj| { let j = j0 + i; if i == j { - assert!(ni.cmp(nj) == 0); - assert!(nj.cmp(ni) == 0); + assert_eq!(ni.cmp(nj), Equal); + assert_eq!(nj.cmp(ni), Equal); assert!(ni == nj); assert!(!(ni != nj)); assert!(ni <= nj); @@ -898,8 +940,8 @@ mod biguint_tests { assert!(!(ni < nj)); assert!(!(ni > nj)); } else { - assert!(ni.cmp(nj) < 0); - assert!(nj.cmp(ni) > 0); + assert_eq!(ni.cmp(nj), Less); + assert_eq!(nj.cmp(ni), Greater); assert!(!(ni == nj)); assert!(ni != nj); @@ -1245,13 +1287,13 @@ mod biguint_tests { let &(n, rs) = num_pair; for rs.each |str_pair| { let &(radix, str) = str_pair; - assert!(Some(n) == BigUint::from_str_radix(str, radix)); + assert_eq!(Some(n), FromStrRadix::from_str_radix(str, radix)); } } - assert!(BigUint::from_str_radix(~"Z", 10) == None); - assert!(BigUint::from_str_radix(~"_", 2) == None); - assert!(BigUint::from_str_radix(~"-1", 10) == None); + assert_eq!(FromStrRadix::from_str_radix::(~"Z", 10), None); + assert_eq!(FromStrRadix::from_str_radix::(~"_", 2), None); + assert_eq!(FromStrRadix::from_str_radix::(~"-1", 10), None); } #[test] @@ -1266,7 +1308,7 @@ mod biguint_tests { fn check(n: uint, s: &str) { let n = factor(n); - let ans = match BigUint::from_str_radix(s, 10) { + let ans = match FromStrRadix::from_str_radix(s, 10) { Some(x) => x, None => fail!() }; assert!(n == ans); @@ -1282,9 +1324,9 @@ mod biguint_tests { #[cfg(test)] mod bigint_tests { use super::{BigInt, BigUint, BigDigit, Sign, Minus, Zero, Plus}; - use core::*; - use core::num::{IntConvertible, Zero, One}; + use core::cmp::{Less, Equal, Greater}; + use core::num::{IntConvertible, Zero, One, FromStrRadix}; #[test] fn test_from_biguint() { @@ -1311,8 +1353,8 @@ mod bigint_tests { for vec::slice(nums, i, nums.len()).eachi |j0, nj| { let j = i + j0; if i == j { - assert!(ni.cmp(nj) == 0); - assert!(nj.cmp(ni) == 0); + assert_eq!(ni.cmp(nj), Equal); + assert_eq!(nj.cmp(ni), Equal); assert!(ni == nj); assert!(!(ni != nj)); assert!(ni <= nj); @@ -1320,8 +1362,8 @@ mod bigint_tests { assert!(!(ni < nj)); assert!(!(ni > nj)); } else { - assert!(ni.cmp(nj) < 0); - assert!(nj.cmp(ni) > 0); + assert_eq!(ni.cmp(nj), Less); + assert_eq!(nj.cmp(ni), Greater); assert!(!(ni == nj)); assert!(ni != nj); @@ -1623,8 +1665,8 @@ mod bigint_tests { #[test] fn test_from_str_radix() { fn check(s: &str, ans: Option) { - let ans = ans.map(|&n| IntConvertible::from_int(n)); - assert!(BigInt::from_str_radix(s, 10) == ans); + let ans = ans.map(|&n| IntConvertible::from_int::(n)); + assert!(FromStrRadix::from_str_radix(s, 10) == ans); } check("10", Some(10)); check("1", Some(1)); diff --git a/src/libstd/num/complex.rs b/src/libstd/num/complex.rs new file mode 100644 index 0000000000000..949850f3ca677 --- /dev/null +++ b/src/libstd/num/complex.rs @@ -0,0 +1,314 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +//! Complex numbers. + +use core::num::{Zero,One,ToStrRadix}; +use core::prelude::*; + +// FIXME #1284: handle complex NaN & infinity etc. This +// probably doesn't map to C's _Complex correctly. + +// FIXME #5734:: Need generic sin/cos for .to/from_polar(). +// FIXME #5735: Need generic sqrt to implement .norm(). + + +/// A complex number in Cartesian form. +#[deriving(Eq,Clone)] +pub struct Cmplx { + re: T, + im: T +} + +pub type Complex = Cmplx; +pub type Complex32 = Cmplx; +pub type Complex64 = Cmplx; + +impl + Sub + Mul + Div + Neg> + Cmplx { + /// Create a new Cmplx + #[inline] + pub fn new(re: T, im: T) -> Cmplx { + Cmplx { re: re, im: im } + } + + /** + Returns the square of the norm (since `T` doesn't necessarily + have a sqrt function), i.e. `re^2 + im^2`. + */ + #[inline] + pub fn norm_sqr(&self) -> T { + self.re * self.re + self.im * self.im + } + + + /// Returns the complex conjugate. i.e. `re - i im` + #[inline] + pub fn conj(&self) -> Cmplx { + Cmplx::new(self.re, -self.im) + } + + + /// Multiplies `self` by the scalar `t`. + #[inline] + pub fn scale(&self, t: T) -> Cmplx { + Cmplx::new(self.re * t, self.im * t) + } + + /// Divides `self` by the scalar `t`. + #[inline] + pub fn unscale(&self, t: T) -> Cmplx { + Cmplx::new(self.re / t, self.im / t) + } + + /// Returns `1/self` + #[inline] + pub fn inv(&self) -> Cmplx { + let norm_sqr = self.norm_sqr(); + Cmplx::new(self.re / norm_sqr, + -self.im / norm_sqr) + } +} + +/* arithmetic */ +// (a + i b) + (c + i d) == (a + c) + i (b + d) +impl + Sub + Mul + Div + Neg> + Add, Cmplx> for Cmplx { + #[inline] + fn add(&self, other: &Cmplx) -> Cmplx { + Cmplx::new(self.re + other.re, self.im + other.im) + } +} +// (a + i b) - (c + i d) == (a - c) + i (b - d) +impl + Sub + Mul + Div + Neg> + Sub, Cmplx> for Cmplx { + #[inline] + fn sub(&self, other: &Cmplx) -> Cmplx { + Cmplx::new(self.re - other.re, self.im - other.im) + } +} +// (a + i b) * (c + i d) == (a*c - b*d) + i (a*d + b*c) +impl + Sub + Mul + Div + Neg> + Mul, Cmplx> for Cmplx { + #[inline] + fn mul(&self, other: &Cmplx) -> Cmplx { + Cmplx::new(self.re*other.re - self.im*other.im, + self.re*other.im + self.im*other.re) + } +} + +// (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d) +// == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)] +impl + Sub + Mul + Div + Neg> + Div, Cmplx> for Cmplx { + #[inline] + fn div(&self, other: &Cmplx) -> Cmplx { + let norm_sqr = other.norm_sqr(); + Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr, + (self.im*other.re - self.re*other.im) / norm_sqr) + } +} + +impl + Sub + Mul + Div + Neg> + Neg> for Cmplx { + #[inline] + fn neg(&self) -> Cmplx { + Cmplx::new(-self.re, -self.im) + } +} + +/* constants */ +impl + Sub + Mul + Div + Neg + Zero> + Zero for Cmplx { + #[inline] + fn zero() -> Cmplx { + Cmplx::new(Zero::zero(), Zero::zero()) + } +} + +impl + Sub + Mul + Div + Neg + Zero + One> + One for Cmplx { + #[inline] + fn one() -> Cmplx { + Cmplx::new(One::one(), Zero::zero()) + } +} + +/* string conversions */ +impl> ToStr for Cmplx { + fn to_str(&self) -> ~str { + if self.im < Zero::zero() { + fmt!("%s-%si", self.re.to_str(), (-self.im).to_str()) + } else { + fmt!("%s+%si", self.re.to_str(), self.im.to_str()) + } + } +} + +impl> ToStrRadix for Cmplx { + fn to_str_radix(&self, radix: uint) -> ~str { + if self.im < Zero::zero() { + fmt!("%s-%si", self.re.to_str_radix(radix), (-self.im).to_str_radix(radix)) + } else { + fmt!("%s+%si", self.re.to_str_radix(radix), self.im.to_str_radix(radix)) + } + } +} + +#[cfg(test)] +mod test { + use core::prelude::*; + use super::*; + use core::num::{Zero,One}; + + pub static _0_0i : Complex = Cmplx { re: 0f, im: 0f }; + pub static _1_0i : Complex = Cmplx { re: 1f, im: 0f }; + pub static _1_1i : Complex = Cmplx { re: 1f, im: 1f }; + pub static _0_1i : Complex = Cmplx { re: 0f, im: 1f }; + pub static _neg1_1i : Complex = Cmplx { re: -1f, im: 1f }; + pub static _05_05i : Complex = Cmplx { re: 0.5f, im: 0.5f }; + pub static all_consts : [Complex, .. 5] = [_0_0i, _1_0i, _1_1i, _neg1_1i, _05_05i]; + + #[test] + fn test_consts() { + // check our constants are what Cmplx::new creates + fn test(c : Complex, r : float, i: float) { + assert_eq!(c, Cmplx::new(r,i)); + } + test(_0_0i, 0f, 0f); + test(_1_0i, 1f, 0f); + test(_1_1i, 1f, 1f); + test(_neg1_1i, -1f, 1f); + test(_05_05i, 0.5f, 0.5f); + + assert_eq!(_0_0i, Zero::zero()); + assert_eq!(_1_0i, One::one()); + } + + #[test] + fn test_norm_sqr() { + fn test(c: Complex, ns: float) { + assert_eq!(c.norm_sqr(), ns); + } + test(_0_0i, 0f); + test(_1_0i, 1f); + test(_1_1i, 2f); + test(_neg1_1i, 2f); + test(_05_05i, 0.5f); + } + + #[test] + fn test_scale_unscale() { + assert_eq!(_05_05i.scale(2f), _1_1i); + assert_eq!(_1_1i.unscale(2f), _05_05i); + for all_consts.each |&c| { + assert_eq!(c.scale(2f).unscale(2f), c); + } + } + + #[test] + fn test_conj() { + for all_consts.each |&c| { + assert_eq!(c.conj(), Cmplx::new(c.re, -c.im)); + assert_eq!(c.conj().conj(), c); + } + } + + #[test] + fn test_inv() { + assert_eq!(_1_1i.inv(), _05_05i.conj()); + assert_eq!(_1_0i.inv(), _1_0i.inv()); + } + + #[test] + #[should_fail] + #[ignore] + fn test_inv_zero() { + // FIXME #5736: should this really fail, or just NaN? + _0_0i.inv(); + } + + + mod arith { + use super::*; + use core::num::Zero; + + #[test] + fn test_add() { + assert_eq!(_05_05i + _05_05i, _1_1i); + assert_eq!(_0_1i + _1_0i, _1_1i); + assert_eq!(_1_0i + _neg1_1i, _0_1i); + + for all_consts.each |&c| { + assert_eq!(_0_0i + c, c); + assert_eq!(c + _0_0i, c); + } + } + + #[test] + fn test_sub() { + assert_eq!(_05_05i - _05_05i, _0_0i); + assert_eq!(_0_1i - _1_0i, _neg1_1i); + assert_eq!(_0_1i - _neg1_1i, _1_0i); + + for all_consts.each |&c| { + assert_eq!(c - _0_0i, c); + assert_eq!(c - c, _0_0i); + } + } + + #[test] + fn test_mul() { + assert_eq!(_05_05i * _05_05i, _0_1i.unscale(2f)); + assert_eq!(_1_1i * _0_1i, _neg1_1i); + + // i^2 & i^4 + assert_eq!(_0_1i * _0_1i, -_1_0i); + assert_eq!(_0_1i * _0_1i * _0_1i * _0_1i, _1_0i); + + for all_consts.each |&c| { + assert_eq!(c * _1_0i, c); + assert_eq!(_1_0i * c, c); + } + } + #[test] + fn test_div() { + assert_eq!(_neg1_1i / _0_1i, _1_1i); + for all_consts.each |&c| { + if c != Zero::zero() { + assert_eq!(c / c, _1_0i); + } + } + } + #[test] + fn test_neg() { + assert_eq!(-_1_0i + _0_1i, _neg1_1i); + assert_eq!((-_0_1i) * _0_1i, _1_0i); + for all_consts.each |&c| { + assert_eq!(-(-c), c); + } + } + } + + #[test] + fn test_to_str() { + fn test(c : Complex, s: ~str) { + assert_eq!(c.to_str(), s); + } + test(_0_0i, ~"0+0i"); + test(_1_0i, ~"1+0i"); + test(_0_1i, ~"0+1i"); + test(_1_1i, ~"1+1i"); + test(_neg1_1i, ~"-1+1i"); + test(-_neg1_1i, ~"1-1i"); + test(_05_05i, ~"0.5+0.5i"); + } +} diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs new file mode 100644 index 0000000000000..f15b382dcd351 --- /dev/null +++ b/src/libstd/num/rational.rs @@ -0,0 +1,511 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +//! Rational numbers + +use core::num::{Zero,One,ToStrRadix,FromStrRadix,Round}; +use core::from_str::FromStr; +use core::to_str::ToStr; +use core::prelude::*; +use core::cmp::TotalEq; +use super::bigint::BigInt; + +/// Represents the ratio between 2 numbers. +#[deriving(Clone)] +pub struct Ratio { + numer: T, + denom: T +} + +/// Alias for a `Ratio` of machine-sized integers. +pub type Rational = Ratio; +pub type Rational32 = Ratio; +pub type Rational64 = Ratio; + +/// Alias for arbitrary precision rationals. +pub type BigRational = Ratio; + +impl + Modulo + Neg + Zero + One + Ord + Eq> + Ratio { + /// Create a ratio representing the integer `t`. + #[inline(always)] + pub fn from_integer(t: T) -> Ratio { + Ratio::new_raw(t, One::one()) + } + + /// Create a ratio without checking for `denom == 0` or reducing. + #[inline(always)] + pub fn new_raw(numer: T, denom: T) -> Ratio { + Ratio { numer: numer, denom: denom } + } + + // Create a new Ratio. Fails if `denom == 0`. + #[inline(always)] + pub fn new(numer: T, denom: T) -> Ratio { + if denom == Zero::zero() { + fail!(~"divide by 0"); + } + let mut ret = Ratio::new_raw(numer, denom); + ret.reduce(); + ret + } + + /// Put self into lowest terms, with denom > 0. + fn reduce(&mut self) { + let mut g : T = gcd(self.numer, self.denom); + + self.numer /= g; + self.denom /= g; + + // keep denom positive! + if self.denom < Zero::zero() { + self.numer = -self.numer; + self.denom = -self.denom; + } + } + /// Return a `reduce`d copy of self. + fn reduced(&self) -> Ratio { + let mut ret = copy *self; + ret.reduce(); + ret + } +} + +/** +Compute the greatest common divisor of two numbers, via Euclid's algorithm. + +The result can be negative. +*/ +#[inline] +pub fn gcd_raw + Zero + Eq>(n: T, m: T) -> T { + let mut m = m, n = n; + while m != Zero::zero() { + let temp = m; + m = n % temp; + n = temp; + } + n +} + +/** +Compute the greatest common divisor of two numbers, via Euclid's algorithm. + +The result is always positive. +*/ +#[inline] +pub fn gcd + Neg + Zero + Ord + Eq>(n: T, m: T) -> T { + let g = gcd_raw(n, m); + if g < Zero::zero() { -g } + else { g } +} + +/* Comparisons */ + +// comparing a/b and c/d is the same as comparing a*d and b*c, so we +// abstract that pattern. The following macro takes a trait and either +// a comma-separated list of "method name -> return value" or just +// "method name" (return value is bool in that case) +macro_rules! cmp_impl { + (impl $imp:ident, $($method:ident),+) => { + cmp_impl!(impl $imp, $($method -> bool),+) + }; + // return something other than a Ratio + (impl $imp:ident, $($method:ident -> $res:ty),+) => { + impl + $imp> $imp for Ratio { + $( + #[inline] + fn $method(&self, other: &Ratio) -> $res { + (self.numer * other.denom). $method (&(self.denom*other.numer)) + } + )+ + } + }; +} +cmp_impl!(impl Eq, eq, ne) +cmp_impl!(impl TotalEq, equals) +cmp_impl!(impl Ord, lt, gt, le, ge) +cmp_impl!(impl TotalOrd, cmp -> cmp::Ordering) + +/* Arithmetic */ +// a/b * c/d = (a*c)/(b*d) +impl + Div + Modulo + Neg + Zero + One + Ord + Eq> + Mul,Ratio> for Ratio { + #[inline] + fn mul(&self, rhs: &Ratio) -> Ratio { + Ratio::new(self.numer * rhs.numer, self.denom * rhs.denom) + } +} + +// (a/b) / (c/d) = (a*d)/(b*c) +impl + Div + Modulo + Neg + Zero + One + Ord + Eq> + Div,Ratio> for Ratio { + #[inline] + fn div(&self, rhs: &Ratio) -> Ratio { + Ratio::new(self.numer * rhs.denom, self.denom * rhs.numer) + } +} + +// Abstracts the a/b `op` c/d = (a*d `op` b*d) / (b*d) pattern +macro_rules! arith_impl { + (impl $imp:ident, $method:ident) => { + impl + Sub + Mul + Div + Modulo + Neg + + Zero + One + Ord + Eq> + $imp,Ratio> for Ratio { + #[inline] + fn $method(&self, rhs: &Ratio) -> Ratio { + Ratio::new((self.numer * rhs.denom).$method(&(self.denom * rhs.numer)), + self.denom * rhs.denom) + } + } + } +} + +// a/b + c/d = (a*d + b*c)/(b*d +arith_impl!(impl Add, add) + +// a/b - c/d = (a*d - b*c)/(b*d) +arith_impl!(impl Sub, sub) + +// a/b % c/d = (a*d % b*c)/(b*d) +arith_impl!(impl Modulo, modulo) + +impl + Modulo + Neg + Zero + One + Ord + Eq> + Neg> for Ratio { + #[inline] + fn neg(&self) -> Ratio { + Ratio::new_raw(-self.numer, self.denom) + } +} + +/* Constants */ +impl + Modulo + Neg + Zero + One + Ord + Eq> + Zero for Ratio { + #[inline] + fn zero() -> Ratio { + Ratio::new_raw(Zero::zero(), One::one()) + } +} + +impl + Modulo + Neg + Zero + One + Ord + Eq> + One for Ratio { + #[inline] + fn one() -> Ratio { + Ratio::new_raw(One::one(), One::one()) + } +} + +/* Utils */ +impl + Sub + Mul + Div + Modulo + Neg + + Zero + One + Ord + Eq> + Round for Ratio { + fn round(&self, mode: num::RoundMode) -> Ratio { + match mode { + num::RoundUp => { self.ceil() } + num::RoundDown => { self.floor()} + num::RoundToZero => { Ratio::from_integer(self.numer / self.denom) } + num::RoundFromZero => { + if *self < Zero::zero() { + Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom) + } else { + Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom) + } + } + } + } + + fn floor(&self) -> Ratio { + if *self < Zero::zero() { + Ratio::from_integer((self.numer - self.denom + One::one()) / self.denom) + } else { + Ratio::from_integer(self.numer / self.denom) + } + } + fn ceil(&self) -> Ratio { + if *self < Zero::zero() { + Ratio::from_integer(self.numer / self.denom) + } else { + Ratio::from_integer((self.numer + self.denom - One::one()) / self.denom) + } + } + fn fract(&self) -> Ratio { + Ratio::new_raw(self.numer % self.denom, self.denom) + } +} + + +/* String conversions */ +impl ToStr for Ratio { + /// Renders as `numer/denom`. + fn to_str(&self) -> ~str { + fmt!("%s/%s", self.numer.to_str(), self.denom.to_str()) + } +} +impl ToStrRadix for Ratio { + /// Renders as `numer/denom` where the numbers are in base `radix`. + fn to_str_radix(&self, radix: uint) -> ~str { + fmt!("%s/%s", self.numer.to_str_radix(radix), self.denom.to_str_radix(radix)) + } +} + +impl + Modulo + Neg + Zero + One + Ord + Eq> + FromStr for Ratio { + /// Parses `numer/denom`. + fn from_str(s: &str) -> Option> { + let split = vec::build(|push| { + for str::each_splitn_char(s, '/', 1) |s| { + push(s.to_owned()); + } + }); + if split.len() < 2 { return None; } + do FromStr::from_str(split[0]).chain |a| { + do FromStr::from_str(split[1]).chain |b| { + Some(Ratio::new(a,b)) + } + } + } +} +impl + Modulo + Neg + Zero + One + Ord + Eq> + FromStrRadix for Ratio { + /// Parses `numer/denom` where the numbers are in base `radix`. + fn from_str_radix(s: &str, radix: uint) -> Option> { + let split = vec::build(|push| { + for str::each_splitn_char(s, '/', 1) |s| { + push(s.to_owned()); + } + }); + if split.len() < 2 { None } + else { + do FromStrRadix::from_str_radix(split[0], radix).chain |a| { + do FromStrRadix::from_str_radix(split[1], radix).chain |b| { + Some(Ratio::new(a,b)) + } + } + } + } +} + +#[cfg(test)] +mod test { + use core::prelude::*; + use super::*; + use core::num::{Zero,One,FromStrRadix}; + use core::from_str::FromStr; + + pub static _0 : Rational = Ratio { numer: 0, denom: 1}; + pub static _1 : Rational = Ratio { numer: 1, denom: 1}; + pub static _2: Rational = Ratio { numer: 2, denom: 1}; + pub static _1_2: Rational = Ratio { numer: 1, denom: 2}; + pub static _3_2: Rational = Ratio { numer: 3, denom: 2}; + pub static _neg1_2: Rational = Ratio { numer: -1, denom: 2}; + + #[test] + fn test_gcd() { + assert_eq!(gcd(10,2),2); + assert_eq!(gcd(10,3),1); + assert_eq!(gcd(0,3),3); + assert_eq!(gcd(3,3),3); + + assert_eq!(gcd(3,-3), 3); + assert_eq!(gcd(-6,3), 3); + assert_eq!(gcd(-4,-2), 2); + } + + #[test] + fn test_test_constants() { + // check our constants are what Ratio::new etc. would make. + assert_eq!(_0, Zero::zero()); + assert_eq!(_1, One::one()); + assert_eq!(_2, Ratio::from_integer(2)); + assert_eq!(_1_2, Ratio::new(1,2)); + assert_eq!(_3_2, Ratio::new(3,2)); + assert_eq!(_neg1_2, Ratio::new(-1,2)); + } + + #[test] + fn test_new_reduce() { + let one22 = Ratio::new(2i,2); + + assert_eq!(one22, One::one()); + } + #[test] + #[should_fail] + fn test_new_zero() { + let _a = Ratio::new(1,0); + } + + + #[test] + fn test_cmp() { + assert!(_0 == _0 && _1 == _1); + assert!(_0 != _1 && _1 != _0); + assert!(_0 < _1 && !(_1 < _0)); + assert!(_1 > _0 && !(_0 > _1)); + + assert!(_0 <= _0 && _1 <= _1); + assert!(_0 <= _1 && !(_1 <= _0)); + + assert!(_0 >= _0 && _1 >= _1); + assert!(_1 >= _0 && !(_0 >= _1)); + } + + + mod arith { + use super::*; + use super::super::*; + + + #[test] + fn test_add() { + assert_eq!(_1 + _1_2, _3_2); + assert_eq!(_1 + _1, _2); + assert_eq!(_1_2 + _3_2, _2); + assert_eq!(_1_2 + _neg1_2, _0); + } + + #[test] + fn test_sub() { + assert_eq!(_1 - _1_2, _1_2); + assert_eq!(_3_2 - _1_2, _1); + assert_eq!(_1 - _neg1_2, _3_2); + } + + #[test] + fn test_mul() { + assert_eq!(_1 * _1_2, _1_2); + assert_eq!(_1_2 * _3_2, Ratio::new(3,4)); + assert_eq!(_1_2 * _neg1_2, Ratio::new(-1, 4)); + } + + #[test] + fn test_div() { + assert_eq!(_1 / _1_2, _2); + assert_eq!(_3_2 / _1_2, _1 + _2); + assert_eq!(_1 / _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2); + } + + #[test] + fn test_modulo() { + assert_eq!(_3_2 % _1, _1_2); + assert_eq!(_2 % _neg1_2, _0); + assert_eq!(_1_2 % _2, _1_2); + } + + #[test] + fn test_neg() { + assert_eq!(-_0, _0); + assert_eq!(-_1_2, _neg1_2); + assert_eq!(-(-_1), _1); + } + #[test] + fn test_zero() { + assert_eq!(_0 + _0, _0); + assert_eq!(_0 * _0, _0); + assert_eq!(_0 * _1, _0); + assert_eq!(_0 / _neg1_2, _0); + assert_eq!(_0 - _0, _0); + } + #[test] + #[should_fail] + fn test_div_0() { + let _a = _1 / _0; + } + } + + #[test] + fn test_round() { + assert_eq!(_1_2.ceil(), _1); + assert_eq!(_1_2.floor(), _0); + assert_eq!(_1_2.round(num::RoundToZero), _0); + assert_eq!(_1_2.round(num::RoundFromZero), _1); + + assert_eq!(_neg1_2.ceil(), _0); + assert_eq!(_neg1_2.floor(), -_1); + assert_eq!(_neg1_2.round(num::RoundToZero), _0); + assert_eq!(_neg1_2.round(num::RoundFromZero), -_1); + + assert_eq!(_1.ceil(), _1); + assert_eq!(_1.floor(), _1); + assert_eq!(_1.round(num::RoundToZero), _1); + assert_eq!(_1.round(num::RoundFromZero), _1); + } + + #[test] + fn test_fract() { + assert_eq!(_1.fract(), _0); + assert_eq!(_neg1_2.fract(), _neg1_2); + assert_eq!(_1_2.fract(), _1_2); + assert_eq!(_3_2.fract(), _1_2); + } + + #[test] + fn test_to_from_str() { + fn test(r: Rational, s: ~str) { + assert_eq!(FromStr::from_str(s), Some(r)); + assert_eq!(r.to_str(), s); + } + test(_1, ~"1/1"); + test(_0, ~"0/1"); + test(_1_2, ~"1/2"); + test(_3_2, ~"3/2"); + test(_2, ~"2/1"); + test(_neg1_2, ~"-1/2"); + } + #[test] + fn test_from_str_fail() { + fn test(s: &str) { + assert_eq!(FromStr::from_str::(s), None); + } + + for ["0 /1", "abc", "", "1/", "--1/2","3/2/1"].each |&s| { + test(s); + } + } + + #[test] + fn test_to_from_str_radix() { + fn test(r: Rational, s: ~str, n: uint) { + assert_eq!(FromStrRadix::from_str_radix(s, n), Some(r)); + assert_eq!(r.to_str_radix(n), s); + } + fn test3(r: Rational, s: ~str) { test(r, s, 3) } + fn test16(r: Rational, s: ~str) { test(r, s, 16) } + + test3(_1, ~"1/1"); + test3(_0, ~"0/1"); + test3(_1_2, ~"1/2"); + test3(_3_2, ~"10/2"); + test3(_2, ~"2/1"); + test3(_neg1_2, ~"-1/2"); + test3(_neg1_2 / _2, ~"-1/11"); + + test16(_1, ~"1/1"); + test16(_0, ~"0/1"); + test16(_1_2, ~"1/2"); + test16(_3_2, ~"3/2"); + test16(_2, ~"2/1"); + test16(_neg1_2, ~"-1/2"); + test16(_neg1_2 / _2, ~"-1/4"); + test16(Ratio::new(13,15), ~"d/f"); + test16(_1_2*_1_2*_1_2*_1_2, ~"1/10"); + } + + #[test] + fn test_from_str_radix_fail() { + fn test(s: &str) { + assert_eq!(FromStrRadix::from_str_radix::(s, 3), None); + } + + for ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"].each |&s| { + test(s); + } + } +} \ No newline at end of file diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index dd56e41359582..c8d250f90f6c4 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -50,13 +50,29 @@ impl Mutable for PriorityQueue { pub impl PriorityQueue { /// Returns the greatest item in the queue - fails if empty + #[cfg(stage0)] fn top(&self) -> &'self T { &self.data[0] } + /// Returns the greatest item in the queue - fails if empty + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn top<'a>(&'a self) -> &'a T { &self.data[0] } + /// Returns the greatest item in the queue - None if empty + #[cfg(stage0)] fn maybe_top(&self) -> Option<&'self T> { if self.is_empty() { None } else { Some(self.top()) } } + /// Returns the greatest item in the queue - None if empty + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn maybe_top<'a>(&'a self) -> Option<&'a T> { + if self.is_empty() { None } else { Some(self.top()) } + } + /// Returns the number of elements the queue can hold without reallocating fn capacity(&self) -> uint { vec::capacity(&self.data) } diff --git a/src/libstd/rl.rs b/src/libstd/rl.rs index a8b25767ce595..9f9f2323d271b 100644 --- a/src/libstd/rl.rs +++ b/src/libstd/rl.rs @@ -59,12 +59,10 @@ pub unsafe fn load_history(file: ~str) -> bool { /// Print out a prompt and then wait for input and return it pub unsafe fn read(prompt: ~str) -> Option<~str> { do str::as_c_str(prompt) |buf| { - unsafe { - let line = rustrt::linenoise(buf); + let line = rustrt::linenoise(buf); - if line.is_null() { None } - else { Some(str::raw::from_c_str(line)) } - } + if line.is_null() { None } + else { Some(str::raw::from_c_str(line)) } } } @@ -74,22 +72,20 @@ fn complete_key(_v: @CompletionCb) {} /// Bind to the main completion callback pub unsafe fn complete(cb: CompletionCb) { - unsafe { - task::local_data::local_data_set(complete_key, @(cb)); - - extern fn callback(line: *c_char, completions: *()) { - unsafe { - let cb = *task::local_data::local_data_get(complete_key) - .get(); - - do cb(str::raw::from_c_str(line)) |suggestion| { - do str::as_c_str(suggestion) |buf| { - rustrt::linenoiseAddCompletion(completions, buf); - } + task::local_data::local_data_set(complete_key, @(cb)); + + extern fn callback(line: *c_char, completions: *()) { + unsafe { + let cb = *task::local_data::local_data_get(complete_key) + .get(); + + do cb(str::raw::from_c_str(line)) |suggestion| { + do str::as_c_str(suggestion) |buf| { + rustrt::linenoiseAddCompletion(completions, buf); } } } - - rustrt::linenoiseSetCompletionCallback(callback); } + + rustrt::linenoiseSetCompletionCallback(callback); } diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs index 61f50069d8997..653283f2e78b9 100644 --- a/src/libstd/rope.rs +++ b/src/libstd/rope.rs @@ -455,7 +455,7 @@ pub mod iterator { node::Content(x) => return node::leaf_iterator::start(x) } } - pub fn next(it: &node::leaf_iterator::T) -> Option { + pub fn next(it: &mut node::leaf_iterator::T) -> Option { return node::leaf_iterator::next(it); } } @@ -470,7 +470,7 @@ pub mod iterator { node::Content(x) => return node::char_iterator::start(x) } } - pub fn next(it: &node::char_iterator::T) -> Option { + pub fn next(it: &mut node::char_iterator::T) -> Option { return node::char_iterator::next(it) } } @@ -832,9 +832,9 @@ pub mod node { unsafe { let mut buf = vec::from_elem(byte_len(node), 0); let mut offset = 0u;//Current position in the buffer - let it = leaf_iterator::start(node); + let mut it = leaf_iterator::start(node); loop { - match (leaf_iterator::next(&it)) { + match leaf_iterator::next(&mut it) { option::None => break, option::Some(x) => { //FIXME (#2744): Replace with memcpy or something similar @@ -862,17 +862,15 @@ pub mod node { * This function executes in linear time. */ pub fn flatten(node: @Node) -> @Node { - unsafe { - match (*node) { - Leaf(_) => node, - Concat(ref x) => { - @Leaf(Leaf { - byte_offset: 0u, - byte_len: x.byte_len, - char_len: x.char_len, - content: @serialize_node(node), - }) - } + match (*node) { + Leaf(_) => node, + Concat(ref x) => { + @Leaf(Leaf { + byte_offset: 0u, + byte_len: x.byte_len, + char_len: x.char_len, + content: @serialize_node(node), + }) } } } @@ -896,9 +894,9 @@ pub mod node { if height(node) < hint_max_node_height { return option::None; } //1. Gather all leaves as a forest let mut forest = ~[]; - let it = leaf_iterator::start(node); + let mut it = leaf_iterator::start(node); loop { - match (leaf_iterator::next(&it)) { + match leaf_iterator::next(&mut it) { option::None => break, option::Some(x) => forest.push(@Leaf(x)) } @@ -1058,11 +1056,12 @@ pub mod node { } pub fn cmp(a: @Node, b: @Node) -> int { - let ita = char_iterator::start(a); - let itb = char_iterator::start(b); + let mut ita = char_iterator::start(a); + let mut itb = char_iterator::start(b); let mut result = 0; while result == 0 { - match ((char_iterator::next(&ita), char_iterator::next(&itb))) { + match (char_iterator::next(&mut ita), char_iterator::next(&mut itb)) + { (option::None, option::None) => break, (option::Some(chara), option::Some(charb)) => { result = char::cmp(chara, charb); @@ -1131,9 +1130,7 @@ pub mod node { * proportional to the height of the rope + the (bounded) * length of the largest leaf. */ - pub fn char_at(node: @Node, pos: uint) -> char { - let mut node = node; - let mut pos = pos; + pub fn char_at(mut node: @Node, mut pos: uint) -> char { loop { match *node { Leaf(x) => return str::char_at(*x.content, pos), @@ -1154,8 +1151,8 @@ pub mod node { use core::vec; pub struct T { - mut stack: ~[@Node], - mut stackpos: int, + stack: ~[@Node], + stackpos: int, } pub fn empty() -> T { @@ -1171,7 +1168,7 @@ pub mod node { } } - pub fn next(it: &T) -> Option { + pub fn next(it: &mut T) -> Option { if it.stackpos < 0 { return option::None; } loop { let current = it.stack[it.stackpos]; @@ -1199,8 +1196,8 @@ pub mod node { pub struct T { leaf_iterator: leaf_iterator::T, - mut leaf: Option, - mut leaf_byte_pos: uint, + leaf: Option, + leaf_byte_pos: uint, } pub fn start(node: @Node) -> T { @@ -1219,13 +1216,13 @@ pub mod node { } } - pub fn next(it: &T) -> Option { + pub fn next(it: &mut T) -> Option { loop { - match (get_current_or_next_leaf(it)) { + match get_current_or_next_leaf(it) { option::None => return option::None, option::Some(_) => { let next_char = get_next_char_in_leaf(it); - match (next_char) { + match next_char { option::None => loop, option::Some(_) => return next_char } @@ -1234,16 +1231,16 @@ pub mod node { }; } - pub fn get_current_or_next_leaf(it: &T) -> Option { - match ((*it).leaf) { - option::Some(_) => return (*it).leaf, + pub fn get_current_or_next_leaf(it: &mut T) -> Option { + match it.leaf { + option::Some(_) => return it.leaf, option::None => { - let next = leaf_iterator::next(&((*it).leaf_iterator)); - match (next) { + let next = leaf_iterator::next(&mut it.leaf_iterator); + match next { option::None => return option::None, option::Some(_) => { - (*it).leaf = next; - (*it).leaf_byte_pos = 0u; + it.leaf = next; + it.leaf_byte_pos = 0u; return next; } } @@ -1251,13 +1248,13 @@ pub mod node { } } - pub fn get_next_char_in_leaf(it: &T) -> Option { - match copy (*it).leaf { + pub fn get_next_char_in_leaf(it: &mut T) -> Option { + match copy it.leaf { option::None => return option::None, option::Some(aleaf) => { - if (*it).leaf_byte_pos >= aleaf.byte_len { + if it.leaf_byte_pos >= aleaf.byte_len { //We are actually past the end of the leaf - (*it).leaf = option::None; + it.leaf = option::None; return option::None } else { let range = @@ -1342,11 +1339,11 @@ mod tests { assert!(rope_to_string(r) == *sample); let mut string_iter = 0u; - let string_len = str::len(*sample); - let rope_iter = iterator::char::start(r); - let mut equal = true; + let string_len = str::len(*sample); + let mut rope_iter = iterator::char::start(r); + let mut equal = true; while equal { - match (node::char_iterator::next(&rope_iter)) { + match (node::char_iterator::next(&mut rope_iter)) { option::None => { if string_iter < string_len { equal = false; @@ -1376,9 +1373,9 @@ mod tests { let r = of_str(sample); let mut len = 0u; - let it = iterator::char::start(r); + let mut it = iterator::char::start(r); loop { - match (node::char_iterator::next(&it)) { + match (node::char_iterator::next(&mut it)) { option::None => break, option::Some(_) => len += 1u } diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index ddc84e07a3584..e4e53b9b61486 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -17,10 +17,13 @@ Core encoding and decoding interfaces. #[forbid(non_camel_case_types)]; use core::prelude::*; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::trie::{TrieMap, TrieSet}; use deque::Deque; use dlist::DList; +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] use treemap::{TreeMap, TreeSet}; pub trait Encoder { @@ -44,22 +47,36 @@ pub trait Encoder { fn emit_str(&self, v: &str); // Compound types: - fn emit_enum(&self, name: &str, f: &fn()); - fn emit_enum_variant(&self, v_name: &str, v_id: uint, sz: uint, f: &fn()); - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()); - fn emit_seq(&self, len: uint, f: &fn()); - fn emit_seq_elt(&self, idx: uint, f: &fn()); + fn emit_enum_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); + fn emit_enum_variant_arg(&self, a_idx: uint, f: &fn()); - fn emit_struct(&self, name: &str, _len: uint, f: &fn()); + fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); + fn emit_enum_struct_variant_field(&self, f_name: &str, f_idx: uint, f: &fn()); + + fn emit_struct(&self, name: &str, len: uint, f: &fn()); + #[cfg(stage0)] fn emit_field(&self, f_name: &str, f_idx: uint, f: &fn()); + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn emit_struct_field(&self, f_name: &str, f_idx: uint, f: &fn()); + + fn emit_tuple(&self, len: uint, f: &fn()); + fn emit_tuple_arg(&self, idx: uint, f: &fn()); + + fn emit_tuple_struct(&self, name: &str, len: uint, f: &fn()); + fn emit_tuple_struct_arg(&self, f_idx: uint, f: &fn()); // Specialized types: fn emit_option(&self, f: &fn()); fn emit_option_none(&self); fn emit_option_some(&self, f: &fn()); + fn emit_seq(&self, len: uint, f: &fn()); + fn emit_seq_elt(&self, idx: uint, f: &fn()); + fn emit_map(&self, len: uint, f: &fn()); fn emit_map_elt_key(&self, idx: uint, f: &fn()); fn emit_map_elt_val(&self, idx: uint, f: &fn()); @@ -87,18 +104,33 @@ pub trait Decoder { // Compound types: fn read_enum(&self, name: &str, f: &fn() -> T) -> T; + fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; - fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T; + fn read_enum_variant_arg(&self, a_idx: uint, f: &fn() -> T) -> T; - fn read_seq(&self, f: &fn(uint) -> T) -> T; - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T; + fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; + fn read_enum_struct_variant_field(&self, &f_name: &str, f_idx: uint, f: &fn() -> T) -> T; + + fn read_struct(&self, s_name: &str, len: uint, f: &fn() -> T) -> T; + #[cfg(stage0)] + fn read_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; - fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T; - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T; + fn read_tuple(&self, f: &fn(uint) -> T) -> T; + fn read_tuple_arg(&self, a_idx: uint, f: &fn() -> T) -> T; + + fn read_tuple_struct(&self, s_name: &str, f: &fn(uint) -> T) -> T; + fn read_tuple_struct_arg(&self, a_idx: uint, f: &fn() -> T) -> T; // Specialized types: fn read_option(&self, f: &fn(bool) -> T) -> T; + fn read_seq(&self, f: &fn(uint) -> T) -> T; + fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T; + fn read_map(&self, f: &fn(uint) -> T) -> T; fn read_map_elt_key(&self, idx: uint, f: &fn() -> T) -> T; fn read_map_elt_val(&self, idx: uint, f: &fn() -> T) -> T; @@ -591,11 +623,11 @@ impl< E: Encoder, K: Encodable + Hash + IterBytes + Eq, V: Encodable -> Encodable for LinearMap { +> Encodable for HashMap { fn encode(&self, e: &E) { do e.emit_map(self.len()) { let mut i = 0; - for self.each |&(key, val)| { + for self.each |key, val| { e.emit_map_elt_key(i, || key.encode(e)); e.emit_map_elt_val(i, || val.encode(e)); i += 1; @@ -608,10 +640,10 @@ impl< D: Decoder, K: Decodable + Hash + IterBytes + Eq, V: Decodable -> Decodable for LinearMap { - fn decode(d: &D) -> LinearMap { +> Decodable for HashMap { + fn decode(d: &D) -> HashMap { do d.read_map |len| { - let mut map = LinearMap::with_capacity(len); + let mut map = HashMap::with_capacity(len); for uint::range(0, len) |i| { let key = d.read_map_elt_key(i, || Decodable::decode(d)); let val = d.read_map_elt_val(i, || Decodable::decode(d)); @@ -625,7 +657,7 @@ impl< impl< S: Encoder, T: Encodable + Hash + IterBytes + Eq -> Encodable for LinearSet { +> Encodable for HashSet { fn encode(&self, s: &S) { do s.emit_seq(self.len()) { let mut i = 0; @@ -640,10 +672,10 @@ impl< impl< D: Decoder, T: Decodable + Hash + IterBytes + Eq -> Decodable for LinearSet { - fn decode(d: &D) -> LinearSet { +> Decodable for HashSet { + fn decode(d: &D) -> HashSet { do d.read_seq |len| { - let mut set = LinearSet::with_capacity(len); + let mut set = HashSet::with_capacity(len); for uint::range(0, len) |i| { set.insert(d.read_seq_elt(i, || Decodable::decode(d))); } @@ -659,7 +691,7 @@ impl< fn encode(&self, e: &E) { do e.emit_map(self.len()) { let mut i = 0; - for self.each |&(key, val)| { + for self.each |key, val| { e.emit_map_elt_key(i, || key.encode(e)); e.emit_map_elt_val(i, || val.encode(e)); i += 1; @@ -709,6 +741,9 @@ impl Decodable for TrieSet { } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] impl< E: Encoder, K: Encodable + Eq + TotalOrd, @@ -717,7 +752,7 @@ impl< fn encode(&self, e: &E) { do e.emit_map(self.len()) { let mut i = 0; - for self.each |&(key, val)| { + for self.each |key, val| { e.emit_map_elt_key(i, || key.encode(e)); e.emit_map_elt_val(i, || val.encode(e)); i += 1; @@ -726,6 +761,9 @@ impl< } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] impl< D: Decoder, K: Decodable + Eq + TotalOrd, @@ -744,6 +782,9 @@ impl< } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] impl< S: Encoder, T: Encodable + Eq + TotalOrd @@ -759,6 +800,9 @@ impl< } } +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] impl< D: Decoder, T: Decodable + Eq + TotalOrd diff --git a/src/libstd/sha1.rs b/src/libstd/sha1.rs index 1a2d4a87d9886..6aa4d1c54bc9e 100644 --- a/src/libstd/sha1.rs +++ b/src/libstd/sha1.rs @@ -282,135 +282,133 @@ mod tests { use core::vec; #[test] - pub fn test() { - unsafe { - struct Test { - input: ~str, - output: ~[u8], - output_str: ~str, - } + fn test() { + struct Test { + input: ~str, + output: ~[u8], + output_str: ~str, + } - fn a_million_letter_a() -> ~str { - let mut i = 0; - let mut rs = ~""; - while i < 100000 { - str::push_str(&mut rs, ~"aaaaaaaaaa"); - i += 1; - } - return rs; + fn a_million_letter_a() -> ~str { + let mut i = 0; + let mut rs = ~""; + while i < 100000 { + str::push_str(&mut rs, ~"aaaaaaaaaa"); + i += 1; } - // Test messages from FIPS 180-1 + return rs; + } + // Test messages from FIPS 180-1 - let fips_180_1_tests = ~[ - Test { - input: ~"abc", - output: ~[ - 0xA9u8, 0x99u8, 0x3Eu8, 0x36u8, - 0x47u8, 0x06u8, 0x81u8, 0x6Au8, - 0xBAu8, 0x3Eu8, 0x25u8, 0x71u8, - 0x78u8, 0x50u8, 0xC2u8, 0x6Cu8, - 0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8, - ], - output_str: ~"a9993e364706816aba3e25717850c26c9cd0d89d" - }, - Test { - input: - ~"abcdbcdecdefdefgefghfghighij" + - ~"hijkijkljklmklmnlmnomnopnopq", - output: ~[ - 0x84u8, 0x98u8, 0x3Eu8, 0x44u8, - 0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8, - 0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8, - 0xF9u8, 0x51u8, 0x29u8, 0xE5u8, - 0xE5u8, 0x46u8, 0x70u8, 0xF1u8, - ], - output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1" - }, - Test { - input: a_million_letter_a(), - output: ~[ - 0x34u8, 0xAAu8, 0x97u8, 0x3Cu8, - 0xD4u8, 0xC4u8, 0xDAu8, 0xA4u8, - 0xF6u8, 0x1Eu8, 0xEBu8, 0x2Bu8, - 0xDBu8, 0xADu8, 0x27u8, 0x31u8, - 0x65u8, 0x34u8, 0x01u8, 0x6Fu8, - ], - output_str: ~"34aa973cd4c4daa4f61eeb2bdbad27316534016f" - }, - ]; - // Examples from wikipedia + let fips_180_1_tests = ~[ + Test { + input: ~"abc", + output: ~[ + 0xA9u8, 0x99u8, 0x3Eu8, 0x36u8, + 0x47u8, 0x06u8, 0x81u8, 0x6Au8, + 0xBAu8, 0x3Eu8, 0x25u8, 0x71u8, + 0x78u8, 0x50u8, 0xC2u8, 0x6Cu8, + 0x9Cu8, 0xD0u8, 0xD8u8, 0x9Du8, + ], + output_str: ~"a9993e364706816aba3e25717850c26c9cd0d89d" + }, + Test { + input: + ~"abcdbcdecdefdefgefghfghighij" + + ~"hijkijkljklmklmnlmnomnopnopq", + output: ~[ + 0x84u8, 0x98u8, 0x3Eu8, 0x44u8, + 0x1Cu8, 0x3Bu8, 0xD2u8, 0x6Eu8, + 0xBAu8, 0xAEu8, 0x4Au8, 0xA1u8, + 0xF9u8, 0x51u8, 0x29u8, 0xE5u8, + 0xE5u8, 0x46u8, 0x70u8, 0xF1u8, + ], + output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1" + }, + Test { + input: a_million_letter_a(), + output: ~[ + 0x34u8, 0xAAu8, 0x97u8, 0x3Cu8, + 0xD4u8, 0xC4u8, 0xDAu8, 0xA4u8, + 0xF6u8, 0x1Eu8, 0xEBu8, 0x2Bu8, + 0xDBu8, 0xADu8, 0x27u8, 0x31u8, + 0x65u8, 0x34u8, 0x01u8, 0x6Fu8, + ], + output_str: ~"34aa973cd4c4daa4f61eeb2bdbad27316534016f" + }, + ]; + // Examples from wikipedia - let wikipedia_tests = ~[ - Test { - input: ~"The quick brown fox jumps over the lazy dog", - output: ~[ - 0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8, - 0x7au8, 0x2du8, 0x28u8, 0xfcu8, - 0xedu8, 0x84u8, 0x9eu8, 0xe1u8, - 0xbbu8, 0x76u8, 0xe7u8, 0x39u8, - 0x1bu8, 0x93u8, 0xebu8, 0x12u8, - ], - output_str: ~"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", - }, - Test { - input: ~"The quick brown fox jumps over the lazy cog", - output: ~[ - 0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8, - 0xd2u8, 0x5eu8, 0x1bu8, 0x3au8, - 0xfau8, 0xd3u8, 0xe8u8, 0x5au8, - 0x0bu8, 0xd1u8, 0x7du8, 0x9bu8, - 0x10u8, 0x0du8, 0xb4u8, 0xb3u8, - ], - output_str: ~"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3", - }, - ]; - let tests = fips_180_1_tests + wikipedia_tests; - fn check_vec_eq(v0: ~[u8], v1: ~[u8]) { - assert!((vec::len::(v0) == vec::len::(v1))); - let len = vec::len::(v0); - let mut i = 0u; - while i < len { - let a = v0[i]; - let b = v1[i]; - assert!((a == b)); - i += 1u; - } + let wikipedia_tests = ~[ + Test { + input: ~"The quick brown fox jumps over the lazy dog", + output: ~[ + 0x2fu8, 0xd4u8, 0xe1u8, 0xc6u8, + 0x7au8, 0x2du8, 0x28u8, 0xfcu8, + 0xedu8, 0x84u8, 0x9eu8, 0xe1u8, + 0xbbu8, 0x76u8, 0xe7u8, 0x39u8, + 0x1bu8, 0x93u8, 0xebu8, 0x12u8, + ], + output_str: ~"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + }, + Test { + input: ~"The quick brown fox jumps over the lazy cog", + output: ~[ + 0xdeu8, 0x9fu8, 0x2cu8, 0x7fu8, + 0xd2u8, 0x5eu8, 0x1bu8, 0x3au8, + 0xfau8, 0xd3u8, 0xe8u8, 0x5au8, + 0x0bu8, 0xd1u8, 0x7du8, 0x9bu8, + 0x10u8, 0x0du8, 0xb4u8, 0xb3u8, + ], + output_str: ~"de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3", + }, + ]; + let tests = fips_180_1_tests + wikipedia_tests; + fn check_vec_eq(v0: ~[u8], v1: ~[u8]) { + assert!((vec::len::(v0) == vec::len::(v1))); + let len = vec::len::(v0); + let mut i = 0u; + while i < len { + let a = v0[i]; + let b = v1[i]; + assert!((a == b)); + i += 1u; } - // Test that it works when accepting the message all at once + } + // Test that it works when accepting the message all at once - let mut sh = sha1::sha1(); - for vec::each(tests) |t| { - sh.input_str(t.input); - let out = sh.result(); - check_vec_eq(t.output, out); + let mut sh = sha1::sha1(); + for vec::each(tests) |t| { + sh.input_str(t.input); + let out = sh.result(); + check_vec_eq(t.output, out); - let out_str = sh.result_str(); - assert!((out_str.len() == 40)); - assert!((out_str == t.output_str)); + let out_str = sh.result_str(); + assert!((out_str.len() == 40)); + assert!((out_str == t.output_str)); - sh.reset(); - } + sh.reset(); + } - // Test that it works when accepting the message in pieces - for vec::each(tests) |t| { - let len = str::len(t.input); - let mut left = len; - while left > 0u { - let take = (left + 1u) / 2u; - sh.input_str(str::slice(t.input, len - left, - take + len - left).to_owned()); - left = left - take; - } - let out = sh.result(); - check_vec_eq(t.output, out); + // Test that it works when accepting the message in pieces + for vec::each(tests) |t| { + let len = str::len(t.input); + let mut left = len; + while left > 0u { + let take = (left + 1u) / 2u; + sh.input_str(str::slice(t.input, len - left, + take + len - left).to_owned()); + left = left - take; + } + let out = sh.result(); + check_vec_eq(t.output, out); - let out_str = sh.result_str(); - assert!((out_str.len() == 40)); - assert!((out_str == t.output_str)); + let out_str = sh.result_str(); + assert!((out_str.len() == 40)); + assert!((out_str == t.output_str)); - sh.reset(); - } + sh.reset(); } } } diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index b6c5ec03068cd..d50804ba47b59 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -14,7 +14,7 @@ */ use core::container::{Container, Mutable, Map, Set}; -use core::iter::{BaseIter, ReverseIter}; +use core::iter::{BaseIter}; use core::option::{Some, None}; use core::prelude::*; @@ -22,32 +22,6 @@ pub struct SmallIntMap { priv v: ~[Option], } -impl<'self, V> BaseIter<(uint, &'self V)> for SmallIntMap { - /// Visit all key-value pairs in order - fn each(&self, it: &fn(&(uint, &'self V)) -> bool) { - for uint::range(0, self.v.len()) |i| { - match self.v[i] { - Some(ref elt) => if !it(&(i, elt)) { break }, - None => () - } - } - } - - fn size_hint(&self) -> Option { Some(self.len()) } -} - -impl<'self, V> ReverseIter<(uint, &'self V)> for SmallIntMap { - /// Visit all key-value pairs in reverse order - fn each_reverse(&self, it: &fn(&(uint, &'self V)) -> bool) { - for uint::range_rev(self.v.len(), 0) |i| { - match self.v[i - 1] { - Some(ref elt) => if !it(&(i - 1, elt)) { break }, - None => () - } - } - } -} - impl Container for SmallIntMap { /// Return the number of elements in the map fn len(&const self) -> uint { @@ -76,18 +50,51 @@ impl Map for SmallIntMap { self.find(key).is_some() } + /// Visit all key-value pairs in order + #[cfg(stage0)] + fn each(&self, it: &fn(&uint, &'self V) -> bool) { + for uint::range(0, self.v.len()) |i| { + match self.v[i] { + Some(ref elt) => if !it(&i, elt) { break }, + None => () + } + } + } + + /// Visit all key-value pairs in order + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) { + for uint::range(0, self.v.len()) |i| { + match self.v[i] { + Some(ref elt) => if !it(&i, elt) { break }, + None => () + } + } + } + /// Visit all keys in order fn each_key(&self, blk: &fn(key: &uint) -> bool) { - self.each(|&(k, _)| blk(&k)) + self.each(|k, _| blk(k)) } /// Visit all values in order + #[cfg(stage0)] fn each_value(&self, blk: &fn(value: &V) -> bool) { - self.each(|&(_, v)| blk(v)) + self.each(|_, v| blk(v)) + } + + /// Visit all values in order + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) { + self.each(|_, v| blk(v)) } /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, it: &fn(&uint, &'self mut V) -> bool) { + fn mutate_values(&mut self, it: &fn(&uint, &mut V) -> bool) { for uint::range(0, self.v.len()) |i| { match self.v[i] { Some(ref mut elt) => if !it(&i, elt) { break }, @@ -97,6 +104,7 @@ impl Map for SmallIntMap { } /// Return a reference to the value corresponding to the key + #[cfg(stage0)] fn find(&self, key: &uint) -> Option<&'self V> { if *key < self.v.len() { match self.v[*key] { @@ -108,7 +116,23 @@ impl Map for SmallIntMap { } } + /// Return a reference to the value corresponding to the key + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn find<'a>(&'a self, key: &uint) -> Option<&'a V> { + if *key < self.v.len() { + match self.v[*key] { + Some(ref value) => Some(value), + None => None + } + } else { + None + } + } + /// Return a mutable reference to the value corresponding to the key + #[cfg(stage0)] fn find_mut(&mut self, key: &uint) -> Option<&'self mut V> { if *key < self.v.len() { match self.v[*key] { @@ -120,6 +144,21 @@ impl Map for SmallIntMap { } } + /// Return a mutable reference to the value corresponding to the key + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut V> { + if *key < self.v.len() { + match self.v[*key] { + Some(ref mut value) => Some(value), + None => None + } + } else { + None + } + } + /// Insert a key-value pair into the map. An existing value for a /// key is replaced by the new value. Return true if the key did /// not already exist in the map. @@ -149,9 +188,41 @@ pub impl SmallIntMap { /// Create an empty SmallIntMap fn new() -> SmallIntMap { SmallIntMap{v: ~[]} } + /// Visit all key-value pairs in reverse order + #[cfg(stage0)] + fn each_reverse(&self, it: &fn(uint, &'self V) -> bool) { + for uint::range_rev(self.v.len(), 0) |i| { + match self.v[i - 1] { + Some(ref elt) => if !it(i - 1, elt) { break }, + None => () + } + } + } + + /// Visit all key-value pairs in reverse order + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) { + for uint::range_rev(self.v.len(), 0) |i| { + match self.v[i - 1] { + Some(ref elt) => if !it(i - 1, elt) { break }, + None => () + } + } + } + + #[cfg(stage0)] fn get(&self, key: &uint) -> &'self V { self.find(key).expect("key not present") } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get<'a>(&'a self, key: &uint) -> &'a V { + self.find(key).expect("key not present") + } } pub impl SmallIntMap { diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index 40a1289517567..72a888fcc917b 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -27,7 +27,7 @@ type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool; pub fn merge_sort(v: &const [T], le: Le) -> ~[T] { type Slice = (uint, uint); - unsafe {return merge_sort_(v, (0u, len(v)), le);} + return merge_sort_(v, (0u, len(v)), le); fn merge_sort_(v: &const [T], slice: Slice, le: Le) -> ~[T] { @@ -68,14 +68,11 @@ fn part(arr: &mut [T], left: uint, let mut storage_index: uint = left; let mut i: uint = left; while i < right { - // XXX: Unsafe because borrow check doesn't handle this right - unsafe { - let a: &T = cast::transmute(&mut arr[i]); - let b: &T = cast::transmute(&mut arr[right]); - if compare_func(a, b) { - arr[i] <-> arr[storage_index]; - storage_index += 1; - } + let a: &mut T = &mut arr[i]; + let b: &mut T = &mut arr[right]; + if compare_func(a, b) { + arr[i] <-> arr[storage_index]; + storage_index += 1; } i += 1; } @@ -736,7 +733,7 @@ mod test_qsort3 { use core::vec; - pub fn check_sort(v1: &mut [int], v2: &mut [int]) { + fn check_sort(v1: &mut [int], v2: &mut [int]) { let len = vec::len::(v1); quick_sort3::(v1); let mut i = 0; @@ -748,7 +745,7 @@ mod test_qsort3 { } #[test] - pub fn test() { + fn test() { { let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; @@ -780,7 +777,7 @@ mod test_qsort { use core::int; use core::vec; - pub fn check_sort(v1: &mut [int], v2: &mut [int]) { + fn check_sort(v1: &mut [int], v2: &mut [int]) { let len = vec::len::(v1); fn leual(a: &int, b: &int) -> bool { *a <= *b } quick_sort::(v1, leual); @@ -793,7 +790,7 @@ mod test_qsort { } #[test] - pub fn test() { + fn test() { { let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; @@ -819,7 +816,7 @@ mod test_qsort { // Regression test for #750 #[test] - pub fn test_simple() { + fn test_simple() { let mut names = ~[2, 1, 3]; let expected = ~[1, 2, 3]; @@ -845,7 +842,7 @@ mod tests { use core::vec; - pub fn check_sort(v1: &[int], v2: &[int]) { + fn check_sort(v1: &[int], v2: &[int]) { let len = vec::len::(v1); pub fn le(a: &int, b: &int) -> bool { *a <= *b } let f = le; @@ -859,7 +856,7 @@ mod tests { } #[test] - pub fn test() { + fn test() { { let v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; let v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; @@ -876,7 +873,7 @@ mod tests { } #[test] - pub fn test_merge_sort_mutable() { + fn test_merge_sort_mutable() { pub fn le(a: &int, b: &int) -> bool { *a <= *b } let mut v1 = ~[3, 2, 1]; let v2 = merge_sort(v1, le); @@ -884,16 +881,13 @@ mod tests { } #[test] - pub fn test_merge_sort_stability() { + fn test_merge_sort_stability() { // tjc: funny that we have to use parens fn ile(x: &(&'static str), y: &(&'static str)) -> bool { - unsafe // to_lower is not pure... - { - let x = x.to_lower(); - let y = y.to_lower(); - x <= y - } + let x = x.to_lower(); + let y = y.to_lower(); + x <= y } let names1 = ~["joe bob", "Joe Bob", "Jack Brown", "JOE Bob", @@ -921,10 +915,8 @@ mod test_tim_sort { impl Ord for CVal { fn lt(&self, other: &CVal) -> bool { - unsafe { - let rng = rand::Rng(); - if rng.gen_float() > 0.995 { fail!(~"It's happening!!!"); } - } + let rng = rand::Rng(); + if rng.gen_float() > 0.995 { fail!(~"It's happening!!!"); } (*self).val < other.val } fn le(&self, other: &CVal) -> bool { (*self).val <= other.val } diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 89bdc750c2277..3dfc3200f0f52 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -18,7 +18,7 @@ not required in or otherwise suitable for the core library. */ #[link(name = "std", - vers = "0.6", + vers = "0.7-pre", uuid = "122bed0b-c19b-4b82-b0b7-7ae8aead7297", url = "https://github.com/mozilla/rust/tree/master/src/libstd")]; @@ -32,7 +32,7 @@ not required in or otherwise suitable for the core library. #[no_core]; -extern mod core(vers = "0.6"); +extern mod core(vers = "0.7-pre"); use core::prelude::*; pub mod uv_ll; @@ -76,6 +76,9 @@ pub mod rope; pub mod smallintmap; pub mod sort; pub mod dlist; +#[cfg(stage1)] +#[cfg(stage2)] +#[cfg(stage3)] pub mod treemap; // And ... other stuff @@ -95,9 +98,15 @@ pub mod cmp; pub mod base64; pub mod rl; pub mod workcache; +#[path="num/bigint.rs"] pub mod bigint; +#[path="num/rational.rs"] +pub mod rational; +#[path="num/complex.rs"] +pub mod complex; pub mod stats; pub mod semver; +pub mod fileinput; #[cfg(unicode)] mod unicode; diff --git a/src/libstd/sync.rs b/src/libstd/sync.rs index 99b3a122d9f70..971bb51f7e9f4 100644 --- a/src/libstd/sync.rs +++ b/src/libstd/sync.rs @@ -72,7 +72,7 @@ fn broadcast_waitqueue(q: &Waitqueue) -> uint { // The building-block used to make semaphores, mutexes, and rwlocks. #[doc(hidden)] struct SemInner { - mut count: int, + count: int, waiters: Waitqueue, // Can be either unit or another waitqueue. Some sems shouldn't come with // a condition variable attached, others should. @@ -101,17 +101,15 @@ fn new_sem_and_signal(count: int, num_condvars: uint) pub impl Sem { fn acquire(&self) { let mut waiter_nobe = None; - unsafe { - do (**self).with |state| { - state.count -= 1; - if state.count < 0 { - // Create waiter nobe. - let (WaitEnd, SignalEnd) = comm::oneshot(); - // Tell outer scope we need to block. - waiter_nobe = Some(WaitEnd); - // Enqueue ourself. - state.waiters.tail.send(SignalEnd); - } + do (**self).with |state| { + state.count -= 1; + if state.count < 0 { + // Create waiter nobe. + let (WaitEnd, SignalEnd) = comm::oneshot(); + // Tell outer scope we need to block. + waiter_nobe = Some(WaitEnd); + // Enqueue ourself. + state.waiters.tail.send(SignalEnd); } } // Uncomment if you wish to test for sem races. Not valgrind-friendly. @@ -122,12 +120,10 @@ pub impl Sem { } } fn release(&self) { - unsafe { - do (**self).with |state| { - state.count += 1; - if state.count <= 0 { - signal_waitqueue(&state.waiters); - } + do (**self).with |state| { + state.count += 1; + if state.count <= 0 { + signal_waitqueue(&state.waiters); } } } @@ -169,9 +165,7 @@ struct SemReleaseGeneric<'self, Q> { sem: &'self Sem } #[unsafe_destructor] impl<'self, Q:Owned> Drop for SemReleaseGeneric<'self, Q> { fn finalize(&self) { - unsafe { - self.sem.release(); - } + self.sem.release(); } } @@ -291,13 +285,11 @@ pub impl<'self> Condvar<'self> { fn signal_on(&self, condvar_id: uint) -> bool { let mut out_of_bounds = None; let mut result = false; - unsafe { - do (**self.sem).with |state| { - if condvar_id < vec::len(state.blocked) { - result = signal_waitqueue(&state.blocked[condvar_id]); - } else { - out_of_bounds = Some(vec::len(state.blocked)); - } + do (**self.sem).with |state| { + if condvar_id < vec::len(state.blocked) { + result = signal_waitqueue(&state.blocked[condvar_id]); + } else { + out_of_bounds = Some(vec::len(state.blocked)); } } do check_cvar_bounds(out_of_bounds, condvar_id, "cond.signal_on()") { @@ -312,17 +304,15 @@ pub impl<'self> Condvar<'self> { fn broadcast_on(&self, condvar_id: uint) -> uint { let mut out_of_bounds = None; let mut queue = None; - unsafe { - do (**self.sem).with |state| { - if condvar_id < vec::len(state.blocked) { - // To avoid :broadcast_heavy, we make a new waitqueue, - // swap it out with the old one, and broadcast on the - // old one outside of the little-lock. - queue = Some(util::replace(&mut state.blocked[condvar_id], - new_waitqueue())); - } else { - out_of_bounds = Some(vec::len(state.blocked)); - } + do (**self.sem).with |state| { + if condvar_id < vec::len(state.blocked) { + // To avoid :broadcast_heavy, we make a new waitqueue, + // swap it out with the old one, and broadcast on the + // old one outside of the little-lock. + queue = Some(util::replace(&mut state.blocked[condvar_id], + new_waitqueue())); + } else { + out_of_bounds = Some(vec::len(state.blocked)); } } do check_cvar_bounds(out_of_bounds, condvar_id, "cond.signal_on()") { @@ -729,7 +719,6 @@ mod tests { use core::cast; use core::cell::Cell; - use core::option; use core::ptr; use core::result; use core::task; @@ -739,19 +728,19 @@ mod tests { * Semaphore tests ************************************************************************/ #[test] - pub fn test_sem_acquire_release() { + fn test_sem_acquire_release() { let s = ~semaphore(1); s.acquire(); s.release(); s.acquire(); } #[test] - pub fn test_sem_basic() { + fn test_sem_basic() { let s = ~semaphore(1); do s.access { } } #[test] - pub fn test_sem_as_mutex() { + fn test_sem_as_mutex() { let s = ~semaphore(1); let s2 = ~s.clone(); do task::spawn || { @@ -764,7 +753,7 @@ mod tests { } } #[test] - pub fn test_sem_as_cvar() { + fn test_sem_as_cvar() { /* Child waits and parent signals */ let (p,c) = comm::stream(); let s = ~semaphore(0); @@ -790,7 +779,7 @@ mod tests { c.send(()); } #[test] - pub fn test_sem_multi_resource() { + fn test_sem_multi_resource() { // Parent and child both get in the critical section at the same // time, and shake hands. let s = ~semaphore(2); @@ -809,7 +798,7 @@ mod tests { } } #[test] - pub fn test_sem_runtime_friendly_blocking() { + fn test_sem_runtime_friendly_blocking() { // Force the runtime to schedule two threads on the same sched_loop. // When one blocks, it should schedule the other one. do task::spawn_sched(task::ManualThreads(1)) { @@ -834,7 +823,7 @@ mod tests { * Mutex tests ************************************************************************/ #[test] - pub fn test_mutex_lock() { + fn test_mutex_lock() { // Unsafely achieve shared state, and do the textbook // "load tmp = move ptr; inc tmp; store ptr <- tmp" dance. let (p,c) = comm::stream(); @@ -865,7 +854,7 @@ mod tests { } } #[test] - pub fn test_mutex_cond_wait() { + fn test_mutex_cond_wait() { let m = ~Mutex(); // Child wakes up parent @@ -897,7 +886,7 @@ mod tests { let _ = port.recv(); // Wait until child wakes up } #[cfg(test)] - pub fn test_mutex_cond_broadcast_helper(num_waiters: uint) { + fn test_mutex_cond_broadcast_helper(num_waiters: uint) { let m = ~Mutex(); let mut ports = ~[]; @@ -924,15 +913,15 @@ mod tests { for ports.each |port| { let _ = port.recv(); } } #[test] - pub fn test_mutex_cond_broadcast() { + fn test_mutex_cond_broadcast() { test_mutex_cond_broadcast_helper(12); } #[test] - pub fn test_mutex_cond_broadcast_none() { + fn test_mutex_cond_broadcast_none() { test_mutex_cond_broadcast_helper(0); } #[test] - pub fn test_mutex_cond_no_waiter() { + fn test_mutex_cond_no_waiter() { let m = ~Mutex(); let m2 = ~m.clone(); do task::try || { @@ -943,7 +932,7 @@ mod tests { } } #[test] #[ignore(cfg(windows))] - pub fn test_mutex_killed_simple() { + fn test_mutex_killed_simple() { // Mutex must get automatically unlocked if failed/killed within. let m = ~Mutex(); let m2 = ~m.clone(); @@ -958,7 +947,7 @@ mod tests { do m.lock { } } #[test] #[ignore(cfg(windows))] - pub fn test_mutex_killed_cond() { + fn test_mutex_killed_cond() { // Getting killed during cond wait must not corrupt the mutex while // unwinding (e.g. double unlock). let m = ~Mutex(); @@ -984,7 +973,7 @@ mod tests { } } #[test] #[ignore(cfg(windows))] - pub fn test_mutex_killed_broadcast() { + fn test_mutex_killed_broadcast() { let m = ~Mutex(); let m2 = ~m.clone(); let (p,c) = comm::stream(); @@ -1037,7 +1026,7 @@ mod tests { } } #[test] - pub fn test_mutex_cond_signal_on_0() { + fn test_mutex_cond_signal_on_0() { // Tests that signal_on(0) is equivalent to signal(). let m = ~Mutex(); do m.lock_cond |cond| { @@ -1051,7 +1040,7 @@ mod tests { } } #[test] #[ignore(cfg(windows))] - pub fn test_mutex_different_conds() { + fn test_mutex_different_conds() { let result = do task::try { let m = ~mutex_with_condvars(2); let m2 = ~m.clone(); @@ -1072,7 +1061,7 @@ mod tests { assert!(result.is_err()); } #[test] #[ignore(cfg(windows))] - pub fn test_mutex_no_condvars() { + fn test_mutex_no_condvars() { let result = do task::try { let m = ~mutex_with_condvars(0); do m.lock_cond |cond| { cond.wait(); } @@ -1095,7 +1084,7 @@ mod tests { #[cfg(test)] pub enum RWlockMode { Read, Write, Downgrade, DowngradeRead } #[cfg(test)] - pub fn lock_rwlock_in_mode(x: &RWlock, mode: RWlockMode, blk: &fn()) { + fn lock_rwlock_in_mode(x: &RWlock, mode: RWlockMode, blk: &fn()) { match mode { Read => x.read(blk), Write => x.write(blk), @@ -1111,7 +1100,7 @@ mod tests { } } #[cfg(test)] - pub fn test_rwlock_exclusion(x: ~RWlock, + fn test_rwlock_exclusion(x: ~RWlock, mode1: RWlockMode, mode2: RWlockMode) { // Test mutual exclusion between readers and writers. Just like the @@ -1143,21 +1132,21 @@ mod tests { } } #[test] - pub fn test_rwlock_readers_wont_modify_the_data() { + fn test_rwlock_readers_wont_modify_the_data() { test_rwlock_exclusion(~RWlock(), Read, Write); test_rwlock_exclusion(~RWlock(), Write, Read); test_rwlock_exclusion(~RWlock(), Read, Downgrade); test_rwlock_exclusion(~RWlock(), Downgrade, Read); } #[test] - pub fn test_rwlock_writers_and_writers() { + fn test_rwlock_writers_and_writers() { test_rwlock_exclusion(~RWlock(), Write, Write); test_rwlock_exclusion(~RWlock(), Write, Downgrade); test_rwlock_exclusion(~RWlock(), Downgrade, Write); test_rwlock_exclusion(~RWlock(), Downgrade, Downgrade); } #[cfg(test)] - pub fn test_rwlock_handshake(x: ~RWlock, + fn test_rwlock_handshake(x: ~RWlock, mode1: RWlockMode, mode2: RWlockMode, make_mode2_go_first: bool) { @@ -1189,7 +1178,7 @@ mod tests { } } #[test] - pub fn test_rwlock_readers_and_readers() { + fn test_rwlock_readers_and_readers() { test_rwlock_handshake(~RWlock(), Read, Read, false); // The downgrader needs to get in before the reader gets in, otherwise // they cannot end up reading at the same time. @@ -1198,7 +1187,7 @@ mod tests { // Two downgrade_reads can never both end up reading at the same time. } #[test] - pub fn test_rwlock_downgrade_unlock() { + fn test_rwlock_downgrade_unlock() { // Tests that downgrade can unlock the lock in both modes let x = ~RWlock(); do lock_rwlock_in_mode(x, Downgrade) { } @@ -1208,12 +1197,12 @@ mod tests { test_rwlock_exclusion(y, Write, Write); } #[test] - pub fn test_rwlock_read_recursive() { + fn test_rwlock_read_recursive() { let x = ~RWlock(); do x.read { do x.read { } } } #[test] - pub fn test_rwlock_cond_wait() { + fn test_rwlock_cond_wait() { // As test_mutex_cond_wait above. let x = ~RWlock(); @@ -1248,7 +1237,7 @@ mod tests { do x.read { } // Just for good measure } #[cfg(test)] - pub fn test_rwlock_cond_broadcast_helper(num_waiters: uint, + fn test_rwlock_cond_broadcast_helper(num_waiters: uint, dg1: bool, dg2: bool) { // Much like the mutex broadcast test. Downgrade-enabled. @@ -1287,7 +1276,7 @@ mod tests { for ports.each |port| { let _ = port.recv(); } } #[test] - pub fn test_rwlock_cond_broadcast() { + fn test_rwlock_cond_broadcast() { test_rwlock_cond_broadcast_helper(0, true, true); test_rwlock_cond_broadcast_helper(0, true, false); test_rwlock_cond_broadcast_helper(0, false, true); @@ -1298,7 +1287,7 @@ mod tests { test_rwlock_cond_broadcast_helper(12, false, false); } #[cfg(test)] #[ignore(cfg(windows))] - pub fn rwlock_kill_helper(mode1: RWlockMode, mode2: RWlockMode) { + fn rwlock_kill_helper(mode1: RWlockMode, mode2: RWlockMode) { // Mutex must get automatically unlocked if failed/killed within. let x = ~RWlock(); let x2 = (*x).clone(); @@ -1313,23 +1302,23 @@ mod tests { do lock_rwlock_in_mode(x, mode2) { } } #[test] #[ignore(cfg(windows))] - pub fn test_rwlock_reader_killed_writer() { + fn test_rwlock_reader_killed_writer() { rwlock_kill_helper(Read, Write); } #[test] #[ignore(cfg(windows))] - pub fn test_rwlock_writer_killed_reader() { + fn test_rwlock_writer_killed_reader() { rwlock_kill_helper(Write,Read ); } #[test] #[ignore(cfg(windows))] - pub fn test_rwlock_reader_killed_reader() { + fn test_rwlock_reader_killed_reader() { rwlock_kill_helper(Read, Read ); } #[test] #[ignore(cfg(windows))] - pub fn test_rwlock_writer_killed_writer() { + fn test_rwlock_writer_killed_writer() { rwlock_kill_helper(Write,Write); } #[test] #[ignore(cfg(windows))] - pub fn test_rwlock_kill_downgrader() { + fn test_rwlock_kill_downgrader() { rwlock_kill_helper(Downgrade, Read); rwlock_kill_helper(Read, Downgrade); rwlock_kill_helper(Downgrade, Write); @@ -1344,7 +1333,7 @@ mod tests { rwlock_kill_helper(Downgrade, DowngradeRead); } #[test] #[should_fail] #[ignore(cfg(windows))] - pub fn test_rwlock_downgrade_cant_swap() { + fn test_rwlock_downgrade_cant_swap() { // Tests that you can't downgrade with a different rwlock's token. let x = ~RWlock(); let y = ~RWlock(); diff --git a/src/libstd/task_pool.rs b/src/libstd/task_pool.rs index aed6721b78ea1..3f2772942a5cb 100644 --- a/src/libstd/task_pool.rs +++ b/src/libstd/task_pool.rs @@ -26,8 +26,7 @@ enum Msg { pub struct TaskPool { channels: ~[Chan>], - mut next_index: uint, - + next_index: uint, } #[unsafe_destructor] @@ -84,7 +83,7 @@ pub impl TaskPool { /// Executes the function `f` on a task in the pool. The function /// receives a reference to the local data returned by the `init_fn`. - fn execute(&self, f: ~fn(&T)) { + fn execute(&mut self, f: ~fn(&T)) { self.channels[self.next_index].send(Execute(f)); self.next_index += 1; if self.next_index == self.channels.len() { self.next_index = 0; } @@ -97,7 +96,7 @@ fn test_task_pool() { let g: ~fn(uint) -> uint = |i| i; g }; - let pool = TaskPool::new(4, Some(SingleThreaded), f); + let mut pool = TaskPool::new(4, Some(SingleThreaded), f); for 8.times { pool.execute(|i| io::println(fmt!("Hello from thread %u!", *i))); } diff --git a/src/libstd/test.rs b/src/libstd/test.rs index 7c5591d839e20..ee83a0c9bd652 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -201,19 +201,19 @@ struct ConsoleTestState { out: @io::Writer, log_out: Option<@io::Writer>, use_color: bool, - mut total: uint, - mut passed: uint, - mut failed: uint, - mut ignored: uint, - mut benchmarked: uint, - mut failures: ~[TestDesc] + total: uint, + passed: uint, + failed: uint, + ignored: uint, + benchmarked: uint, + failures: ~[TestDesc] } // A simple console test runner pub fn run_tests_console(opts: &TestOpts, tests: ~[TestDescAndFn]) -> bool { - fn callback(event: &TestEvent, st: @ConsoleTestState) { + fn callback(event: &TestEvent, st: &mut ConsoleTestState) { debug!("callback(event=%?)", event); match *event { TeFiltered(ref filtered_tests) => { @@ -268,16 +268,16 @@ pub fn run_tests_console(opts: &TestOpts, None => None }; - let st = @ConsoleTestState { + let st = @mut ConsoleTestState { out: io::stdout(), log_out: log_out, use_color: use_color(), - mut total: 0u, - mut passed: 0u, - mut failed: 0u, - mut ignored: 0u, - mut benchmarked: 0u, - mut failures: ~[] + total: 0u, + passed: 0u, + failed: 0u, + ignored: 0u, + benchmarked: 0u, + failures: ~[] }; run_tests(opts, tests, |x| callback(&x, st)); @@ -290,15 +290,18 @@ pub fn run_tests_console(opts: &TestOpts, print_failures(st); } - st.out.write_str(fmt!("\nresult: ")); - if success { - // There's no parallelism at this point so it's safe to use color - write_ok(st.out, true); - } else { - write_failed(st.out, true); + { + let st: &mut ConsoleTestState = st; + st.out.write_str(fmt!("\nresult: ")); + if success { + // There's no parallelism at this point so it's safe to use color + write_ok(st.out, true); + } else { + write_failed(st.out, true); + } + st.out.write_str(fmt!(". %u passed; %u failed; %u ignored\n\n", + st.passed, st.failed, st.ignored)); } - st.out.write_str(fmt!(". %u passed; %u failed; %u ignored\n\n", - st.passed, st.failed, st.ignored)); return success; @@ -356,7 +359,7 @@ pub fn run_tests_console(opts: &TestOpts, } } -fn print_failures(st: @ConsoleTestState) { +fn print_failures(st: &ConsoleTestState) { st.out.write_line(~"\nfailures:"); let mut failures = ~[]; for uint::range(0, vec::uniq_len(&const st.failures)) |i| { @@ -390,12 +393,12 @@ fn should_sort_failures_before_printing_them() { out: wr, log_out: option::None, use_color: false, - mut total: 0u, - mut passed: 0u, - mut failed: 0u, - mut ignored: 0u, - mut benchmarked: 0u, - mut failures: ~[test_b, test_a] + total: 0u, + passed: 0u, + failed: 0u, + ignored: 0u, + benchmarked: 0u, + failures: ~[test_b, test_a] }; print_failures(st); @@ -820,7 +823,7 @@ mod tests { #[test] #[ignore(cfg(windows))] - pub fn test_should_fail() { + fn test_should_fail() { fn f() { fail!(); } let desc = TestDescAndFn { desc: TestDesc { @@ -838,7 +841,7 @@ mod tests { } #[test] - pub fn test_should_fail_but_succeeds() { + fn test_should_fail_but_succeeds() { fn f() { } let desc = TestDescAndFn { desc: TestDesc { @@ -856,7 +859,7 @@ mod tests { } #[test] - pub fn first_free_arg_should_be_a_filter() { + fn first_free_arg_should_be_a_filter() { let args = ~[~"progname", ~"filter"]; let opts = match parse_opts(args) { either::Left(copy o) => o, @@ -866,7 +869,7 @@ mod tests { } #[test] - pub fn parse_ignored_flag() { + fn parse_ignored_flag() { let args = ~[~"progname", ~"filter", ~"--ignored"]; let opts = match parse_opts(args) { either::Left(copy o) => o, diff --git a/src/libstd/time.rs b/src/libstd/time.rs index 3af193e87486b..70dc4d8cfebbf 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -176,16 +176,12 @@ pub fn now() -> Tm { /// Parses the time from the string according to the format string. pub fn strptime(s: &str, format: &str) -> Result { - // unsafe only because do_strptime is annoying to make pure - // (it does IO with a str_reader) - unsafe {do_strptime(s, format)} + do_strptime(s, format) } /// Formats the time according to the format string. pub fn strftime(format: &str, tm: &Tm) -> ~str { - // unsafe only because do_strftime is annoying to make pure - // (it does IO with a str_reader) - unsafe { do_strftime(format, tm) } + do_strftime(format, tm) } pub impl Tm { @@ -876,7 +872,7 @@ mod tests { use core::str; use core::vec; - pub fn test_get_time() { + fn test_get_time() { static some_recent_date: i64 = 1325376000i64; // 2012-01-01T00:00:00Z static some_future_date: i64 = 1577836800i64; // 2020-01-01T00:00:00Z @@ -897,7 +893,7 @@ mod tests { } } - pub fn test_precise_time() { + fn test_precise_time() { let s0 = precise_time_s(); let ns1 = precise_time_ns(); @@ -914,7 +910,7 @@ mod tests { assert!(ns2 >= ns1); } - pub fn test_at_utc() { + fn test_at_utc() { os::setenv(~"TZ", ~"America/Los_Angeles"); tzset(); @@ -935,7 +931,7 @@ mod tests { assert!(utc.tm_nsec == 54321_i32); } - pub fn test_at() { + fn test_at() { os::setenv(~"TZ", ~"America/Los_Angeles"); tzset(); @@ -963,7 +959,7 @@ mod tests { assert!(local.tm_nsec == 54321_i32); } - pub fn test_to_timespec() { + fn test_to_timespec() { os::setenv(~"TZ", ~"America/Los_Angeles"); tzset(); @@ -974,7 +970,7 @@ mod tests { assert!(utc.to_local().to_timespec() == time); } - pub fn test_conversions() { + fn test_conversions() { os::setenv(~"TZ", ~"America/Los_Angeles"); tzset(); @@ -990,7 +986,7 @@ mod tests { assert!(utc.to_local().to_utc() == utc); } - pub fn test_strptime() { + fn test_strptime() { os::setenv(~"TZ", ~"America/Los_Angeles"); tzset(); @@ -1148,7 +1144,7 @@ mod tests { assert!(test(~"%", ~"%%")); } - pub fn test_ctime() { + fn test_ctime() { os::setenv(~"TZ", ~"America/Los_Angeles"); tzset(); @@ -1162,7 +1158,7 @@ mod tests { assert!(local.ctime() == ~"Fri Feb 13 15:31:30 2009"); } - pub fn test_strftime() { + fn test_strftime() { os::setenv(~"TZ", ~"America/Los_Angeles"); tzset(); @@ -1235,7 +1231,7 @@ mod tests { assert!(utc.rfc3339() == ~"2009-02-13T23:31:30Z"); } - pub fn test_timespec_eq_ord() { + fn test_timespec_eq_ord() { use core::cmp::{eq, ge, gt, le, lt, ne}; let a = &Timespec::new(-2, 1); @@ -1269,7 +1265,7 @@ mod tests { } #[test] - pub fn run_tests() { + fn run_tests() { // The tests race on tzset. So instead of having many independent // tests, we will just call the functions now. test_get_time(); diff --git a/src/libstd/timer.rs b/src/libstd/timer.rs index 229d1a07caaab..c229e72ae5d4a 100644 --- a/src/libstd/timer.rs +++ b/src/libstd/timer.rs @@ -42,47 +42,45 @@ pub fn delayed_send(iotask: &IoTask, msecs: uint, ch: &Chan, val: T) { + let (timer_done_po, timer_done_ch) = stream::<()>(); + let timer_done_ch = SharedChan(timer_done_ch); + let timer = uv::ll::timer_t(); + let timer_ptr = ptr::addr_of(&timer); + do iotask::interact(iotask) |loop_ptr| { unsafe { - let (timer_done_po, timer_done_ch) = stream::<()>(); - let timer_done_ch = SharedChan(timer_done_ch); - let timer = uv::ll::timer_t(); - let timer_ptr = ptr::addr_of(&timer); - do iotask::interact(iotask) |loop_ptr| { - unsafe { - let init_result = uv::ll::timer_init(loop_ptr, timer_ptr); - if (init_result == 0i32) { - let start_result = uv::ll::timer_start( - timer_ptr, delayed_send_cb, msecs, 0u); - if (start_result == 0i32) { - // Note: putting the channel into a ~ - // to cast to *c_void - let timer_done_ch_clone = ~timer_done_ch.clone(); - let timer_done_ch_ptr = transmute::< - ~SharedChan<()>, *c_void>( - timer_done_ch_clone); - uv::ll::set_data_for_uv_handle( - timer_ptr, - timer_done_ch_ptr); - } else { - let error_msg = uv::ll::get_last_err_info( - loop_ptr); - fail!(~"timer::delayed_send() start failed: " + - error_msg); - } - } else { - let error_msg = uv::ll::get_last_err_info(loop_ptr); - fail!(~"timer::delayed_send() init failed: " + - error_msg); - } + let init_result = uv::ll::timer_init(loop_ptr, timer_ptr); + if (init_result == 0i32) { + let start_result = uv::ll::timer_start( + timer_ptr, delayed_send_cb, msecs, 0u); + if (start_result == 0i32) { + // Note: putting the channel into a ~ + // to cast to *c_void + let timer_done_ch_clone = ~timer_done_ch.clone(); + let timer_done_ch_ptr = transmute::< + ~SharedChan<()>, *c_void>( + timer_done_ch_clone); + uv::ll::set_data_for_uv_handle( + timer_ptr, + timer_done_ch_ptr); + } else { + let error_msg = uv::ll::get_last_err_info( + loop_ptr); + fail!(~"timer::delayed_send() start failed: " + + error_msg); } - }; - // delayed_send_cb has been processed by libuv - timer_done_po.recv(); - // notify the caller immediately - ch.send(val); - // uv_close for this timer has been processed - timer_done_po.recv(); + } else { + let error_msg = uv::ll::get_last_err_info(loop_ptr); + fail!(~"timer::delayed_send() init failed: " + + error_msg); + } + } }; + // delayed_send_cb has been processed by libuv + timer_done_po.recv(); + // notify the caller immediately + ch.send(val); + // uv_close for this timer has been processed + timer_done_po.recv(); } /** @@ -185,13 +183,13 @@ mod test { use core::pipes::{stream, SharedChan}; #[test] - pub fn test_gl_timer_simple_sleep_test() { + fn test_gl_timer_simple_sleep_test() { let hl_loop = &uv::global_loop::get(); sleep(hl_loop, 1u); } #[test] - pub fn test_gl_timer_sleep_stress1() { + fn test_gl_timer_sleep_stress1() { let hl_loop = &uv::global_loop::get(); for iter::repeat(50u) { sleep(hl_loop, 1u); @@ -199,7 +197,7 @@ mod test { } #[test] - pub fn test_gl_timer_sleep_stress2() { + fn test_gl_timer_sleep_stress2() { let (po, ch) = stream(); let ch = SharedChan(ch); let hl_loop = &uv::global_loop::get(); @@ -243,7 +241,7 @@ mod test { #[test] #[cfg(ignore)] - pub fn test_gl_timer_recv_timeout_before_time_passes() { + fn test_gl_timer_recv_timeout_before_time_passes() { let times = 100; let mut successes = 0; let mut failures = 0; @@ -272,7 +270,7 @@ mod test { } #[test] - pub fn test_gl_timer_recv_timeout_after_time_passes() { + fn test_gl_timer_recv_timeout_after_time_passes() { let times = 100; let mut successes = 0; let mut failures = 0; diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index d0868da4408d4..ac887c7fdc41d 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -13,6 +13,7 @@ //! `TotalOrd`. use core::prelude::*; +use core::iterator::*; // This is implemented as an AA tree, which is a simplified variation of // a red-black tree where where red (horizontal) nodes can only be added @@ -43,8 +44,7 @@ impl Eq for TreeMap { let mut x = self.iter(); let mut y = other.iter(); for self.len().times { - if map_next(&mut x).unwrap() != - map_next(&mut y).unwrap() { + if x.next().unwrap() != y.next().unwrap() { return false } } @@ -62,8 +62,8 @@ fn lt(a: &TreeMap, let (a_len, b_len) = (a.len(), b.len()); for uint::min(a_len, b_len).times { - let (key_a,_) = map_next(&mut x).unwrap(); - let (key_b,_) = map_next(&mut y).unwrap(); + let (key_a,_) = x.next().unwrap(); + let (key_b,_) = y.next().unwrap(); if *key_a < *key_b { return true; } if *key_a > *key_b { return false; } }; @@ -82,24 +82,6 @@ impl Ord for TreeMap { fn gt(&self, other: &TreeMap) -> bool { lt(other, self) } } -impl<'self, K: TotalOrd, V> BaseIter<(&'self K, &'self V)> for TreeMap { - /// Visit all key-value pairs in order - fn each(&self, f: &fn(&(&'self K, &'self V)) -> bool) { - each(&self.root, f) - } - fn size_hint(&self) -> Option { Some(self.len()) } -} - -impl<'self, K: TotalOrd, V> - ReverseIter<(&'self K, &'self V)> - for TreeMap -{ - /// Visit all key-value pairs in reverse order - fn each_reverse(&self, f: &fn(&(&'self K, &'self V)) -> bool) { - each_reverse(&self.root, f); - } -} - impl Container for TreeMap { /// Return the number of elements in the map fn len(&const self) -> uint { self.length } @@ -122,22 +104,29 @@ impl Map for TreeMap { self.find(key).is_some() } + /// Visit all key-value pairs in order + fn each<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) { + each(&self.root, f) + } + /// Visit all keys in order - fn each_key(&self, f: &fn(&K) -> bool) { self.each(|&(k, _)| f(k)) } + fn each_key(&self, f: &fn(&K) -> bool) { + self.each(|k, _| f(k)) + } /// Visit all values in order - fn each_value(&self, f: &fn(&V) -> bool) { - self.each(|&(_, v)| f(v)) + fn each_value<'a>(&'a self, f: &fn(&'a V) -> bool) { + self.each(|_, v| f(v)) } /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, f: &fn(&'self K, &'self mut V) -> bool) { + fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool) { mutate_values(&mut self.root, f); } /// Return a reference to the value corresponding to the key - fn find(&self, key: &K) -> Option<&'self V> { - let mut current: &'self Option<~TreeNode> = &self.root; + fn find<'a>(&'a self, key: &K) -> Option<&'a V> { + let mut current: &'a Option<~TreeNode> = &self.root; loop { match *current { Some(ref r) => { @@ -154,7 +143,7 @@ impl Map for TreeMap { /// Return a mutable reference to the value corresponding to the key #[inline(always)] - fn find_mut(&mut self, key: &K) -> Option<&'self mut V> { + fn find_mut<'a>(&'a mut self, key: &K) -> Option<&'a mut V> { find_mut(&mut self.root, key) } @@ -180,19 +169,24 @@ pub impl TreeMap { /// Create an empty TreeMap fn new() -> TreeMap { TreeMap{root: None, length: 0} } + /// Visit all key-value pairs in reverse order + fn each_reverse<'a>(&'a self, f: &fn(&'a K, &'a V) -> bool) { + each_reverse(&self.root, f); + } + /// Visit all keys in reverse order fn each_key_reverse(&self, f: &fn(&K) -> bool) { - self.each_reverse(|&(k, _)| f(k)) + self.each_reverse(|k, _| f(k)) } /// Visit all values in reverse order fn each_value_reverse(&self, f: &fn(&V) -> bool) { - self.each_reverse(|&(_, v)| f(v)) + self.each_reverse(|_, v| f(v)) } /// Get a lazy iterator over the key-value pairs in the map. /// Requires that it be frozen (immutable). - fn iter(&self) -> TreeMapIterator<'self, K, V> { + fn iter<'a>(&'a self) -> TreeMapIterator<'a, K, V> { TreeMapIterator{stack: ~[], node: &self.root} } } @@ -203,37 +197,33 @@ pub struct TreeMapIterator<'self, K, V> { priv node: &'self Option<~TreeNode> } -/// Advance the iterator to the next node (in order) and return a -/// tuple with a reference to the key and value. If there are no -/// more nodes, return `None`. -pub fn map_next<'r, K, V>(iter: &mut TreeMapIterator<'r, K, V>) - -> Option<(&'r K, &'r V)> { - while !iter.stack.is_empty() || iter.node.is_some() { - match *iter.node { - Some(ref x) => { - iter.stack.push(x); - iter.node = &x.left; - } - None => { - let res = iter.stack.pop(); - iter.node = &res.right; - return Some((&res.key, &res.value)); - } +impl<'self, K, V> Iterator<(&'self K, &'self V)> for TreeMapIterator<'self, K, V> { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return `None`. + fn next(&mut self) -> Option<(&'self K, &'self V)> { + while !self.stack.is_empty() || self.node.is_some() { + match *self.node { + Some(ref x) => { + self.stack.push(x); + self.node = &x.left; + } + None => { + let res = self.stack.pop(); + self.node = &res.right; + return Some((&res.key, &res.value)); + } + } } + None } - None } -/// Advance the iterator through the map -pub fn map_advance<'r, K, V>(iter: &mut TreeMapIterator<'r, K, V>, - f: &fn((&'r K, &'r V)) -> bool) { - loop { - match map_next(iter) { - Some(x) => { - if !f(x) { return } - } - None => return - } +impl<'self, T> Iterator<&'self T> for TreeSetIterator<'self, T> { + /// Advance the iterator to the next node (in order). If there are no more nodes, return `None`. + #[inline(always)] + fn next(&mut self) -> Option<&'self T> { + do self.iter.next().map |&(value, _)| { value } } } @@ -313,14 +303,14 @@ impl Set for TreeSet { fn is_disjoint(&self, other: &TreeSet) -> bool { let mut x = self.iter(); let mut y = other.iter(); - let mut a = set_next(&mut x); - let mut b = set_next(&mut y); + let mut a = x.next(); + let mut b = y.next(); while a.is_some() && b.is_some() { let a1 = a.unwrap(); let b1 = b.unwrap(); match a1.cmp(b1) { - Less => a = set_next(&mut x), - Greater => b = set_next(&mut y), + Less => a = x.next(), + Greater => b = y.next(), Equal => return false } } @@ -337,8 +327,8 @@ impl Set for TreeSet { fn is_superset(&self, other: &TreeSet) -> bool { let mut x = self.iter(); let mut y = other.iter(); - let mut a = set_next(&mut x); - let mut b = set_next(&mut y); + let mut a = x.next(); + let mut b = y.next(); while b.is_some() { if a.is_none() { return false @@ -350,10 +340,10 @@ impl Set for TreeSet { match a1.cmp(b1) { Less => (), Greater => return false, - Equal => b = set_next(&mut y), + Equal => b = y.next(), } - a = set_next(&mut x); + a = x.next(); } true } @@ -363,13 +353,13 @@ impl Set for TreeSet { let mut x = self.iter(); let mut y = other.iter(); - let mut a = set_next(&mut x); - let mut b = set_next(&mut y); + let mut a = x.next(); + let mut b = y.next(); while a.is_some() { if b.is_none() { return do a.while_some() |a1| { - if f(a1) { set_next(&mut x) } else { None } + if f(a1) { x.next() } else { None } } } @@ -380,10 +370,10 @@ impl Set for TreeSet { if cmp == Less { if !f(a1) { return } - a = set_next(&mut x); + a = x.next(); } else { - if cmp == Equal { a = set_next(&mut x) } - b = set_next(&mut y); + if cmp == Equal { a = x.next() } + b = y.next(); } } } @@ -394,13 +384,13 @@ impl Set for TreeSet { let mut x = self.iter(); let mut y = other.iter(); - let mut a = set_next(&mut x); - let mut b = set_next(&mut y); + let mut a = x.next(); + let mut b = y.next(); while a.is_some() { if b.is_none() { return do a.while_some() |a1| { - if f(a1) { set_next(&mut x) } else { None } + if f(a1) { x.next() } else { None } } } @@ -411,18 +401,18 @@ impl Set for TreeSet { if cmp == Less { if !f(a1) { return } - a = set_next(&mut x); + a = x.next(); } else { if cmp == Greater { if !f(b1) { return } } else { - a = set_next(&mut x); + a = x.next(); } - b = set_next(&mut y); + b = y.next(); } } do b.while_some |b1| { - if f(b1) { set_next(&mut y) } else { None } + if f(b1) { y.next() } else { None } } } @@ -431,8 +421,8 @@ impl Set for TreeSet { let mut x = self.iter(); let mut y = other.iter(); - let mut a = set_next(&mut x); - let mut b = set_next(&mut y); + let mut a = x.next(); + let mut b = y.next(); while a.is_some() && b.is_some() { let a1 = a.unwrap(); @@ -441,12 +431,12 @@ impl Set for TreeSet { let cmp = a1.cmp(b1); if cmp == Less { - a = set_next(&mut x); + a = x.next(); } else { if cmp == Equal { if !f(a1) { return } } - b = set_next(&mut y); + b = y.next(); } } } @@ -456,13 +446,13 @@ impl Set for TreeSet { let mut x = self.iter(); let mut y = other.iter(); - let mut a = set_next(&mut x); - let mut b = set_next(&mut y); + let mut a = x.next(); + let mut b = y.next(); while a.is_some() { if b.is_none() { return do a.while_some() |a1| { - if f(a1) { set_next(&mut x) } else { None } + if f(a1) { x.next() } else { None } } } @@ -473,17 +463,17 @@ impl Set for TreeSet { if cmp == Greater { if !f(b1) { return } - b = set_next(&mut y); + b = y.next(); } else { if !f(a1) { return } if cmp == Equal { - b = set_next(&mut y); + b = y.next(); } - a = set_next(&mut x); + a = x.next(); } } do b.while_some |b1| { - if f(b1) { set_next(&mut y) } else { None } + if f(b1) { y.next() } else { None } } } } @@ -496,7 +486,7 @@ pub impl TreeSet { /// Get a lazy iterator over the values in the set. /// Requires that it be frozen (immutable). #[inline(always)] - fn iter(&self) -> TreeSetIterator<'self, T> { + fn iter<'a>(&'a self) -> TreeSetIterator<'a, T> { TreeSetIterator{iter: self.map.iter()} } } @@ -506,20 +496,6 @@ pub struct TreeSetIterator<'self, T> { priv iter: TreeMapIterator<'self, T, ()> } -/// Advance the iterator to the next node (in order). If this iterator is -/// finished, does nothing. -#[inline(always)] -pub fn set_next<'r, T>(iter: &mut TreeSetIterator<'r, T>) -> Option<&'r T> { - do map_next(&mut iter.iter).map |&(value, _)| { value } -} - -/// Advance the iterator through the set -#[inline(always)] -pub fn set_advance<'r, T>(iter: &mut TreeSetIterator<'r, T>, - f: &fn(&'r T) -> bool) { - do map_advance(&mut iter.iter) |(k, _)| { f(k) } -} - // Nodes keep track of their level in the tree, starting at 1 in the // leaves and with a red child sharing the level of the parent. struct TreeNode { @@ -538,18 +514,18 @@ pub impl TreeNode { } fn each<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&(&'r K, &'r V)) -> bool) { + f: &fn(&'r K, &'r V) -> bool) { for node.each |x| { each(&x.left, f); - if f(&(&x.key, &x.value)) { each(&x.right, f) } + if f(&x.key, &x.value) { each(&x.right, f) } } } fn each_reverse<'r, K: TotalOrd, V>(node: &'r Option<~TreeNode>, - f: &fn(&(&'r K, &'r V)) -> bool) { + f: &fn(&'r K, &'r V) -> bool) { for node.each |x| { each_reverse(&x.right, f); - if f(&(&x.key, &x.value)) { each_reverse(&x.left, f) } + if f(&x.key, &x.value) { each_reverse(&x.left, f) } } } @@ -719,6 +695,7 @@ fn remove(node: &mut Option<~TreeNode>, #[cfg(test)] mod test_treemap { use core::prelude::*; + use core::iterator::*; use super::*; use core::rand::RngUtil; use core::rand; @@ -796,7 +773,7 @@ mod test_treemap { let &(k, v) = x; assert!(map.find(&k).unwrap() == &v) } - for map.each |&(map_k, map_v)| { + for map.each |map_k, map_v| { let mut found = false; for ctrl.each |x| { let &(ctrl_k, ctrl_v) = x; @@ -912,7 +889,7 @@ mod test_treemap { assert!(m.insert(1, 2)); let mut n = 0; - for m.each |&(k, v)| { + for m.each |k, v| { assert!(*k == n); assert!(*v == n * 2); n += 1; @@ -930,7 +907,7 @@ mod test_treemap { assert!(m.insert(1, 2)); let mut n = 4; - for m.each_reverse |&(k, v)| { + for m.each_reverse |k, v| { assert!(*k == n); assert!(*v == n * 2); n -= 1; @@ -1005,13 +982,13 @@ mod test_treemap { let m = m; let mut a = m.iter(); - assert!(map_next(&mut a).unwrap() == (&x1, &y1)); - assert!(map_next(&mut a).unwrap() == (&x2, &y2)); - assert!(map_next(&mut a).unwrap() == (&x3, &y3)); - assert!(map_next(&mut a).unwrap() == (&x4, &y4)); - assert!(map_next(&mut a).unwrap() == (&x5, &y5)); + assert!(a.next().unwrap() == (&x1, &y1)); + assert!(a.next().unwrap() == (&x2, &y2)); + assert!(a.next().unwrap() == (&x3, &y3)); + assert!(a.next().unwrap() == (&x4, &y4)); + assert!(a.next().unwrap() == (&x5, &y5)); - assert!(map_next(&mut a).is_none()); + assert!(a.next().is_none()); let mut b = m.iter(); @@ -1019,7 +996,7 @@ mod test_treemap { (&x5, &y5)]; let mut i = 0; - for map_advance(&mut b) |x| { + for b.advance |x| { assert!(expected[i] == x); i += 1; @@ -1028,7 +1005,7 @@ mod test_treemap { } } - for map_advance(&mut b) |x| { + for b.advance |x| { assert!(expected[i] == x); i += 1; } @@ -1037,6 +1014,8 @@ mod test_treemap { #[cfg(test)] mod test_set { + use core::prelude::*; + use core::iterator::*; use super::*; #[test] @@ -1216,4 +1195,30 @@ mod test_set { [-2, 1, 5, 9, 13, 19], [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]); } + + #[test] + fn test_zip() { + let mut x = TreeSet::new(); + x.insert(5u); + x.insert(12u); + x.insert(11u); + + let mut y = TreeSet::new(); + y.insert("foo"); + y.insert("bar"); + + let x = x; + let y = y; + let mut z = x.iter().zip(y.iter()); + + // FIXME: #5801: this needs a type hint to compile... + let result: Option<(&uint, & &'static str)> = z.next(); + assert!(result.unwrap() == (&5u, & &"bar")); + + let result: Option<(&uint, & &'static str)> = z.next(); + assert!(result.unwrap() == (&11u, & &"foo")); + + let result: Option<(&uint, & &'static str)> = z.next(); + assert!(result.is_none()); + } } diff --git a/src/libstd/uv_iotask.rs b/src/libstd/uv_iotask.rs index fe40fc6a78b41..7a9d2438e6ada 100644 --- a/src/libstd/uv_iotask.rs +++ b/src/libstd/uv_iotask.rs @@ -75,7 +75,7 @@ pub fn spawn_iotask(task: task::TaskBuilder) -> IoTask { * module. It is not safe to send the `loop_ptr` param to this callback out * via ports/chans. */ -pub unsafe fn interact(iotask: &IoTask, cb: ~fn(*c_void)) { +pub fn interact(iotask: &IoTask, cb: ~fn(*c_void)) { send_msg(iotask, Interaction(cb)); } @@ -87,9 +87,7 @@ pub unsafe fn interact(iotask: &IoTask, cb: ~fn(*c_void)) { * closed, causing a failure otherwise. */ pub fn exit(iotask: &IoTask) { - unsafe { - send_msg(iotask, TeardownLoop); - } + send_msg(iotask, TeardownLoop); } diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs index 7582a7cff513c..740ecec001f83 100644 --- a/src/libstd/uv_ll.rs +++ b/src/libstd/uv_ll.rs @@ -1111,22 +1111,22 @@ pub unsafe fn freeaddrinfo(res: *addrinfo) { } // libuv struct initializers -pub unsafe fn tcp_t() -> uv_tcp_t { +pub fn tcp_t() -> uv_tcp_t { return uv_ll_struct_stubgen::gen_stub_uv_tcp_t(); } -pub unsafe fn connect_t() -> uv_connect_t { +pub fn connect_t() -> uv_connect_t { return uv_ll_struct_stubgen::gen_stub_uv_connect_t(); } -pub unsafe fn write_t() -> uv_write_t { +pub fn write_t() -> uv_write_t { return uv_ll_struct_stubgen::gen_stub_uv_write_t(); } -pub unsafe fn async_t() -> uv_async_t { +pub fn async_t() -> uv_async_t { return uv_ll_struct_stubgen::gen_stub_uv_async_t(); } -pub unsafe fn timer_t() -> uv_timer_t { +pub fn timer_t() -> uv_timer_t { return uv_ll_struct_stubgen::gen_stub_uv_timer_t(); } -pub unsafe fn getaddrinfo_t() -> uv_getaddrinfo_t { +pub fn getaddrinfo_t() -> uv_getaddrinfo_t { return uv_ll_struct_stubgen::gen_stub_uv_getaddrinfo_t(); } @@ -1225,7 +1225,7 @@ pub unsafe fn addrinfo_as_sockaddr_in6(input: *addrinfo) -> *sockaddr_in6 { } #[cfg(test)] -pub mod test { +mod test { use core::prelude::*; use core::comm::{SharedChan, stream, GenericChan, GenericPort}; use super::*; @@ -1759,11 +1759,11 @@ pub mod test { #[cfg(target_os="darwin")] #[cfg(target_os="linux")] #[cfg(target_os="android")] - pub mod tcp_and_server_client_test { + mod tcp_and_server_client_test { #[cfg(target_arch="x86_64")] - pub mod impl64 { + mod impl64 { #[test] - pub fn test_uv_ll_tcp_server_and_request() { + fn test_uv_ll_tcp_server_and_request() { unsafe { super::super::impl_uv_tcp_server_and_request(); } @@ -1772,10 +1772,10 @@ pub mod test { #[cfg(target_arch="x86")] #[cfg(target_arch="arm")] #[cfg(target_arch="mips")] - pub mod impl32 { + mod impl32 { #[test] #[ignore(cfg(target_os = "linux"))] - pub fn test_uv_ll_tcp_server_and_request() { + fn test_uv_ll_tcp_server_and_request() { unsafe { super::super::impl_uv_tcp_server_and_request(); } diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index 6ed1364d7fcb2..c4b450810aa86 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -24,7 +24,7 @@ use core::pipes::recv; use core::prelude::*; use core::result; use core::run; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::task; use core::to_bytes; @@ -136,16 +136,16 @@ pub impl WorkKey { } } -struct WorkMap(LinearMap); +struct WorkMap(HashMap); impl WorkMap { - fn new() -> WorkMap { WorkMap(LinearMap::new()) } + fn new() -> WorkMap { WorkMap(HashMap::new()) } } impl Encodable for WorkMap { fn encode(&self, s: &S) { let mut d = ~[]; - for self.each |&(k, v)| { + for self.each |k, v| { d.push((copy *k, copy *v)) } sort::tim_sort(d); @@ -166,7 +166,7 @@ impl Decodable for WorkMap { struct Database { db_filename: Path, - db_cache: LinearMap<~str, ~str>, + db_cache: HashMap<~str, ~str>, db_dirty: bool } @@ -212,7 +212,7 @@ struct Context { db: @mut Database, logger: @mut Logger, cfg: @json::Object, - freshness: LinearMap<~str,@fn(&str,&str)->bool> + freshness: HashMap<~str,@fn(&str,&str)->bool> } struct Prep { @@ -267,7 +267,7 @@ pub impl Context { db: db, logger: lg, cfg: cfg, - freshness: LinearMap::new() + freshness: HashMap::new() } } @@ -319,7 +319,7 @@ impl TPrep for Prep { } fn all_fresh(&self, cat: &str, map: &WorkMap) -> bool { - for map.each |&(k, v)| { + for map.each |k, v| { if ! self.is_fresh(cat, k.kind, k.name, *v) { return false; } @@ -411,10 +411,10 @@ fn test() { use core::io::WriterUtil; let db = @mut Database { db_filename: Path("db.json"), - db_cache: LinearMap::new(), + db_cache: HashMap::new(), db_dirty: false }; let lg = @mut Logger { a: () }; - let cfg = @LinearMap::new(); + let cfg = @HashMap::new(); let cx = @Context::new(db, lg, cfg); let w:Work<~str> = do cx.prep("test1") |prep| { let pth = Path("foo.c"); diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 37fed113382a2..a848f97d2e09e 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -274,13 +274,11 @@ impl ToStr for Abi { impl ToStr for AbiSet { fn to_str(&self) -> ~str { - unsafe { // so we can push to strs. - let mut strs = ~[]; - for self.each |abi| { - strs.push(abi.data().name); - } - fmt!("\"%s\"", str::connect_slices(strs, " ")) + let mut strs = ~[]; + for self.each |abi| { + strs.push(abi.data().name); } + fmt!("\"%s\"", str::connect_slices(strs, " ")) } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 2e7ae4c537a8c..9c20012d42e6b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -113,7 +113,7 @@ pub struct Lifetime { #[auto_encode] #[auto_decode] #[deriving(Eq)] -pub struct path { +pub struct Path { span: span, global: bool, idents: ~[ident], @@ -144,7 +144,7 @@ pub static crate_node_id: node_id = 0; // the "special" built-in traits (see middle::lang_items) and // detects Copy, Send, Owned, and Const. pub enum TyParamBound { - TraitTyParamBound(@Ty), + TraitTyParamBound(@trait_ref), RegionTyParamBound } @@ -194,6 +194,7 @@ pub enum def { def_local(node_id, bool /* is_mutbl */), def_variant(def_id /* enum */, def_id /* variant */), def_ty(def_id), + def_trait(def_id), def_prim_ty(prim_ty), def_ty_param(def_id, uint), def_binding(node_id, binding_mode), @@ -300,10 +301,10 @@ pub enum pat_ { // which it is. The resolver determines this, and // records this pattern's node_id in an auxiliary // set (of "pat_idents that refer to nullary enums") - pat_ident(binding_mode, @path, Option<@pat>), - pat_enum(@path, Option<~[@pat]>), /* "none" means a * pattern where + pat_ident(binding_mode, @Path, Option<@pat>), + pat_enum(@Path, Option<~[@pat]>), /* "none" means a * pattern where * we don't bind the fields to names */ - pat_struct(@path, ~[field_pat], bool), + pat_struct(@Path, ~[field_pat], bool), pat_tup(~[@pat]), pat_box(@pat), pat_uniq(@pat), @@ -566,7 +567,7 @@ pub enum expr_ { expr_assign_op(binop, @expr, @expr), expr_field(@expr, ident, ~[@Ty]), expr_index(@expr, @expr), - expr_path(@path), + expr_path(@Path), expr_addr_of(mutability, @expr), expr_break(Option), expr_again(Option), @@ -578,7 +579,7 @@ pub enum expr_ { expr_mac(mac), // A struct literal expression. - expr_struct(@path, ~[field], Option<@expr>), + expr_struct(@Path, ~[field], Option<@expr>), // A vector literal constructed from one repeated element. expr_repeat(@expr /* element */, @expr /* count */, mutability), @@ -696,7 +697,7 @@ pub type mac = spanned; #[auto_decode] #[deriving(Eq)] pub enum mac_ { - mac_invoc_tt(@path,~[token_tree]), // new macro-invocation + mac_invoc_tt(@Path,~[token_tree]), // new macro-invocation } pub type lit = spanned; @@ -893,7 +894,7 @@ pub enum ty_ { ty_closure(@TyClosure), ty_bare_fn(@TyBareFn), ty_tup(~[@Ty]), - ty_path(@path, node_id), + ty_path(@Path, node_id), ty_mac(mac), // ty_infer means the type should be inferred instead of it having been // specified. This should only appear at the "top level" of a type and not @@ -1001,15 +1002,6 @@ pub enum self_ty_ { sty_uniq(mutability) // `~self` } -impl self_ty_ { - fn is_borrowed(&self) -> bool { - match *self { - sty_region(*) => true, - _ => false - } - } -} - pub type self_ty = spanned; #[auto_encode] @@ -1117,13 +1109,13 @@ pub enum view_path_ { // or just // // foo::bar::baz (with 'baz =' implicitly on the left) - view_path_simple(ident, @path, namespace, node_id), + view_path_simple(ident, @Path, namespace, node_id), // foo::bar::* - view_path_glob(@path, node_id), + view_path_glob(@Path, node_id), // foo::bar::{a,b,c} - view_path_list(@path, ~[path_list_ident], node_id) + view_path_list(@Path, ~[path_list_ident], node_id) } #[auto_encode] @@ -1176,7 +1168,7 @@ pub struct attribute_ { #[auto_decode] #[deriving(Eq)] pub struct trait_ref { - path: @path, + path: @Path, ref_id: node_id, } @@ -1185,6 +1177,15 @@ pub struct trait_ref { #[deriving(Eq)] pub enum visibility { public, private, inherited } +impl visibility { + fn inherit_from(&self, parent_visibility: visibility) -> visibility { + match self { + &inherited => parent_visibility, + &public | &private => *self + } + } +} + #[auto_encode] #[auto_decode] #[deriving(Eq)] diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index f22b466efebda..147d8227b81ea 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -23,7 +23,7 @@ use print::pprust; use visit; use core::cmp; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::str; use core::vec; @@ -104,7 +104,7 @@ pub enum ast_node { node_struct_ctor(@struct_def, @item, @path), } -pub type map = @mut LinearMap; +pub type map = @mut HashMap; pub struct Ctx { map: map, @@ -134,7 +134,7 @@ pub fn mk_ast_map_visitor() -> vt { pub fn map_crate(diag: @span_handler, c: crate) -> map { let cx = @mut Ctx { - map: @mut LinearMap::new(), + map: @mut HashMap::new(), path: ~[], local_id: 0u, diag: diag, diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 208ed1e35fe1a..e83a3ef8bad52 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -30,7 +30,7 @@ pub fn path_name_i(idents: &[ident], intr: @token::ident_interner) -> ~str { } -pub fn path_to_ident(p: @path) -> ident { copy *p.idents.last() } +pub fn path_to_ident(p: @Path) -> ident { copy *p.idents.last() } pub fn local_def(id: node_id) -> def_id { ast::def_id { crate: local_crate, node: id } @@ -61,7 +61,7 @@ pub fn def_id_of_def(d: def) -> def_id { def_fn(id, _) | def_static_method(id, _, _) | def_mod(id) | def_foreign_mod(id) | def_const(id) | def_variant(_, id) | def_ty(id) | def_ty_param(id, _) | - def_use(id) | def_struct(id) => { + def_use(id) | def_struct(id) | def_trait(id) => { id } def_arg(id, _, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id) @@ -223,8 +223,8 @@ pub fn default_block( } } -pub fn ident_to_path(s: span, +i: ident) -> @path { - @ast::path { span: s, +pub fn ident_to_path(s: span, +i: ident) -> @Path { + @ast::Path { span: s, global: false, idents: ~[i], rp: None, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 9f8dbef9b967b..5063a0381e782 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -20,7 +20,7 @@ use diagnostic::span_handler; use parse::comments::{doc_comment_style, strip_doc_comment_decoration}; use core::vec; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use std; /* Constructors */ @@ -333,7 +333,7 @@ pub fn find_inline_attr(attrs: &[ast::attribute]) -> inline_attr { pub fn require_unique_names(diagnostic: @span_handler, metas: &[@ast::meta_item]) { - let mut set = LinearSet::new(); + let mut set = HashSet::new(); for metas.each |meta| { let name = get_meta_item_name(*meta); diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 7a8aff121a86d..0ed371d9c9afe 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -206,8 +206,12 @@ pub struct FileLines lines: ~[uint] } +// represents the origin of a file: pub enum FileSubstr { + // indicates that this is a normal standalone file: pub FssNone, + // indicates that this "file" is actually a substring + // of another file that appears earlier in the codemap pub FssInternal(span), } @@ -252,15 +256,13 @@ pub impl FileMap { // get a line from the list of pre-computed line-beginnings pub fn get_line(&self, line: int) -> ~str { - unsafe { - let begin: BytePos = self.lines[line] - self.start_pos; - let begin = begin.to_uint(); - let end = match str::find_char_from(*self.src, '\n', begin) { - Some(e) => e, - None => str::len(*self.src) - }; - str::slice(*self.src, begin, end).to_owned() - } + let begin: BytePos = self.lines[line] - self.start_pos; + let begin = begin.to_uint(); + let end = match str::find_char_from(*self.src, '\n', begin) { + Some(e) => e, + None => str::len(*self.src) + }; + str::slice(*self.src, begin, end).to_owned() } pub fn record_multibyte_char(&self, pos: BytePos, bytes: uint) { diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index d25792355a718..e53a8f361b5fe 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -222,15 +222,14 @@ pub fn expand_auto_decode( priv impl @ext_ctxt { fn bind_path( &self, - span: span, + _span: span, ident: ast::ident, - path: @ast::path, + path: @ast::Path, bounds: @OptVec ) -> ast::TyParam { - let bound = ast::TraitTyParamBound(@ast::Ty { - id: self.next_id(), - node: ast::ty_path(path, self.next_id()), - span: span, + let bound = ast::TraitTyParamBound(@ast::trait_ref { + ref_id: self.next_id(), + path: path }); ast::TyParam { @@ -249,8 +248,8 @@ priv impl @ext_ctxt { } } - fn path(&self, span: span, +strs: ~[ast::ident]) -> @ast::path { - @ast::path { + fn path(&self, span: span, +strs: ~[ast::ident]) -> @ast::Path { + @ast::Path { span: span, global: false, idents: strs, @@ -259,8 +258,8 @@ priv impl @ext_ctxt { } } - fn path_global(&self, span: span, +strs: ~[ast::ident]) -> @ast::path { - @ast::path { + fn path_global(&self, span: span, +strs: ~[ast::ident]) -> @ast::Path { + @ast::Path { span: span, global: true, idents: strs, @@ -274,8 +273,8 @@ priv impl @ext_ctxt { span: span, +strs: ~[ast::ident], +tps: ~[@ast::Ty] - ) -> @ast::path { - @ast::path { + ) -> @ast::Path { + @ast::Path { span: span, global: false, idents: strs, @@ -289,8 +288,8 @@ priv impl @ext_ctxt { span: span, +strs: ~[ast::ident], +tps: ~[@ast::Ty] - ) -> @ast::path { - @ast::path { + ) -> @ast::Path { + @ast::Path { span: span, global: true, idents: strs, @@ -440,7 +439,7 @@ fn mk_impl( span: span, ident: ast::ident, ty_param: ast::TyParam, - path: @ast::path, + path: @ast::Path, generics: &ast::Generics, f: &fn(@ast::Ty) -> @ast::method ) -> @ast::item { @@ -466,10 +465,9 @@ fn mk_impl( // 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::Ty { - id: cx.next_id(), - node: ast::ty_path(path, cx.next_id()), - span: span, + let t_bound = ast::TraitTyParamBound(@ast::trait_ref { + path: path, + ref_id: cx.next_id(), }); impl_tps.push(ast::TyParam { @@ -734,12 +732,12 @@ fn mk_struct_ser_impl( ) ); - // ast for `__s.emit_field($(name), $(idx), $(expr_lambda))` + // 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_field"), + cx.ident_of(~"emit_struct_field"), ~[ cx.lit_str(span, @cx.str_of(field.ident)), cx.lit_uint(span, idx), @@ -788,11 +786,11 @@ fn mk_struct_deser_impl( ) ); - // ast for `__d.read_field($(name), $(idx), $(expr_lambda))` + // 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_field"), + cx.ident_of(~"read_struct_field"), ~[ cx.lit_str(span, @cx.str_of(field.ident)), cx.lit_uint(span, idx), @@ -1255,20 +1253,35 @@ mod test { self.add_to_log(CallToEmitEnumVariantArg (idx)); f(); } - fn emit_seq(&self, +_len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + self.emit_enum_variant(name, id, cnt, f) } - fn emit_seq_elt(&self, +_idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + + fn emit_enum_struct_variant_field(&self, _name: &str, idx: uint, f: &fn()) { + self.emit_enum_variant_arg(idx, f) } fn emit_struct(&self, name: &str, +len: uint, f: &fn()) { self.add_to_log(CallToEmitStruct (name.to_str(),len)); f(); } - fn emit_field(&self, name: &str, +idx: uint, f: &fn()) { + fn emit_struct_field(&self, name: &str, +idx: uint, f: &fn()) { self.add_to_log(CallToEmitField (name.to_str(),idx)); f(); } + fn emit_tuple(&self, _len: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_tuple_arg(&self, _idx: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + + fn emit_tuple_struct(&self, _name: &str, _len: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_tuple_struct_arg(&self, _idx: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_option(&self, f: &fn()) { self.add_to_log(CallToEmitOption); f(); @@ -1281,6 +1294,13 @@ mod test { f(); } + fn emit_seq(&self, +_len: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_seq_elt(&self, +_idx: uint, f: &fn()) { + self.add_unknown_to_log(); f(); + } + fn emit_map(&self, _len: uint, f: &fn()) { self.add_unknown_to_log(); f(); } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 93e2ad64c8c23..886af694920f7 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -20,7 +20,7 @@ use parse; use parse::token; use core::vec; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; // new-style macro! tt code: // @@ -125,7 +125,7 @@ pub fn syntax_expander_table() -> SyntaxEnv { fn builtin_item_tt(f: SyntaxExpanderTTItemFun) -> @Transformer { @SE(IdentTT(SyntaxExpanderTTItem{expander: f, span: None})) } - let mut syntax_expanders = LinearMap::new(); + let mut syntax_expanders = HashMap::new(); // NB identifier starts with space, and can't conflict with legal idents syntax_expanders.insert(@~" block", @ScopeMacros(true)); @@ -430,8 +430,8 @@ pub fn get_exprs_from_tts(cx: @ext_ctxt, tts: &[ast::token_tree]) // a transformer env is either a base map or a map on top // of another chain. pub enum MapChain { - BaseMapChain(~LinearMap), - ConsMapChain(~LinearMap,@mut MapChain) + BaseMapChain(~HashMap), + ConsMapChain(~HashMap,@mut MapChain) } @@ -439,13 +439,13 @@ pub enum MapChain { impl MapChain{ // Constructor. I don't think we need a zero-arg one. - fn new(+init: ~LinearMap) -> @mut MapChain { + fn new(+init: ~HashMap) -> @mut MapChain { @mut BaseMapChain(init) } // add a new frame to the environment (functionally) fn push_frame (@mut self) -> @mut MapChain { - @mut ConsMapChain(~LinearMap::new() ,self) + @mut ConsMapChain(~HashMap::new() ,self) } // no need for pop, it'll just be functional. @@ -454,7 +454,20 @@ impl MapChain{ // ugh: can't get this to compile with mut because of the // lack of flow sensitivity. - fn get_map(&self) -> &'self LinearMap { + #[cfg(stage0)] + fn get_map(&self) -> &'self HashMap { + match *self { + BaseMapChain (~ref map) => map, + ConsMapChain (~ref map,_) => map + } + } + + // ugh: can't get this to compile with mut because of the + // lack of flow sensitivity. + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get_map<'a>(&'a self) -> &'a HashMap { match *self { BaseMapChain (~ref map) => map, ConsMapChain (~ref map,_) => map @@ -509,10 +522,10 @@ impl MapChain{ #[cfg(test)] mod test { use super::MapChain; - use core::hashmap::linear::LinearMap; + use core::hashmap::HashMap; #[test] fn testenv () { - let mut a = LinearMap::new(); + let mut a = HashMap::new(); a.insert (@~"abc",@15); let m = MapChain::new(~a); m.insert (@~"def",@16); diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 9499f95f0e76f..b375adef9263d 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -63,30 +63,30 @@ pub fn mk_unary(cx: @ext_ctxt, sp: span, op: ast::unop, e: @ast::expr) cx.next_id(); // see ast_util::op_expr_callee_id mk_expr(cx, sp, ast::expr_unary(op, e)) } -pub fn mk_raw_path(sp: span, +idents: ~[ast::ident]) -> @ast::path { - let p = @ast::path { span: sp, - global: false, - idents: idents, - rp: None, - types: ~[] }; - return p; +pub fn mk_raw_path(sp: span, +idents: ~[ast::ident]) -> @ast::Path { + mk_raw_path_(sp, idents, ~[]) } pub fn mk_raw_path_(sp: span, +idents: ~[ast::ident], +types: ~[@ast::Ty]) - -> @ast::path { - @ast::path { span: sp, + -> @ast::Path { + @ast::Path { span: sp, global: false, idents: idents, rp: None, types: types } } -pub fn mk_raw_path_global(sp: span, +idents: ~[ast::ident]) -> @ast::path { - @ast::path { span: sp, +pub fn mk_raw_path_global(sp: span, +idents: ~[ast::ident]) -> @ast::Path { + mk_raw_path_global_(sp, idents, ~[]) +} +pub fn mk_raw_path_global_(sp: span, + +idents: ~[ast::ident], + +types: ~[@ast::Ty]) -> @ast::Path { + @ast::Path { span: sp, global: true, idents: idents, rp: None, - types: ~[] } + types: types } } pub fn mk_path(cx: @ext_ctxt, sp: span, +idents: ~[ast::ident]) -> @ast::expr { @@ -271,6 +271,36 @@ pub fn mk_simple_block(cx: @ext_ctxt, span: span, } } +pub fn mk_lambda_(cx: @ext_ctxt, + span: span, + fn_decl: ast::fn_decl, + blk: ast::blk) + -> @ast::expr { + mk_expr(cx, span, ast::expr_fn_block(fn_decl, blk)) +} +pub fn mk_lambda(cx: @ext_ctxt, + span: span, + fn_decl: ast::fn_decl, + expr: @ast::expr) + -> @ast::expr { + let blk = mk_simple_block(cx, span, expr); + mk_lambda_(cx, span, fn_decl, blk) +} +pub fn mk_lambda_stmts(cx: @ext_ctxt, + span: span, + fn_decl: ast::fn_decl, + stmts: ~[@ast::stmt]) + -> @ast::expr { + let blk = mk_block(cx, span, ~[], stmts, None); + mk_lambda(cx, span, fn_decl, blk) +} +pub fn mk_lambda_no_args(cx: @ext_ctxt, + span: span, + expr: @ast::expr) + -> @ast::expr { + let fn_decl = mk_fn_decl(~[], mk_ty_infer(cx, span)); + mk_lambda(cx, span, fn_decl, expr) +} pub fn mk_copy(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { mk_expr(cx, sp, ast::expr_copy(e)) } @@ -280,11 +310,20 @@ pub fn mk_managed(cx: @ext_ctxt, sp: span, e: @ast::expr) -> @ast::expr { pub fn mk_pat(cx: @ext_ctxt, span: span, +pat: ast::pat_) -> @ast::pat { @ast::pat { id: cx.next_id(), node: pat, span: span } } +pub fn mk_pat_wild(cx: @ext_ctxt, span: span) -> @ast::pat { + mk_pat(cx, span, ast::pat_wild) +} +pub fn mk_pat_lit(cx: @ext_ctxt, + span: span, + expr: @ast::expr) -> @ast::pat { + mk_pat(cx, span, ast::pat_lit(expr)) +} pub fn mk_pat_ident(cx: @ext_ctxt, span: span, ident: ast::ident) -> @ast::pat { mk_pat_ident_with_binding_mode(cx, span, ident, ast::bind_by_copy) } + pub fn mk_pat_ident_with_binding_mode(cx: @ext_ctxt, span: span, ident: ast::ident, @@ -295,7 +334,7 @@ pub fn mk_pat_ident_with_binding_mode(cx: @ext_ctxt, } pub fn mk_pat_enum(cx: @ext_ctxt, span: span, - path: @ast::path, + path: @ast::Path, +subpats: ~[@ast::pat]) -> @ast::pat { let pat = ast::pat_enum(path, Some(subpats)); @@ -303,7 +342,7 @@ pub fn mk_pat_enum(cx: @ext_ctxt, } pub fn mk_pat_struct(cx: @ext_ctxt, span: span, - path: @ast::path, + path: @ast::Path, +field_pats: ~[ast::field_pat]) -> @ast::pat { let pat = ast::pat_struct(path, field_pats, false); @@ -337,6 +376,40 @@ pub fn mk_ty_path_global(cx: @ext_ctxt, let ty = @ast::Ty { id: cx.next_id(), node: ty, span: span }; ty } +pub fn mk_ty_rptr(cx: @ext_ctxt, + span: span, + ty: @ast::Ty, + mutbl: ast::mutability) + -> @ast::Ty { + @ast::Ty { + id: cx.next_id(), + span: span, + node: ast::ty_rptr( + None, + ast::mt { ty: ty, mutbl: mutbl } + ), + } +} +pub fn mk_ty_infer(cx: @ext_ctxt, span: span) -> @ast::Ty { + @ast::Ty { + id: cx.next_id(), + node: ast::ty_infer, + span: span, + } +} +pub fn mk_trait_ref_global(cx: @ext_ctxt, + span: span, + +idents: ~[ ast::ident ]) + -> @ast::trait_ref +{ + mk_trait_ref_(cx, build::mk_raw_path_global(span, idents)) +} +pub fn mk_trait_ref_(cx: @ext_ctxt, path: @ast::Path) -> @ast::trait_ref { + @ast::trait_ref { + path: path, + ref_id: cx.next_id() + } +} pub fn mk_simple_ty_path(cx: @ext_ctxt, span: span, ident: ast::ident) @@ -360,6 +433,16 @@ pub fn mk_arg(cx: @ext_ctxt, pub fn mk_fn_decl(+inputs: ~[ast::arg], output: @ast::Ty) -> ast::fn_decl { ast::fn_decl { inputs: inputs, output: output, cf: ast::return_val } } +pub fn mk_trait_ty_param_bound_global(cx: @ext_ctxt, + span: span, + +idents: ~[ast::ident]) + -> ast::TyParamBound { + ast::TraitTyParamBound(mk_trait_ref_global(cx, span, idents)) +} +pub fn mk_trait_ty_param_bound_(cx: @ext_ctxt, + path: @ast::Path) -> ast::TyParamBound { + ast::TraitTyParamBound(mk_trait_ref_(cx, path)) +} pub fn mk_ty_param(cx: @ext_ctxt, ident: ast::ident, bounds: @OptVec) @@ -368,8 +451,38 @@ pub fn mk_ty_param(cx: @ext_ctxt, } pub fn mk_lifetime(cx: @ext_ctxt, span: span, - ident: ast::ident) -> ast::Lifetime -{ + ident: ast::ident) + -> ast::Lifetime { ast::Lifetime { id: cx.next_id(), span: span, ident: ident } } - +pub fn mk_arm(cx: @ext_ctxt, + span: span, + pats: ~[@ast::pat], + expr: @ast::expr) + -> ast::arm { + ast::arm { + pats: pats, + guard: None, + body: mk_simple_block(cx, span, expr) + } +} +pub fn mk_unreachable(cx: @ext_ctxt, span: span) -> @ast::expr { + let loc = cx.codemap().lookup_char_pos(span.lo); + mk_call_global( + cx, + span, + ~[ + cx.ident_of(~"core"), + cx.ident_of(~"sys"), + cx.ident_of(~"begin_unwind"), + ], + ~[ + mk_uniq_str(cx, span, ~"internal error: entered unreachable code"), + mk_uniq_str(cx, span, loc.file.name), + mk_uint(cx, span, loc.line), + ] + ) +} +pub fn mk_unreachable_arm(cx: @ext_ctxt, span: span) -> ast::arm { + mk_arm(cx, span, ~[mk_pat_wild(cx, span)], mk_unreachable(cx, span)) +} diff --git a/src/libsyntax/ext/concat_idents.rs b/src/libsyntax/ext/concat_idents.rs index 0c3bef56459b5..f4901191b8ac9 100644 --- a/src/libsyntax/ext/concat_idents.rs +++ b/src/libsyntax/ext/concat_idents.rs @@ -41,7 +41,7 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) id: cx.next_id(), callee_id: cx.next_id(), node: ast::expr_path( - @ast::path { + @ast::Path { span: sp, global: false, idents: ~[res], diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index c9e1771599939..d996bca60a367 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -8,28 +8,36 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - -use ast; -use ast::*; +use ast::{meta_item, item, expr}; +use codemap::span; use ext::base::ext_ctxt; use ext::build; -use ext::deriving::*; -use codemap::{span, spanned}; -use ast_util; +use ext::deriving::generic::*; +use core::option::{None,Some}; -use core::uint; pub fn expand_deriving_clone(cx: @ext_ctxt, span: span, - _: @meta_item, + mitem: @meta_item, in_items: ~[@item]) -> ~[@item] { - expand_deriving(cx, - span, - in_items, - expand_deriving_clone_struct_def, - expand_deriving_clone_enum_def) + let trait_def = TraitDef { + path: ~[~"core", ~"clone", ~"Clone"], + additional_bounds: ~[], + methods: ~[ + MethodDef { + name: ~"clone", + nargs: 0, + output_type: None, // return Self + const_nonmatching: false, + combine_substructure: cs_clone + } + ] + }; + + expand_deriving_generic(cx, span, + mitem, in_items, + &trait_def) } pub fn expand_deriving_obsolete(cx: @ext_ctxt, @@ -41,252 +49,52 @@ pub fn expand_deriving_obsolete(cx: @ext_ctxt, in_items } -fn create_derived_clone_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - method: @method) - -> @item { - let methods = [ method ]; - let trait_path = [ - cx.ident_of(~"core"), - cx.ident_of(~"clone"), - cx.ident_of(~"Clone"), - ]; - create_derived_impl(cx, span, type_ident, generics, methods, trait_path) -} -// Creates a method from the given expression conforming to the signature of -// the `clone` method. -fn create_clone_method(cx: @ext_ctxt, - span: span, - +type_ident: ast::ident, - generics: &Generics, - expr: @ast::expr) - -> @method { - // Create the type parameters of the return value. - let mut output_ty_params = ~[]; - for generics.ty_params.each |ty_param| { - let path = build::mk_ty_path(cx, span, ~[ ty_param.ident ]); - output_ty_params.push(path); - } - - // Create the type of the return value. - let output_type_path = build::mk_raw_path_(span, - ~[ type_ident ], - output_ty_params); - let output_type = ast::ty_path(output_type_path, cx.next_id()); - let output_type = @ast::Ty { - id: cx.next_id(), - node: output_type, - span: span - }; - - // Create the function declaration. - let fn_decl = build::mk_fn_decl(~[], output_type); - - // Create the body block. - let body_block = build::mk_simple_block(cx, span, expr); - - // Create the self type and method identifier. - let self_ty = spanned { node: sty_region(None, m_imm), span: span }; - let method_ident = cx.ident_of(~"clone"); - - // Create the method. - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - self_ty: self_ty, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public, +fn cs_clone(cx: @ext_ctxt, span: span, + substr: &Substructure) -> @expr { + let clone_ident = substr.method_ident; + let ctor_ident; + let all_fields; + let subcall = |field| + build::mk_method_call(cx, span, field, clone_ident, ~[]); + + match *substr.fields { + Struct(af) => { + ctor_ident = ~[ substr.type_ident ]; + all_fields = af; + } + EnumMatching(_, variant, af) => { + ctor_ident = ~[ variant.node.name ]; + all_fields = af; + }, + EnumNonMatching(*) => cx.bug("Non-matching enum variants in `deriving(Clone)`") } -} - -fn call_substructure_clone_method(cx: @ext_ctxt, - span: span, - self_field: @expr) - -> @expr { - // Call the substructure method. - let clone_ident = cx.ident_of(~"clone"); - build::mk_method_call(cx, span, - self_field, clone_ident, - ~[]) -} - -fn expand_deriving_clone_struct_def(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the method. - let method = if !is_struct_tuple(struct_def) { - expand_deriving_clone_struct_method(cx, - span, - struct_def, - type_ident, - generics) - } else { - expand_deriving_clone_tuple_struct_method(cx, - span, - struct_def, - type_ident, - generics) - }; - - // Create the implementation. - create_derived_clone_impl(cx, span, type_ident, generics, method) -} - -fn expand_deriving_clone_enum_def(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the method. - let method = expand_deriving_clone_enum_method(cx, - span, - enum_definition, - type_ident, - generics); - - // Create the implementation. - create_derived_clone_impl(cx, span, type_ident, generics, method) -} - -fn expand_deriving_clone_struct_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @method { - let self_ident = cx.ident_of(~"self"); - - // Create the new fields. - let mut fields = ~[]; - for struct_def.fields.each |struct_field| { - match struct_field.node.kind { - named_field(ident, _, _) => { - // Create the accessor for this field. - let self_field = build::mk_access(cx, - span, - ~[ self_ident ], - ident); - // Call the substructure method. - let call = call_substructure_clone_method(cx, - span, - self_field); - - let field = build::Field { ident: ident, ex: call }; - fields.push(field); - } - unnamed_field => { - cx.span_bug(span, - ~"unnamed fields in \ - expand_deriving_clone_struct_method"); + match all_fields { + [(None, _, _), .. _] => { + // enum-like + let subcalls = all_fields.map(|&(_, self_f, _)| subcall(self_f)); + build::mk_call(cx, span, ctor_ident, subcalls) + }, + _ => { + // struct-like + let fields = do all_fields.map |&(o_id, self_f, _)| { + let ident = match o_id { + Some(i) => i, + None => cx.span_bug(span, + ~"unnamed field in normal struct \ + in `deriving(Clone)`") + }; + build::Field { ident: ident, ex: subcall(self_f) } + }; + + if fields.is_empty() { + // no fields, so construct like `None` + build::mk_path(cx, span, ctor_ident) + } else { + build::mk_struct_e(cx, span, + ctor_ident, + fields) } } } - - // Create the struct literal. - let struct_literal = build::mk_struct_e(cx, - span, - ~[ type_ident ], - fields); - create_clone_method(cx, span, type_ident, generics, struct_literal) -} - -fn expand_deriving_clone_tuple_struct_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @method { - // Create the pattern for the match. - let matching_path = build::mk_raw_path(span, ~[ type_ident ]); - let field_count = struct_def.fields.len(); - let subpats = create_subpatterns(cx, span, ~"__self", field_count); - let pat = build::mk_pat_enum(cx, span, matching_path, subpats); - - // Create the new fields. - let mut subcalls = ~[]; - for uint::range(0, struct_def.fields.len()) |i| { - // Create the expression for this field. - let field_ident = cx.ident_of(~"__self" + i.to_str()); - let field = build::mk_path(cx, span, ~[ field_ident ]); - - // Call the substructure method. - let subcall = call_substructure_clone_method(cx, span, field); - subcalls.push(subcall); - } - - // Create the call to the struct constructor. - let call = build::mk_call(cx, span, ~[ type_ident ], subcalls); - - // Create the pattern body. - let match_body_block = build::mk_simple_block(cx, span, call); - - // Create the arm. - let arm = ast::arm { - pats: ~[ pat ], - guard: None, - body: match_body_block - }; - - // Create the method body. - let self_match_expr = expand_enum_or_struct_match(cx, span, ~[ arm ]); - - // Create the method. - create_clone_method(cx, span, type_ident, generics, self_match_expr) -} - -fn expand_deriving_clone_enum_method(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @method { - // Create the arms of the match in the method body. - let arms = do enum_definition.variants.map |variant| { - // Create the matching pattern. - let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); - - // Iterate over the variant arguments, creating the subcalls. - let mut subcalls = ~[]; - for uint::range(0, variant_arg_count(cx, span, variant)) |j| { - // Create the expression for this field. - let field_ident = cx.ident_of(~"__self" + j.to_str()); - let field = build::mk_path(cx, span, ~[ field_ident ]); - - // Call the substructure method. - let subcall = call_substructure_clone_method(cx, span, field); - subcalls.push(subcall); - } - - // Create the call to the enum variant (if necessary). - let call = if subcalls.len() > 0 { - build::mk_call(cx, span, ~[ variant.node.name ], subcalls) - } else { - build::mk_path(cx, span, ~[ variant.node.name ]) - }; - - // Create the pattern body. - let match_body_block = build::mk_simple_block(cx, span, call); - - // Create the arm. - ast::arm { pats: ~[ pat ], guard: None, body: match_body_block } - }; - - // Create the method body. - let self_match_expr = expand_enum_or_struct_match(cx, span, arms); - - // Create the method. - create_clone_method(cx, span, type_ident, generics, self_match_expr) } diff --git a/src/libsyntax/ext/deriving/cmp/eq.rs b/src/libsyntax/ext/deriving/cmp/eq.rs new file mode 100644 index 0000000000000..c0060cc67dc33 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/eq.rs @@ -0,0 +1,65 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use ast::{meta_item, item, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; + +use core::option::Some; + +pub fn expand_deriving_eq(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + // structures are equal if all fields are equal, and non equal, if + // any fields are not equal or if the enum variants are different + fn cs_eq(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + cs_and(|cx, span, _| build::mk_bool(cx, span, false), + cx, span, substr) + } + fn cs_ne(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + cs_or(|cx, span, _| build::mk_bool(cx, span, true), + cx, span, substr) + } + macro_rules! md ( + ($name:expr, $f:ident) => { + MethodDef { + name: $name, + output_type: Some(~[~"bool"]), + nargs: 1, + const_nonmatching: true, + combine_substructure: $f + }, + } + ) + + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"Eq"], + additional_bounds: ~[], + methods: ~[ + md!(~"eq", cs_eq), + md!(~"ne", cs_ne) + ] + }; + + 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/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs new file mode 100644 index 0000000000000..398e27eb3e385 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -0,0 +1,128 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use ast::{meta_item, item, expr_if, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; +use core::option::Some; + +macro_rules! md { + ($name:expr, $less:expr, $equal:expr) => { + MethodDef { + name: $name, + output_type: Some(~[~"bool"]), + nargs: 1, + const_nonmatching: false, + combine_substructure: |cx, span, substr| + cs_ord($less, $equal, cx, span, substr) + } + } +} + +pub fn expand_deriving_ord(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"Ord"], + // XXX: Ord doesn't imply Eq yet + additional_bounds: ~[~[~"core", ~"cmp", ~"Eq"]], + methods: ~[ + md!(~"lt", true, false), + md!(~"le", true, true), + md!(~"gt", false, false), + md!(~"ge", false, true) + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) +} + +/// `less`: is this `lt` or `le`? `equal`: is this `le` or `ge`? +fn cs_ord(less: bool, equal: bool, + cx: @ext_ctxt, span: span, + substr: &Substructure) -> @expr { + let binop = if less { + cx.ident_of(~"lt") + } else { + cx.ident_of(~"gt") + }; + let false_blk_expr = build::mk_block(cx, span, + ~[], ~[], + Some(build::mk_bool(cx, span, false))); + let true_blk = build::mk_simple_block(cx, span, + build::mk_bool(cx, span, true)); + let base = build::mk_bool(cx, span, equal); + + cs_fold( + false, // need foldr, + |cx, span, subexpr, self_f, other_fs| { + /* + + build up a series of nested ifs from the inside out to get + lexical ordering (hence foldr), i.e. + + ``` + if self.f1 `binop` other.f1 { + true + } else if self.f1 == other.f1 { + if self.f2 `binop` other.f2 { + true + } else if self.f2 == other.f2 { + `equal` + } else { + false + } + } else { + false + } + ``` + + The inner "`equal`" case is only reached if the two + items have all fields equal. + */ + if other_fs.len() != 1 { + cx.span_bug(span, "Not exactly 2 arguments in `deriving(Ord)`"); + } + + let cmp = build::mk_method_call(cx, span, + self_f, cx.ident_of(~"eq"), other_fs); + let subexpr = build::mk_simple_block(cx, span, subexpr); + let elseif = expr_if(cmp, subexpr, Some(false_blk_expr)); + let elseif = build::mk_expr(cx, span, elseif); + + let cmp = build::mk_method_call(cx, span, + self_f, binop, other_fs); + let if_ = expr_if(cmp, true_blk, Some(elseif)); + + build::mk_expr(cx, span, if_) + }, + base, + |cx, span, args| { + // nonmatching enums, order by the order the variants are + // written + match args { + [(self_var, _, _), + (other_var, _, _)] => + build::mk_bool(cx, span, + if less { + self_var < other_var + } else { + self_var > other_var + }), + _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(Ord)`") + } + }, + cx, span, substr) +} diff --git a/src/libsyntax/ext/deriving/cmp/totaleq.rs b/src/libsyntax/ext/deriving/cmp/totaleq.rs new file mode 100644 index 0000000000000..fc8ec103a6021 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/totaleq.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +use ast::{meta_item, item, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; + +use core::option::Some; + +pub fn expand_deriving_totaleq(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + + fn cs_equals(cx: @ext_ctxt, span: span, substr: &Substructure) -> @expr { + cs_and(|cx, span, _| build::mk_bool(cx, span, false), + cx, span, substr) + } + + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"TotalEq"], + additional_bounds: ~[], + methods: ~[ + MethodDef { + name: ~"equals", + output_type: Some(~[~"bool"]), + nargs: 1, + const_nonmatching: true, + combine_substructure: cs_equals + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) +} diff --git a/src/libsyntax/ext/deriving/cmp/totalord.rs b/src/libsyntax/ext/deriving/cmp/totalord.rs new file mode 100644 index 0000000000000..a098a7463d3e7 --- /dev/null +++ b/src/libsyntax/ext/deriving/cmp/totalord.rs @@ -0,0 +1,78 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ast::{meta_item, item, expr}; +use codemap::span; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::generic::*; +use core::cmp::{Ordering, Equal, Less, Greater}; +use core::option::Some; + +pub fn expand_deriving_totalord(cx: @ext_ctxt, + span: span, + mitem: @meta_item, + in_items: ~[@item]) -> ~[@item] { + let trait_def = TraitDef { + path: ~[~"core", ~"cmp", ~"TotalOrd"], + additional_bounds: ~[], + methods: ~[ + MethodDef { + name: ~"cmp", + output_type: Some(~[~"core", ~"cmp", ~"Ordering"]), + nargs: 1, + const_nonmatching: false, + combine_substructure: cs_cmp + } + ] + }; + + expand_deriving_generic(cx, span, mitem, in_items, + &trait_def) +} + + +pub fn ordering_const(cx: @ext_ctxt, span: span, cnst: Ordering) -> @expr { + let cnst = match cnst { + Less => ~"Less", + Equal => ~"Equal", + Greater => ~"Greater" + }; + build::mk_path_global(cx, span, + ~[cx.ident_of(~"core"), + cx.ident_of(~"cmp"), + cx.ident_of(cnst)]) +} + +pub fn cs_cmp(cx: @ext_ctxt, span: span, + substr: &Substructure) -> @expr { + let lexical_ord = ~[cx.ident_of(~"core"), + cx.ident_of(~"cmp"), + cx.ident_of(~"lexical_ordering")]; + + cs_same_method_fold( + // foldr (possibly) nests the matches in lexical_ordering better + false, + |cx, span, old, new| { + build::mk_call_global(cx, span, lexical_ord, ~[old, new]) + }, + ordering_const(cx, span, Equal), + |cx, span, list| { + match list { + // an earlier nonmatching variant is Less than a + // later one + [(self_var, _, _), + (other_var, _, _)] => ordering_const(cx, span, + self_var.cmp(&other_var)), + _ => cx.span_bug(span, "Not exactly 2 arguments in `deriving(TotalOrd)`") + } + }, + cx, span, substr) +} diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs new file mode 100644 index 0000000000000..df3536a3caef7 --- /dev/null +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -0,0 +1,455 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::prelude::*; + +use ast; +use ast::*; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span, spanned}; +use ast_util; +use opt_vec; + +use core::uint; + +pub fn expand_deriving_decodable( + cx: @ext_ctxt, + span: span, + _mitem: @meta_item, + in_items: ~[@item] +) -> ~[@item] { + expand_deriving( + cx, + span, + in_items, + expand_deriving_decodable_struct_def, + expand_deriving_decodable_enum_def + ) +} + +fn create_derived_decodable_impl( + cx: @ext_ctxt, + span: span, + type_ident: ident, + generics: &Generics, + method: @method +) -> @item { + let decoder_ty_param = build::mk_ty_param( + cx, + cx.ident_of(~"__D"), + @opt_vec::with( + build::mk_trait_ty_param_bound_global( + cx, + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decoder"), + ] + ) + ) + ); + + // All the type parameters need to bound to the trait. + let generic_ty_params = opt_vec::with(decoder_ty_param); + + let methods = [method]; + let trait_path = build::mk_raw_path_global_( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decodable") + ], + ~[ + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")) + ] + ); + create_derived_impl( + cx, + span, + type_ident, + generics, + methods, + trait_path, + generic_ty_params, + opt_vec::Empty + ) +} + +// Creates a method from the given set of statements conforming to the +// signature of the `decodable` method. +fn create_decode_method( + cx: @ext_ctxt, + span: span, + type_ident: ast::ident, + generics: &Generics, + expr: @ast::expr +) -> @method { + // Create the `e` parameter. + let d_arg_type = build::mk_ty_rptr( + cx, + span, + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")), + ast::m_imm + ); + let d_ident = cx.ident_of(~"__d"); + let d_arg = build::mk_arg(cx, span, d_ident, d_arg_type); + + // Create the type of the return value. + let output_type = create_self_type_with_params( + cx, + span, + type_ident, + generics + ); + + // Create the function declaration. + let inputs = ~[d_arg]; + let fn_decl = build::mk_fn_decl(inputs, output_type); + + // Create the body block. + let body_block = build::mk_simple_block(cx, span, expr); + + // Create the method. + let self_ty = spanned { node: sty_static, span: span }; + let method_ident = cx.ident_of(~"decode"); + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } +} + +fn call_substructure_decode_method( + cx: @ext_ctxt, + span: span +) -> @ast::expr { + // Call the substructure method. + build::mk_call_( + cx, + span, + build::mk_path_global( + cx, + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Decodable"), + cx.ident_of(~"decode"), + ] + ), + ~[ + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]) + ] + ) +} + +fn expand_deriving_decodable_struct_def( + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_decodable_struct_method( + cx, + span, + struct_def, + type_ident, + generics + ); + + // Create the implementation. + create_derived_decodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn expand_deriving_decodable_enum_def( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_decodable_enum_method( + cx, + span, + enum_definition, + type_ident, + generics + ); + + // Create the implementation. + create_derived_decodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn create_read_struct_field( + cx: @ext_ctxt, + span: span, + idx: uint, + ident: ident +) -> build::Field { + // Call the substructure method. + let decode_expr = call_substructure_decode_method(cx, span); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_struct_field"), + ~[ + build::mk_base_str(cx, span, cx.str_of(ident)), + build::mk_uint(cx, span, idx), + build::mk_lambda_no_args(cx, span, decode_expr), + ] + ); + + build::Field { ident: ident, ex: call_expr } +} + +fn create_read_struct_arg( + cx: @ext_ctxt, + span: span, + idx: uint, + ident: ident +) -> build::Field { + // Call the substructure method. + let decode_expr = call_substructure_decode_method(cx, span); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_struct_arg"), + ~[ + build::mk_uint(cx, span, idx), + build::mk_lambda_no_args(cx, span, decode_expr), + ] + ); + + build::Field { ident: ident, ex: call_expr } +} + +fn expand_deriving_decodable_struct_method( + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics +) -> @method { + // Create the body of the method. + let mut i = 0; + let mut fields = ~[]; + for struct_def.fields.each |struct_field| { + match struct_field.node.kind { + named_field(ident, _, _) => { + fields.push(create_read_struct_field(cx, span, i, ident)); + } + unnamed_field => { + cx.span_unimpl( + span, + ~"unnamed fields with `deriving(Decodable)`" + ); + } + } + i += 1; + } + + let read_struct_expr = build::mk_method_call( + cx, + span, + build::mk_path( + cx, + span, + ~[cx.ident_of(~"__d")] + ), + cx.ident_of(~"read_struct"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + build::mk_uint(cx, span, fields.len()), + build::mk_lambda_no_args( + cx, + span, + build::mk_struct_e( + cx, + span, + ~[type_ident], + fields + ) + ), + ] + ); + + // Create the method itself. + create_decode_method(cx, span, type_ident, generics, read_struct_expr) +} + +fn create_read_variant_arg( + cx: @ext_ctxt, + span: span, + idx: uint, + variant: &ast::variant +) -> ast::arm { + // Create the matching pattern. + let pat = build::mk_pat_lit(cx, span, build::mk_uint(cx, span, idx)); + + // Feed each argument in this variant to the decode function + // as well. + let variant_arg_len = variant_arg_count(cx, span, variant); + + let expr = if variant_arg_len == 0 { + build::mk_path(cx, span, ~[variant.node.name]) + } else { + // Feed the discriminant to the decode function. + let mut args = ~[]; + + for uint::range(0, variant_arg_len) |j| { + // Call the substructure method. + let expr = call_substructure_decode_method(cx, span); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_enum_variant_arg"), + ~[ + build::mk_uint(cx, span, j), + build::mk_lambda_no_args(cx, span, expr), + ] + ); + + args.push(call_expr); + } + + build::mk_call( + cx, + span, + ~[variant.node.name], + args + ) + }; + + // Create the arm. + build::mk_arm(cx, span, ~[pat], expr) +} + +fn create_read_enum_variant( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def +) -> @expr { + // Create a vector that contains all the variant names. + let expr_arm_names = build::mk_base_vec_e( + cx, + span, + do enum_definition.variants.map |variant| { + build::mk_base_str( + cx, + span, + cx.str_of(variant.node.name) + ) + } + ); + + // Create the arms of the match in the method body. + let mut arms = do enum_definition.variants.mapi |i, variant| { + create_read_variant_arg(cx, span, i, variant) + }; + + // Add the impossible case arm. + arms.push(build::mk_unreachable_arm(cx, span)); + + // Create the read_enum_variant expression. + build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_enum_variant"), + ~[ + expr_arm_names, + build::mk_lambda( + cx, + span, + build::mk_fn_decl( + ~[ + build::mk_arg( + cx, + span, + cx.ident_of(~"__i"), + build::mk_ty_infer(cx, span) + ) + ], + build::mk_ty_infer(cx, span) + ), + build::mk_expr( + cx, + span, + ast::expr_match( + build::mk_path(cx, span, ~[cx.ident_of(~"__i")]), + arms + ) + ) + ) + ] + ) +} + +fn expand_deriving_decodable_enum_method( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ast::ident, + generics: &Generics +) -> @method { + let read_enum_variant_expr = create_read_enum_variant( + cx, + span, + enum_definition + ); + + // Create the read_enum expression + let read_enum_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__d")]), + cx.ident_of(~"read_enum"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + build::mk_lambda_no_args(cx, span, read_enum_variant_expr), + ] + ); + + // Create the method. + create_decode_method(cx, span, type_ident, generics, read_enum_expr) +} diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs new file mode 100644 index 0000000000000..9776f484818cc --- /dev/null +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -0,0 +1,389 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::prelude::*; + +use ast; +use ast::*; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span, spanned}; +use ast_util; +use opt_vec; + +use core::uint; + +pub fn expand_deriving_encodable( + cx: @ext_ctxt, + span: span, + _mitem: @meta_item, + in_items: ~[@item] +) -> ~[@item] { + expand_deriving( + cx, + span, + in_items, + expand_deriving_encodable_struct_def, + expand_deriving_encodable_enum_def + ) +} + +fn create_derived_encodable_impl( + cx: @ext_ctxt, + span: span, + type_ident: ident, + generics: &Generics, + method: @method +) -> @item { + let encoder_ty_param = build::mk_ty_param( + cx, + cx.ident_of(~"__E"), + @opt_vec::with( + build::mk_trait_ty_param_bound_global( + cx, + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Encoder"), + ] + ) + ) + ); + + // All the type parameters need to bound to the trait. + let generic_ty_params = opt_vec::with(encoder_ty_param); + + let methods = [method]; + let trait_path = build::mk_raw_path_global_( + span, + ~[ + cx.ident_of(~"std"), + cx.ident_of(~"serialize"), + cx.ident_of(~"Encodable") + ], + ~[ + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")) + ] + ); + create_derived_impl( + cx, + span, + type_ident, + generics, + methods, + trait_path, + generic_ty_params, + opt_vec::Empty + ) +} + +// Creates a method from the given set of statements conforming to the +// signature of the `encodable` method. +fn create_encode_method( + cx: @ext_ctxt, + span: span, + +statements: ~[@stmt] +) -> @method { + // Create the `e` parameter. + let e_arg_type = build::mk_ty_rptr( + cx, + span, + build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")), + ast::m_imm + ); + let e_ident = cx.ident_of(~"__e"); + let e_arg = build::mk_arg(cx, span, e_ident, e_arg_type); + + // Create the type of the return value. + let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span }; + + // Create the function declaration. + let inputs = ~[e_arg]; + let fn_decl = build::mk_fn_decl(inputs, output_type); + + // Create the body block. + let body_block = build::mk_block_(cx, span, statements); + + // Create the method. + let self_ty = spanned { node: sty_region(None, m_imm), span: span }; + let method_ident = cx.ident_of(~"encode"); + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } +} + +fn call_substructure_encode_method( + cx: @ext_ctxt, + span: span, + self_field: @expr +) -> @ast::expr { + // Gather up the parameters we want to chain along. + let e_ident = cx.ident_of(~"__e"); + let e_expr = build::mk_path(cx, span, ~[e_ident]); + + // Call the substructure method. + let encode_ident = cx.ident_of(~"encode"); + build::mk_method_call( + cx, + span, + self_field, + encode_ident, + ~[e_expr] + ) +} + +fn expand_deriving_encodable_struct_def( + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_encodable_struct_method( + cx, + span, + type_ident, + struct_def + ); + + // Create the implementation. + create_derived_encodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn expand_deriving_encodable_enum_def( + cx: @ext_ctxt, + span: span, + enum_definition: &enum_def, + type_ident: ident, + generics: &Generics +) -> @item { + // Create the method. + let method = expand_deriving_encodable_enum_method( + cx, + span, + type_ident, + enum_definition + ); + + // Create the implementation. + create_derived_encodable_impl( + cx, + span, + type_ident, + generics, + method + ) +} + +fn expand_deriving_encodable_struct_method( + cx: @ext_ctxt, + span: span, + type_ident: ident, + struct_def: &struct_def +) -> @method { + let self_ident = cx.ident_of(~"self"); + + // Create the body of the method. + let mut idx = 0; + let mut statements = ~[]; + for struct_def.fields.each |struct_field| { + match struct_field.node.kind { + named_field(ident, _, _) => { + // Create the accessor for this field. + let self_field = build::mk_access( + cx, + span, + ~[self_ident], + ident + ); + + // Call the substructure method. + let encode_expr = call_substructure_encode_method( + cx, + span, + self_field + ); + + let blk_expr = build::mk_lambda( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + encode_expr + ); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_struct_field"), + ~[ + build::mk_base_str(cx, span, cx.str_of(ident)), + build::mk_uint(cx, span, idx), + blk_expr + ] + ); + + statements.push(build::mk_stmt(cx, span, call_expr)); + } + unnamed_field => { + cx.span_unimpl( + span, + ~"unnamed fields with `deriving(Encodable)`" + ); + } + } + idx += 1; + } + + let emit_struct_stmt = build::mk_method_call( + cx, + span, + build::mk_path( + cx, + span, + ~[cx.ident_of(~"__e")] + ), + cx.ident_of(~"emit_struct"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + build::mk_uint(cx, span, statements.len()), + build::mk_lambda_stmts( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + statements + ), + ] + ); + + let statements = ~[build::mk_stmt(cx, span, emit_struct_stmt)]; + + // Create the method itself. + return create_encode_method(cx, span, statements); +} + +fn expand_deriving_encodable_enum_method( + cx: @ext_ctxt, + span: span, + type_ident: ast::ident, + enum_definition: &enum_def +) -> @method { + // Create the arms of the match in the method body. + let arms = do enum_definition.variants.mapi |i, variant| { + // Create the matching pattern. + let pat = create_enum_variant_pattern(cx, span, variant, ~"__self"); + + // Feed the discriminant to the encode function. + let mut stmts = ~[]; + + // Feed each argument in this variant to the encode function + // as well. + let variant_arg_len = variant_arg_count(cx, span, variant); + for uint::range(0, variant_arg_len) |j| { + // Create the expression for this field. + let field_ident = cx.ident_of(~"__self_" + j.to_str()); + let field = build::mk_path(cx, span, ~[ field_ident ]); + + // Call the substructure method. + let expr = call_substructure_encode_method(cx, span, field); + + let blk_expr = build::mk_lambda( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + expr + ); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_enum_variant_arg"), + ~[ + build::mk_uint(cx, span, j), + blk_expr, + ] + ); + + stmts.push(build::mk_stmt(cx, span, call_expr)); + } + + // Create the pattern body. + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_enum_variant"), + ~[ + build::mk_base_str(cx, span, cx.str_of(variant.node.name)), + build::mk_uint(cx, span, i), + build::mk_uint(cx, span, variant_arg_len), + build::mk_lambda_stmts( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + stmts + ) + ] + ); + + let match_body_block = build::mk_simple_block(cx, span, call_expr); + + // Create the arm. + ast::arm { + pats: ~[pat], + guard: None, + body: match_body_block, + } + }; + + // Create the method body. + let lambda_expr = build::mk_lambda( + cx, + span, + build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + expand_enum_or_struct_match(cx, span, arms) + ); + + let call_expr = build::mk_method_call( + cx, + span, + build::mk_path(cx, span, ~[cx.ident_of(~"__e")]), + cx.ident_of(~"emit_enum"), + ~[ + build::mk_base_str(cx, span, cx.str_of(type_ident)), + lambda_expr, + ] + ); + + let stmt = build::mk_stmt(cx, span, call_expr); + + // Create the method. + create_encode_method(cx, span, ~[stmt]) +} diff --git a/src/libsyntax/ext/deriving/eq.rs b/src/libsyntax/ext/deriving/eq.rs deleted file mode 100644 index 07b2835d44cdf..0000000000000 --- a/src/libsyntax/ext/deriving/eq.rs +++ /dev/null @@ -1,498 +0,0 @@ -// Copyright 2012-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use core::prelude::*; - -use ast; -use ast::*; -use ext::base::ext_ctxt; -use ext::build; -use ext::deriving::*; -use codemap::{span, spanned}; -use ast_util; - -use core::uint; - -enum Junction { - Conjunction, - Disjunction, -} - -pub impl Junction { - fn to_binop(self) -> binop { - match self { - Conjunction => and, - Disjunction => or, - } - } -} - -pub fn expand_deriving_eq(cx: @ext_ctxt, - span: span, - _mitem: @meta_item, - in_items: ~[@item]) - -> ~[@item] { - expand_deriving(cx, - span, - in_items, - expand_deriving_eq_struct_def, - expand_deriving_eq_enum_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 -} - -/// Creates a method from the given expression, the signature of which -/// conforms to the `eq` or `ne` method. -fn create_eq_method(cx: @ext_ctxt, - span: span, - method_ident: ident, - type_ident: ident, - generics: &Generics, - body: @expr) - -> @method { - // Create the type of the `other` parameter. - let arg_path_type = create_self_type_with_params(cx, - span, - type_ident, - generics); - let arg_type = ty_rptr( - None, - ast::mt { ty: arg_path_type, mutbl: m_imm } - ); - let arg_type = @ast::Ty { - id: cx.next_id(), - node: arg_type, - span: span, - }; - - // Create the `other` parameter. - let other_ident = cx.ident_of(~"__other"); - let arg = build::mk_arg(cx, span, other_ident, arg_type); - - // Create the type of the return value. - let bool_ident = cx.ident_of(~"bool"); - let output_type = build::mk_raw_path(span, ~[ bool_ident ]); - let output_type = ty_path(output_type, cx.next_id()); - let output_type = @ast::Ty { - id: cx.next_id(), - node: output_type, - span: span, - }; - - // Create the function declaration. - let fn_decl = build::mk_fn_decl(~[ arg ], output_type); - - // Create the body block. - let body_block = build::mk_simple_block(cx, span, body); - - // Create the method. - let self_ty = spanned { node: sty_region(None, m_imm), span: span }; - @ast::method { - ident: method_ident, - attrs: ~[], - generics: ast_util::empty_generics(), - self_ty: self_ty, - purity: impure_fn, - decl: fn_decl, - body: body_block, - id: cx.next_id(), - span: span, - self_id: cx.next_id(), - vis: public - } -} - -fn create_derived_eq_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - eq_method: @method, - ne_method: @method) - -> @item { - let methods = [ eq_method, ne_method ]; - let trait_path = [ - cx.ident_of(~"core"), - cx.ident_of(~"cmp"), - cx.ident_of(~"Eq") - ]; - create_derived_impl(cx, span, type_ident, generics, methods, trait_path) -} - -fn call_substructure_eq_method(cx: @ext_ctxt, - span: span, - self_field: @expr, - other_field_ref: @expr, - method_ident: ident, - junction: Junction, - chain_expr: &mut Option<@expr>) { - // Call the substructure method. - let self_call = build::mk_method_call(cx, span, - self_field, method_ident, - ~[ other_field_ref ]); - - // Connect to the outer expression if necessary. - *chain_expr = match *chain_expr { - None => Some(self_call), - Some(copy old_outer_expr) => { - let binop = junction.to_binop(); - let chain_expr = build::mk_binary(cx, - span, - binop, - old_outer_expr, - self_call); - Some(chain_expr) - } - }; -} - -fn finish_eq_chain_expr(cx: @ext_ctxt, - span: span, - chain_expr: Option<@expr>, - junction: Junction) - -> @expr { - match chain_expr { - None => { - match junction { - Conjunction => build::mk_bool(cx, span, true), - Disjunction => build::mk_bool(cx, span, false), - } - } - Some(ref outer_expr) => *outer_expr, - } -} - -fn expand_deriving_eq_struct_def(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the methods. - let eq_ident = cx.ident_of(~"eq"); - let ne_ident = cx.ident_of(~"ne"); - - let derive_struct_fn = if is_struct_tuple(struct_def) { - expand_deriving_eq_struct_tuple_method - } else { - expand_deriving_eq_struct_method - }; - - let eq_method = derive_struct_fn(cx, - span, - struct_def, - eq_ident, - type_ident, - generics, - Conjunction); - let ne_method = derive_struct_fn(cx, - span, - struct_def, - ne_ident, - type_ident, - generics, - Disjunction); - - // Create the implementation. - return create_derived_eq_impl(cx, - span, - type_ident, - generics, - eq_method, - ne_method); -} - -fn expand_deriving_eq_enum_def(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - type_ident: ident, - generics: &Generics) - -> @item { - // Create the methods. - let eq_ident = cx.ident_of(~"eq"); - let ne_ident = cx.ident_of(~"ne"); - let eq_method = expand_deriving_eq_enum_method(cx, - span, - enum_definition, - eq_ident, - type_ident, - generics, - Conjunction); - let ne_method = expand_deriving_eq_enum_method(cx, - span, - enum_definition, - ne_ident, - type_ident, - generics, - Disjunction); - - // Create the implementation. - return create_derived_eq_impl(cx, - span, - type_ident, - generics, - eq_method, - ne_method); -} - -fn expand_deriving_eq_struct_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - method_ident: ident, - type_ident: ident, - generics: &Generics, - junction: Junction) - -> @method { - let self_ident = cx.ident_of(~"self"); - let other_ident = cx.ident_of(~"__other"); - - // Create the body of the method. - let mut outer_expr = None; - for struct_def.fields.each |struct_field| { - match struct_field.node.kind { - named_field(ident, _, _) => { - // Create the accessor for the other field. - let other_field = build::mk_access(cx, - span, - ~[ other_ident ], - ident); - let other_field_ref = build::mk_addr_of(cx, - span, - other_field); - - // Create the accessor for this field. - let self_field = build::mk_access(cx, - span, - ~[ self_ident ], - ident); - - // Call the substructure method. - call_substructure_eq_method(cx, - span, - self_field, - other_field_ref, - method_ident, - junction, - &mut outer_expr); - } - unnamed_field => { - cx.span_unimpl(span, ~"unnamed fields with `deriving_eq`"); - } - } - } - - // Create the method itself. - let body = finish_eq_chain_expr(cx, span, outer_expr, junction); - return create_eq_method(cx, - span, - method_ident, - type_ident, - generics, - body); -} - -fn expand_deriving_eq_enum_method(cx: @ext_ctxt, - span: span, - enum_definition: &enum_def, - method_ident: ident, - type_ident: ident, - generics: &Generics, - junction: Junction) - -> @method { - let self_ident = cx.ident_of(~"self"); - let other_ident = cx.ident_of(~"__other"); - - let is_eq; - match junction { - Conjunction => is_eq = true, - Disjunction => is_eq = false, - } - - // Create the arms of the self match in the method body. - let mut self_arms = ~[]; - for enum_definition.variants.each |self_variant| { - let mut other_arms = ~[]; - - // Create the matching pattern. - let matching_pat = create_enum_variant_pattern(cx, - span, - self_variant, - ~"__other"); - - // Create the matching pattern body. - let mut matching_body_expr = None; - for uint::range(0, variant_arg_count(cx, span, self_variant)) |i| { - // Create the expression for the other field. - let other_field_ident = cx.ident_of(~"__other" + i.to_str()); - let other_field = build::mk_path(cx, - span, - ~[ other_field_ident ]); - - // Create the expression for this field. - let self_field_ident = cx.ident_of(~"__self" + i.to_str()); - let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); - - // Call the substructure method. - call_substructure_eq_method(cx, - span, - self_field, - other_field, - method_ident, - junction, - &mut matching_body_expr); - } - - let matching_body_expr = finish_eq_chain_expr(cx, - span, - matching_body_expr, - junction); - let matching_body_block = build::mk_simple_block(cx, - span, - matching_body_expr); - - // Create the matching arm. - let matching_arm = ast::arm { - pats: ~[ matching_pat ], - guard: None, - body: matching_body_block - }; - other_arms.push(matching_arm); - - // Maybe generate a non-matching case. If there is only one - // variant then there will always be a match. - if enum_definition.variants.len() > 1 { - // Create the nonmatching pattern. - let nonmatching_pat = @ast::pat { - id: cx.next_id(), - node: pat_wild, - span: span - }; - - // Create the nonmatching pattern body. - let nonmatching_expr = build::mk_bool(cx, span, !is_eq); - let nonmatching_body_block = - build::mk_simple_block(cx, - span, - nonmatching_expr); - - // Create the nonmatching arm. - let nonmatching_arm = ast::arm { - pats: ~[ nonmatching_pat ], - guard: None, - body: nonmatching_body_block, - }; - other_arms.push(nonmatching_arm); - } - - // Create the self pattern. - let self_pat = create_enum_variant_pattern(cx, - span, - self_variant, - ~"__self"); - - // Create the self pattern body. - let other_expr = build::mk_path(cx, span, ~[ other_ident ]); - let other_expr = build::mk_unary(cx, span, deref, other_expr); - let other_match_expr = expr_match(other_expr, other_arms); - let other_match_expr = build::mk_expr(cx, - span, - other_match_expr); - let other_match_body_block = build::mk_simple_block(cx, - span, - other_match_expr); - - // Create the self arm. - let self_arm = ast::arm { - pats: ~[ self_pat ], - guard: None, - body: other_match_body_block, - }; - self_arms.push(self_arm); - } - - // Create the method body. - let self_expr = build::mk_path(cx, span, ~[ self_ident ]); - let self_expr = build::mk_unary(cx, span, deref, self_expr); - let self_match_expr = expr_match(self_expr, self_arms); - let self_match_expr = build::mk_expr(cx, span, self_match_expr); - - // Create the method. - return create_eq_method(cx, - span, - method_ident, - type_ident, - generics, - self_match_expr); -} - -fn expand_deriving_eq_struct_tuple_method(cx: @ext_ctxt, - span: span, - struct_def: &struct_def, - method_ident: ident, - type_ident: ident, - generics: &Generics, - junction: Junction) - -> @method { - let self_str = ~"self"; - let other_str = ~"__other"; - let type_path = build::mk_raw_path(span, ~[type_ident]); - let fields = copy struct_def.fields; - - // Create comparison expression, comparing each of the fields - let mut match_body = None; - for fields.eachi |i, _| { - let other_field_ident = cx.ident_of(other_str + i.to_str()); - let other_field = build::mk_path(cx, span, ~[ other_field_ident ]); - - let self_field_ident = cx.ident_of(self_str + i.to_str()); - let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); - - call_substructure_eq_method(cx, span, self_field, other_field, - method_ident, junction, &mut match_body); - } - let match_body = finish_eq_chain_expr(cx, span, match_body, junction); - - // Create arm for the '__other' match, containing the comparison expr - let other_subpats = create_subpatterns(cx, span, other_str, fields.len()); - let other_arm = ast::arm { - pats: ~[ build::mk_pat_enum(cx, span, type_path, other_subpats) ], - guard: None, - body: build::mk_simple_block(cx, span, match_body), - }; - - // Create the match on '__other' - let other_expr = build::mk_path(cx, span, ~[ cx.ident_of(other_str) ]); - let other_expr = build::mk_unary(cx, span, deref, other_expr); - let other_match_expr = expr_match(other_expr, ~[other_arm]); - let other_match_expr = build::mk_expr(cx, span, other_match_expr); - - // Create arm for the 'self' match, which contains the '__other' match - let self_subpats = create_subpatterns(cx, span, self_str, fields.len()); - let self_arm = ast::arm { - pats: ~[build::mk_pat_enum(cx, span, type_path, self_subpats)], - guard: None, - body: build::mk_simple_block(cx, span, other_match_expr), - }; - - // Create the match on 'self' - let self_expr = build::mk_path(cx, span, ~[ cx.ident_of(self_str) ]); - let self_expr = build::mk_unary(cx, span, deref, self_expr); - let self_match_expr = expr_match(self_expr, ~[self_arm]); - let self_match_expr = build::mk_expr(cx, span, self_match_expr); - - create_eq_method(cx, span, method_ident, - type_ident, generics, self_match_expr) -} diff --git a/src/libsyntax/ext/deriving/generic.rs b/src/libsyntax/ext/deriving/generic.rs new file mode 100644 index 0000000000000..dfbb98fa23388 --- /dev/null +++ b/src/libsyntax/ext/deriving/generic.rs @@ -0,0 +1,906 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +Some code that abstracts away much of the boilerplate of writing +`deriving` instances for traits. Among other things it manages getting +access to the fields of the 4 different sorts of structs and enum +variants, as well as creating the method and impl ast instances. + +Supported features (fairly exhaustive): +- Methods taking any number of parameters of type `&Self`, including + none other than `self`. (`MethodDef.nargs`) +- Methods returning `Self` or a non-parameterised type + (e.g. `bool` or `core::cmp::Ordering`). (`MethodDef.output_type`) +- Generating `impl`s for types with type parameters + (e.g. `Option`), the parameters are automatically given the + current trait as a bound. +- Additional bounds on the type parameters, e.g. the `Ord` instance + requires an explicit `Eq` bound at the + moment. (`TraitDef.additional_bounds`) + +(Key unsupported things: methods with arguments of non-`&Self` type, +traits with parameters, methods returning parameterised types, static +methods.) + +The most important thing for implementers is the `Substructure` and +`SubstructureFields` objects. The latter groups 3 possibilities of the +arguments: + +- `Struct`, when `Self` is a struct (including tuple structs, e.g + `struct T(int, char)`). +- `EnumMatching`, when `Self` is an enum and all the arguments are the + same variant of the enum (e.g. `Some(1)`, `Some(3)` and `Some(4)`) +- `EnumNonMatching` when `Self` is an enum and the arguments are not + the same variant (e.g. `None`, `Some(1)` and `None`). If + `const_nonmatching` is true, this will contain an empty list. + +In the first two cases, the values from the corresponding fields in +all the arguments are grouped together. In the `EnumNonMatching` case +this isn't possible (different variants have different fields), so the +fields are grouped by which argument they come from. + +All of the cases have `Option` in several places associated +with field `expr`s. This represents the name of the field it is +associated with. It is only not `None` when the associated field has +an identifier in the source code. For example, the `x`s in the +following snippet + + struct A { x : int } + + struct B(int); + + enum C { + C0(int), + C1 { x: int } + } + +The `int`s in `B` and `C0` don't have an identifier, so the +`Option`s would be `None` for them. + +# Examples + +The following simplified `Eq` is used for in-code examples: + + trait Eq { + fn eq(&self, other: &Self); + } + impl Eq for int { + fn eq(&self, other: &int) -> bool { + *self == *other + } + } + +Some examples of the values of `SubstructureFields` follow, using the +above `Eq`, `A`, `B` and `C`. + +## Structs + +When generating the `expr` for the `A` impl, the `SubstructureFields` is + + Struct(~[(Some(), + , + ~[ + ~[])]) + +## Enums + +When generating the `expr` for a call with `self == C0(a)` and `other +== C0(b)`, the SubstructureFields is + + EnumMatching(0, , + ~[None, + , + ~[]]) + +For `C1 {x}` and `C1 {x}`, + + EnumMatching(1, , + ~[Some(), + , + ~[]]) + +For `C0(a)` and `C1 {x}` , + + EnumNonMatching(~[(0, , + ~[(None, )]), + (1, , + ~[(Some(), + )])]) + +(and vice verse, but with the order of the outermost list flipped.) + +*/ + +use core::prelude::*; + +use ast; + +use ast::{ + and, binop, deref, enum_def, expr, expr_match, ident, impure_fn, + item, Generics, m_imm, meta_item, method, named_field, or, + pat_wild, public, struct_def, sty_region, ty_rptr, ty_path, + variant}; + +use ast_util; +use ext::base::ext_ctxt; +use ext::build; +use ext::deriving::*; +use codemap::{span,respan}; +use opt_vec; + +pub fn expand_deriving_generic(cx: @ext_ctxt, + span: span, + _mitem: @meta_item, + in_items: ~[@item], + trait_def: &TraitDef) -> ~[@item] { + let expand_enum: ExpandDerivingEnumDefFn = + |cx, span, enum_def, type_ident, generics| { + trait_def.expand_enum_def(cx, span, enum_def, type_ident, generics) + }; + let expand_struct: ExpandDerivingStructDefFn = + |cx, span, struct_def, type_ident, generics| { + trait_def.expand_struct_def(cx, span, struct_def, type_ident, generics) + }; + + expand_deriving(cx, span, in_items, + expand_struct, + expand_enum) +} + +pub struct TraitDef<'self> { + /// Path of the trait + path: ~[~str], + /// Additional bounds required of any type parameters, other than + /// the current trait + additional_bounds: ~[~[~str]], + methods: ~[MethodDef<'self>] +} + +pub struct MethodDef<'self> { + /// name of the method + name: ~str, + /// The path of return type of the method, e.g. `~[~"core", + /// ~"cmp", ~"Eq"]`. `None` for `Self`. + output_type: Option<~[~str]>, + /// Number of arguments other than `self` (all of type `&Self`) + nargs: uint, + + /// if the value of the nonmatching enums is independent of the + /// actual enums, i.e. can use _ => .. match. + const_nonmatching: bool, + + combine_substructure: CombineSubstructureFunc<'self> +} + +/// All the data about the data structure/method being derived upon. +pub struct Substructure<'self> { + type_ident: ident, + method_ident: ident, + fields: &'self SubstructureFields +} + +/// A summary of the possible sets of fields. See above for details +/// and examples +pub enum SubstructureFields { + /** + Vec of `(field ident, self, [others])` where the field ident is + the ident of the current field (`None` for all fields in tuple + structs) + */ + Struct(~[(Option, @expr, ~[@expr])]), + + /** + Matching variants of the enum: variant index, ast::variant, + fields: `(field ident, self, [others])`, where the field ident is + only non-`None` in the case of a struct variant. + */ + EnumMatching(uint, variant, ~[(Option, @expr, ~[@expr])]), + + /** + non-matching variants of the enum, [(variant index, ast::variant, + [field ident, fields])] (i.e. all fields for self are in the + first tuple, for other1 are in the second tuple, etc.) + */ + EnumNonMatching(~[(uint, variant, ~[(Option, @expr)])]) +} + + +/** +Combine the values of all the fields together. The last argument is +all the fields of all the structures, see above for details. +*/ +pub type CombineSubstructureFunc<'self> = + &'self fn(@ext_ctxt, span, &Substructure) -> @expr; + +/** +Deal with non-matching enum variants, the argument is a list +representing each variant: (variant index, ast::variant instance, +[variant fields]) +*/ +pub type EnumNonMatchFunc<'self> = + &'self fn(@ext_ctxt, span, ~[(uint, variant, ~[(Option, @expr)])]) -> @expr; + + + +impl<'self> TraitDef<'self> { + fn create_derived_impl(&self, cx: @ext_ctxt, span: span, + type_ident: ident, generics: &Generics, + methods: ~[@method]) -> @item { + let trait_path = build::mk_raw_path_global( + span, + do self.path.map |&s| { cx.ident_of(s) }); + + let additional_bounds = opt_vec::from( + do self.additional_bounds.map |v| { + do v.map |&s| { cx.ident_of(s) } + }); + create_derived_impl(cx, span, + type_ident, generics, + methods, trait_path, + opt_vec::Empty, + additional_bounds) + } + + fn expand_struct_def(&self, cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident, + generics: &Generics) + -> @item { + let is_tuple = is_struct_tuple(struct_def); + + let methods = do self.methods.map |method_def| { + let body = if is_tuple { + method_def.expand_struct_tuple_method_body(cx, span, + struct_def, + type_ident) + } else { + method_def.expand_struct_method_body(cx, span, + struct_def, + type_ident) + }; + + method_def.create_method(cx, span, type_ident, generics, body) + }; + + self.create_derived_impl(cx, span, type_ident, generics, methods) + } + + fn expand_enum_def(&self, + cx: @ext_ctxt, span: span, + enum_def: &enum_def, + type_ident: ident, + generics: &Generics) -> @item { + let methods = do self.methods.map |method_def| { + let body = method_def.expand_enum_method_body(cx, span, + enum_def, + type_ident); + + method_def.create_method(cx, span, type_ident, generics, body) + }; + + self.create_derived_impl(cx, span, type_ident, generics, methods) + } +} + +impl<'self> MethodDef<'self> { + fn call_substructure_method(&self, + cx: @ext_ctxt, + span: span, + type_ident: ident, + fields: &SubstructureFields) + -> @expr { + let substructure = Substructure { + type_ident: type_ident, + method_ident: cx.ident_of(self.name), + fields: fields + }; + (self.combine_substructure)(cx, span, + &substructure) + } + + fn get_output_type_path(&self, cx: @ext_ctxt, span: span, + generics: &Generics, type_ident: ident) -> @ast::Path { + match self.output_type { + None => { // Self, add any type parameters + let out_ty_params = do vec::build |push| { + for generics.ty_params.each |ty_param| { + push(build::mk_ty_path(cx, span, ~[ ty_param.ident ])); + } + }; + + build::mk_raw_path_(span, ~[ type_ident ], out_ty_params) + } + Some(str_path) => { + let p = do str_path.map |&s| { cx.ident_of(s) }; + build::mk_raw_path_global(span, p) + } + } + } + + fn create_method(&self, cx: @ext_ctxt, span: span, + type_ident: ident, + generics: &Generics, body: @expr) -> @method { + // Create the `Self` type of the `other` parameters. + let arg_path_type = create_self_type_with_params(cx, + span, + type_ident, + generics); + let arg_type = ty_rptr( + None, + ast::mt { ty: arg_path_type, mutbl: m_imm } + ); + let arg_type = @ast::Ty { + id: cx.next_id(), + node: arg_type, + span: span, + }; + + // create the arguments + let other_idents = create_other_idents(cx, self.nargs); + let args = do other_idents.map |&id| { + build::mk_arg(cx, span, id, arg_type) + }; + + let output_type = self.get_output_type_path(cx, span, generics, type_ident); + let output_type = ty_path(output_type, cx.next_id()); + let output_type = @ast::Ty { + id: cx.next_id(), + node: output_type, + span: span, + }; + + let method_ident = cx.ident_of(self.name); + let fn_decl = build::mk_fn_decl(args, output_type); + let body_block = build::mk_simple_block(cx, span, body); + + // Create the method. + let self_ty = respan(span, sty_region(None, m_imm)); + @ast::method { + ident: method_ident, + attrs: ~[], + generics: ast_util::empty_generics(), + self_ty: self_ty, + purity: impure_fn, + decl: fn_decl, + body: body_block, + id: cx.next_id(), + span: span, + self_id: cx.next_id(), + vis: public + } + } + + /** + ``` + #[deriving(Eq)] + struct A(int, int); + + // equivalent to: + + impl Eq for A { + fn eq(&self, __other_1: &A) -> bool { + match *self { + (ref self_1, ref self_2) => { + match *__other_1 { + (ref __other_1_1, ref __other_1_2) => { + self_1.eq(__other_1_1) && self_2.eq(__other_1_2) + } + } + } + } + } + } + ``` + */ + fn expand_struct_tuple_method_body(&self, + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident) -> @expr { + let self_str = ~"self"; + let other_strs = create_other_strs(self.nargs); + let num_fields = struct_def.fields.len(); + + + let fields = do struct_def.fields.mapi |i, _| { + let other_fields = do other_strs.map |&other_str| { + let other_field_ident = cx.ident_of(fmt!("%s_%u", other_str, i)); + build::mk_path(cx, span, ~[ other_field_ident ]) + }; + + let self_field_ident = cx.ident_of(fmt!("%s_%u", self_str, i)); + let self_field = build::mk_path(cx, span, ~[ self_field_ident ]); + + (None, self_field, other_fields) + }; + + let mut match_body = self.call_substructure_method(cx, span, type_ident, &Struct(fields)); + + let type_path = build::mk_raw_path(span, ~[type_ident]); + + // create the matches from inside to out (i.e. other_{self.nargs} to other_1) + for other_strs.each_reverse |&other_str| { + match_body = create_deref_match(cx, span, type_path, + other_str, num_fields, + match_body) + } + + // create the match on self + return create_deref_match(cx, span, type_path, + ~"self", num_fields, match_body); + + /** + Creates a match expression against a tuple that needs to + be dereferenced, but nothing else + + ``` + match *`to_match` { + (`to_match`_1, ..., `to_match`_`num_fields`) => `match_body` + } + ``` + */ + fn create_deref_match(cx: @ext_ctxt, + span: span, + type_path: @ast::Path, + to_match: ~str, + num_fields: uint, + match_body: @expr) -> @expr { + let match_subpats = create_subpatterns(cx, span, to_match, num_fields); + let match_arm = ast::arm { + pats: ~[ build::mk_pat_enum(cx, span, type_path, match_subpats) ], + guard: None, + body: build::mk_simple_block(cx, span, match_body), + }; + + let deref_expr = build::mk_unary(cx, span, deref, + build::mk_path(cx, span, + ~[ cx.ident_of(to_match)])); + let match_expr = build::mk_expr(cx, span, expr_match(deref_expr, ~[match_arm])); + + match_expr + } + } + + /** + ``` + #[deriving(Eq)] + struct A { x: int, y: int } + + // equivalent to: + + impl Eq for A { + fn eq(&self, __other_1: &A) -> bool { + self.x.eq(&__other_1.x) && + self.y.eq(&__other_1.y) + } + } + ``` + */ + fn expand_struct_method_body(&self, + cx: @ext_ctxt, + span: span, + struct_def: &struct_def, + type_ident: ident) + -> @expr { + let self_ident = cx.ident_of(~"self"); + let other_idents = create_other_idents(cx, self.nargs); + + let fields = do struct_def.fields.map |struct_field| { + match struct_field.node.kind { + named_field(ident, _, _) => { + // Create the accessor for this field in the other args. + let other_fields = do other_idents.map |&id| { + build::mk_access(cx, span, ~[id], ident) + }; + let other_field_refs = do other_fields.map |&other_field| { + build::mk_addr_of(cx, span, other_field) + }; + + // Create the accessor for this field in self. + let self_field = + build::mk_access( + cx, span, + ~[ self_ident ], + ident); + + (Some(ident), self_field, other_field_refs) + } + unnamed_field => { + cx.span_unimpl(span, ~"unnamed fields with `deriving_generic`"); + } + } + }; + + self.call_substructure_method(cx, span, type_ident, &Struct(fields)) + } + + /** + ``` + #[deriving(Eq)] + enum A { + A1 + A2(int) + } + + // is equivalent to + + impl Eq for A { + fn eq(&self, __other_1: &A) { + match *self { + A1 => match *__other_1 { + A1 => true, + A2(ref __other_1_1) => false + }, + A2(self_1) => match *__other_1 { + A1 => false, + A2(ref __other_1_1) => self_1.eq(__other_1_1) + } + } + } + } + ``` + */ + fn expand_enum_method_body(&self, + cx: @ext_ctxt, + span: span, + enum_def: &enum_def, + type_ident: ident) + -> @expr { + self.build_enum_match(cx, span, enum_def, type_ident, + None, ~[], 0) + } + + + /** + Creates the nested matches for an enum definition recursively, i.e. + + ``` + match self { + Variant1 => match other { Variant1 => matching, Variant2 => nonmatching, ... }, + Variant2 => match other { Variant1 => nonmatching, Variant2 => matching, ... }, + ... + } + ``` + + It acts in the most naive way, so every branch (and subbranch, + subsubbranch, etc) exists, not just the ones where all the variants in + the tree are the same. Hopefully the optimisers get rid of any + repetition, otherwise derived methods with many Self arguments will be + exponentially large. + + `matching` is Some(n) if all branches in the tree above the + current position are variant `n`, `None` otherwise (including on + the first call). + */ + fn build_enum_match(&self, + cx: @ext_ctxt, span: span, + enum_def: &enum_def, + type_ident: ident, + matching: Option, + matches_so_far: ~[(uint, variant, + ~[(Option, @expr)])], + match_count: uint) -> @expr { + if match_count == self.nargs + 1 { + // we've matched against all arguments, so make the final + // expression at the bottom of the match tree + match matches_so_far { + [] => cx.bug(~"no self match on an enum in `deriving_generic`"), + _ => { + // we currently have a vec of vecs, where each + // subvec is the fields of one of the arguments, + // but if the variants all match, we want this as + // vec of tuples, where each tuple represents a + // field. + + let substructure; + + // most arms don't have matching variants, so do a + // quick check to see if they match (even though + // this means iterating twice) instead of being + // optimistic and doing a pile of allocations etc. + match matching { + Some(variant_index) => { + // `ref` inside let matches is buggy. Causes havoc wih rusc. + // let (variant_index, ref self_vec) = matches_so_far[0]; + let (variant, self_vec) = match matches_so_far[0] { + (_, v, ref s) => (v, s) + }; + + let mut enum_matching_fields = vec::from_elem(self_vec.len(), ~[]); + + for matches_so_far.tail().each |&(_, _, other_fields)| { + for other_fields.eachi |i, &(_, other_field)| { + enum_matching_fields[i].push(other_field); + } + } + let field_tuples = + do vec::map2(*self_vec, + enum_matching_fields) |&(id, self_f), &other| { + (id, self_f, other) + }; + substructure = EnumMatching(variant_index, variant, field_tuples); + } + None => { + substructure = EnumNonMatching(matches_so_far); + } + } + self.call_substructure_method(cx, span, type_ident, &substructure) + } + } + + } else { // there are still matches to create + let (current_match_ident, current_match_str) = if match_count == 0 { + (cx.ident_of(~"self"), ~"__self") + } else { + let s = fmt!("__other_%u", matches_so_far.len() - 1); + (cx.ident_of(s), s) + }; + + let mut arms = ~[]; + + // this is used as a stack + let mut matches_so_far = matches_so_far; + + macro_rules! mk_arm( + ($pat:expr, $expr:expr) => { + { + let blk = build::mk_simple_block(cx, span, $expr); + let arm = ast::arm { + pats: ~[$ pat ], + guard: None, + body: blk + }; + arm + } + } + ) + + // the code for nonmatching variants only matters when + // we've seen at least one other variant already + if self.const_nonmatching && match_count > 0 { + // make a matching-variant match, and a _ match. + let index = match matching { + Some(i) => i, + None => cx.span_bug(span, ~"Non-matching variants when required to\ + be matching in `deriving_generic`") + }; + + // matching-variant match + let variant = &enum_def.variants[index]; + let pattern = create_enum_variant_pattern(cx, span, + variant, + current_match_str); + + let idents = do vec::build |push| { + for each_variant_arg_ident(cx, span, variant) |i, field_id| { + let id = cx.ident_of(fmt!("%s_%u", current_match_str, i)); + push((field_id, build::mk_path(cx, span, ~[ id ]))); + } + }; + + matches_so_far.push((index, *variant, idents)); + let arm_expr = self.build_enum_match(cx, span, + enum_def, + type_ident, + matching, + matches_so_far, + match_count + 1); + matches_so_far.pop(); + let arm = mk_arm!(pattern, arm_expr); + arms.push(arm); + + if enum_def.variants.len() > 1 { + // _ match, if necessary + let wild_pat = @ast::pat { + id: cx.next_id(), + node: pat_wild, + span: span + }; + + let wild_expr = self.call_substructure_method(cx, span, type_ident, + &EnumNonMatching(~[])); + let wild_arm = mk_arm!(wild_pat, wild_expr); + arms.push(wild_arm); + } + } else { + // create an arm matching on each variant + for enum_def.variants.eachi |index, variant| { + let pattern = create_enum_variant_pattern(cx, span, + variant, + current_match_str); + + let idents = do vec::build |push| { + for each_variant_arg_ident(cx, span, variant) |i, field_id| { + let id = cx.ident_of(fmt!("%s_%u", current_match_str, i)); + push((field_id, build::mk_path(cx, span, ~[ id ]))); + } + }; + + matches_so_far.push((index, *variant, idents)); + let new_matching = + match matching { + _ if match_count == 0 => Some(index), + Some(i) if index == i => Some(i), + _ => None + }; + let arm_expr = self.build_enum_match(cx, span, + enum_def, + type_ident, + new_matching, + matches_so_far, + match_count + 1); + matches_so_far.pop(); + + let arm = mk_arm!(pattern, arm_expr); + arms.push(arm); + } + } + let deref_expr = build::mk_unary(cx, span, deref, + build::mk_path(cx, span, + ~[ current_match_ident ])); + let match_expr = build::mk_expr(cx, span, + expr_match(deref_expr, arms)); + + match_expr + } + } +} + +/// Create variable names (as strings) to refer to the non-self +/// parameters +fn create_other_strs(n: uint) -> ~[~str] { + do vec::build |push| { + for uint::range(0, n) |i| { + push(fmt!("__other_%u", i)); + } + } +} +/// Like `create_other_strs`, but returns idents for the strings +fn create_other_idents(cx: @ext_ctxt, n: uint) -> ~[ident] { + do create_other_strs(n).map |&s| { + cx.ident_of(s) + } +} + + + +/* helpful premade recipes */ + +/** +Fold the fields. `use_foldl` controls whether this is done +left-to-right (`true`) or right-to-left (`false`). +*/ +pub fn cs_fold(use_foldl: bool, + f: &fn(@ext_ctxt, span, + old: @expr, + self_f: @expr, other_fs: ~[@expr]) -> @expr, + base: @expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: @ext_ctxt, span: span, + substructure: &Substructure) -> @expr { + match *substructure.fields { + EnumMatching(_, _, all_fields) | Struct(all_fields) => { + if use_foldl { + do all_fields.foldl(base) |&old, &(_, self_f, other_fs)| { + f(cx, span, old, self_f, other_fs) + } + } else { + do all_fields.foldr(base) |&(_, self_f, other_fs), old| { + f(cx, span, old, self_f, other_fs) + } + } + }, + EnumNonMatching(all_enums) => enum_nonmatch_f(cx, span, all_enums) + } +} + + +/** +Call the method that is being derived on all the fields, and then +process the collected results. i.e. + +``` +f(cx, span, ~[self_1.method(__other_1_1, __other_2_1), + self_2.method(__other_1_2, __other_2_2)]) +``` +*/ +pub fn cs_same_method(f: &fn(@ext_ctxt, span, ~[@expr]) -> @expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: @ext_ctxt, span: span, + substructure: &Substructure) -> @expr { + match *substructure.fields { + EnumMatching(_, _, all_fields) | Struct(all_fields) => { + // call self_n.method(other_1_n, other_2_n, ...) + let called = do all_fields.map |&(_, self_field, other_fields)| { + build::mk_method_call(cx, span, + self_field, + substructure.method_ident, + other_fields) + }; + + f(cx, span, called) + }, + EnumNonMatching(all_enums) => enum_nonmatch_f(cx, span, all_enums) + } +} + +/** +Fold together the results of calling the derived method on all the +fields. `use_foldl` controls whether this is done left-to-right +(`true`) or right-to-left (`false`). +*/ +pub fn cs_same_method_fold(use_foldl: bool, + f: &fn(@ext_ctxt, span, @expr, @expr) -> @expr, + base: @expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: @ext_ctxt, span: span, + substructure: &Substructure) -> @expr { + cs_same_method( + |cx, span, vals| { + if use_foldl { + do vals.foldl(base) |&old, &new| { + f(cx, span, old, new) + } + } else { + do vals.foldr(base) |&new, old| { + f(cx, span, old, new) + } + } + }, + enum_nonmatch_f, + cx, span, substructure) + +} + +/** +Use a given binop to combine the result of calling the derived method +on all the fields. +*/ +pub fn cs_binop(binop: binop, base: @expr, + enum_nonmatch_f: EnumNonMatchFunc, + cx: @ext_ctxt, span: span, + substructure: &Substructure) -> @expr { + cs_same_method_fold( + true, // foldl is good enough + |cx, span, old, new| { + build::mk_binary(cx, span, + binop, + old, new) + + }, + base, + enum_nonmatch_f, + cx, span, substructure) +} + +/// cs_binop with binop == or +pub fn cs_or(enum_nonmatch_f: EnumNonMatchFunc, + cx: @ext_ctxt, span: span, + substructure: &Substructure) -> @expr { + cs_binop(or, build::mk_bool(cx, span, false), + enum_nonmatch_f, + cx, span, substructure) +} +/// cs_binop with binop == and +pub fn cs_and(enum_nonmatch_f: EnumNonMatchFunc, + cx: @ext_ctxt, span: span, + substructure: &Substructure) -> @expr { + cs_binop(and, build::mk_bool(cx, span, true), + enum_nonmatch_f, + cx, span, substructure) +} diff --git a/src/libsyntax/ext/deriving/iter_bytes.rs b/src/libsyntax/ext/deriving/iter_bytes.rs index e2a43591ef026..75215b90eb0da 100644 --- a/src/libsyntax/ext/deriving/iter_bytes.rs +++ b/src/libsyntax/ext/deriving/iter_bytes.rs @@ -17,6 +17,7 @@ use ext::build; use ext::deriving::*; use codemap::{span, spanned}; use ast_util; +use opt_vec; use core::uint; @@ -49,12 +50,14 @@ fn create_derived_iter_bytes_impl(cx: @ext_ctxt, method: @method) -> @item { let methods = [ method ]; - let trait_path = [ + let trait_path = ~[ cx.ident_of(~"core"), cx.ident_of(~"to_bytes"), cx.ident_of(~"IterBytes") ]; - create_derived_impl(cx, span, type_ident, generics, methods, trait_path) + let trait_path = build::mk_raw_path_global(span, trait_path); + create_derived_impl(cx, span, type_ident, generics, methods, trait_path, + opt_vec::Empty, opt_vec::Empty) } // Creates a method from the given set of statements conforming to the @@ -191,7 +194,7 @@ fn expand_deriving_iter_bytes_struct_method(cx: @ext_ctxt, } unnamed_field => { cx.span_unimpl(span, - ~"unnamed fields with `deriving_iter_bytes`"); + ~"unnamed fields with `deriving(IterBytes)`"); } } } @@ -228,7 +231,7 @@ fn expand_deriving_iter_bytes_enum_method(cx: @ext_ctxt, // as well. for uint::range(0, variant_arg_count(cx, span, variant)) |j| { // Create the expression for this field. - let field_ident = cx.ident_of(~"__self" + j.to_str()); + let field_ident = cx.ident_of(~"__self_" + j.to_str()); let field = build::mk_path(cx, span, ~[ field_ident ]); // Call the substructure method. diff --git a/src/libsyntax/ext/deriving/mod.rs b/src/libsyntax/ext/deriving/mod.rs index 18ebceaeb4396..78faf5556b2ce 100644 --- a/src/libsyntax/ext/deriving/mod.rs +++ b/src/libsyntax/ext/deriving/mod.rs @@ -14,7 +14,7 @@ use core::prelude::*; use ast; -use ast::{TraitTyParamBound, Ty, bind_by_ref, deref, enum_def}; +use ast::{Ty, bind_by_ref, deref, enum_def}; use ast::{expr, expr_match, ident, item, item_}; use ast::{item_enum, item_impl, item_struct, Generics}; use ast::{m_imm, meta_item, method}; @@ -24,28 +24,41 @@ use ast::{tuple_variant_kind}; use ast::{ty_path, unnamed_field, variant}; use ext::base::ext_ctxt; use ext::build; -use codemap::span; +use codemap::{span, respan}; use parse::token::special_idents::clownshoes_extensions; use opt_vec; use core::uint; pub mod clone; -pub mod eq; pub mod iter_bytes; +pub mod encodable; +pub mod decodable; + +#[path="cmp/eq.rs"] +pub mod eq; +#[path="cmp/totaleq.rs"] +pub mod totaleq; +#[path="cmp/ord.rs"] +pub mod ord; +#[path="cmp/totalord.rs"] +pub mod totalord; + -type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt, - span, - x: &struct_def, - ident, - y: &Generics) - -> @item; -type ExpandDerivingEnumDefFn<'self> = &'self fn(@ext_ctxt, - span, - x: &enum_def, - ident, - y: &Generics) - -> @item; +pub mod generic; + +pub type ExpandDerivingStructDefFn<'self> = &'self fn(@ext_ctxt, + span, + x: &struct_def, + ident, + y: &Generics) + -> @item; +pub type ExpandDerivingEnumDefFn<'self> = &'self fn(@ext_ctxt, + span, + x: &enum_def, + ident, + y: &Generics) + -> @item; pub fn expand_meta_deriving(cx: @ext_ctxt, _span: span, @@ -72,10 +85,20 @@ pub fn expand_meta_deriving(cx: @ext_ctxt, match *tname { ~"Clone" => clone::expand_deriving_clone(cx, titem.span, titem, in_items), - ~"Eq" => eq::expand_deriving_eq(cx, titem.span, - titem, in_items), ~"IterBytes" => iter_bytes::expand_deriving_iter_bytes(cx, titem.span, titem, in_items), + ~"Encodable" => encodable::expand_deriving_encodable(cx, + titem.span, titem, in_items), + ~"Decodable" => decodable::expand_deriving_decodable(cx, + titem.span, titem, in_items), + ~"Eq" => eq::expand_deriving_eq(cx, titem.span, + titem, in_items), + ~"TotalEq" => totaleq::expand_deriving_totaleq(cx, titem.span, + titem, in_items), + ~"Ord" => ord::expand_deriving_ord(cx, titem.span, + titem, in_items), + ~"TotalOrd" => totalord::expand_deriving_totalord(cx, titem.span, + titem, in_items), tname => { cx.span_err(titem.span, fmt!("unknown \ `deriving` trait: `%s`", tname)); @@ -120,9 +143,19 @@ pub fn expand_deriving(cx: @ext_ctxt, } fn create_impl_item(cx: @ext_ctxt, span: span, +item: item_) -> @item { + let doc_attr = respan(span, + ast::lit_str(@~"Automatically derived.")); + let doc_attr = respan(span, ast::meta_name_value(@~"doc", doc_attr)); + let doc_attr = ast::attribute_ { + style: ast::attr_outer, + value: @doc_attr, + is_sugared_doc: false + }; + let doc_attr = respan(span, doc_attr); + @ast::item { ident: clownshoes_extensions, - attrs: ~[], + attrs: ~[doc_attr], id: cx.next_id(), node: item, vis: public, @@ -153,18 +186,22 @@ pub fn create_self_type_with_params(cx: @ext_ctxt, } pub fn create_derived_impl(cx: @ext_ctxt, - span: span, - type_ident: ident, - generics: &Generics, - methods: &[@method], - trait_path: &[ident]) - -> @item { + span: span, + type_ident: ident, + generics: &Generics, + methods: &[@method], + trait_path: @ast::Path, + mut impl_ty_params: opt_vec::OptVec, + bounds_paths: opt_vec::OptVec<~[ident]>) + -> @item { /*! * * Given that we are deriving a trait `Tr` for a type `T<'a, ..., * 'z, A, ..., Z>`, creates an impl like: * - * impl<'a, ..., 'z, A:Tr, ..., Z: Tr> Tr for T { ... } + * impl<'a, ..., 'z, A:Tr B1 B2, ..., Z: Tr B1 B2> Tr for T { ... } + * + * where B1, B2, ... are the bounds given by `bounds_paths`. * * FIXME(#5090): Remove code duplication between this and the * code in auto_encode.rs @@ -176,28 +213,20 @@ pub fn create_derived_impl(cx: @ext_ctxt, }); // Create the type parameters. - let impl_ty_params = generics.ty_params.map(|ty_param| { - let bound = build::mk_ty_path_global(cx, - span, - trait_path.map(|x| *x)); - let bounds = @opt_vec::with(TraitTyParamBound(bound)); - build::mk_ty_param(cx, ty_param.ident, bounds) - }); + for generics.ty_params.each |ty_param| { + let mut bounds = do bounds_paths.map |&bound_path| { + build::mk_trait_ty_param_bound_global(cx, span, bound_path) + }; + + let this_trait_bound = + build::mk_trait_ty_param_bound_(cx, trait_path); + bounds.push(this_trait_bound); + + impl_ty_params.push(build::mk_ty_param(cx, ty_param.ident, @bounds)); + } // Create the reference to the trait. - let trait_path = ast::path { - span: span, - global: true, - idents: trait_path.map(|x| *x), - rp: None, - types: ~[] - }; - let trait_path = @trait_path; - let trait_ref = ast::trait_ref { - path: trait_path, - ref_id: cx.next_id() - }; - let trait_ref = @trait_ref; + let trait_ref = build::mk_trait_ref_(cx, trait_path); // Create the type of `self`. let self_type = create_self_type_with_params(cx, @@ -222,8 +251,8 @@ pub fn create_subpatterns(cx: @ext_ctxt, let mut subpats = ~[]; for uint::range(0, n) |_i| { // Create the subidentifier. - let index = subpats.len().to_str(); - let ident = cx.ident_of(prefix + index); + let index = subpats.len(); + let ident = cx.ident_of(fmt!("%s_%u", prefix, index)); // Create the subpattern. let subpath = build::mk_raw_path(span, ~[ ident ]); @@ -293,6 +322,29 @@ pub fn variant_arg_count(_cx: @ext_ctxt, _span: span, variant: &variant) -> uint } } +/// Iterate through the idents of the variant arguments. The field is +/// unnamed (i.e. it's not a struct-like enum), then `None`. +pub fn each_variant_arg_ident(_cx: @ext_ctxt, _span: span, + variant: &variant, it: &fn(uint, Option) -> bool) { + match variant.node.kind { + tuple_variant_kind(ref args) => { + for uint::range(0, args.len()) |i| { + if !it(i, None) { break } + } + } + struct_variant_kind(ref struct_def) => { + for struct_def.fields.eachi |i, f| { + let id = match f.node.kind { + named_field(ident, _, _) => Some(ident), + unnamed_field => None + }; + if !it(i, id) { break } + } + } + } +} + + pub fn expand_enum_or_struct_match(cx: @ext_ctxt, span: span, arms: ~[ ast::arm ]) diff --git a/src/libsyntax/ext/pipes/ast_builder.rs b/src/libsyntax/ext/pipes/ast_builder.rs index 1d1a101d61f1d..5eea58b89b1c6 100644 --- a/src/libsyntax/ext/pipes/ast_builder.rs +++ b/src/libsyntax/ext/pipes/ast_builder.rs @@ -34,16 +34,16 @@ mod syntax { pub use parse; } -pub fn path(+ids: ~[ident], span: span) -> @ast::path { - @ast::path { span: span, +pub fn path(+ids: ~[ident], span: span) -> @ast::Path { + @ast::Path { span: span, global: false, idents: ids, rp: None, types: ~[] } } -pub fn path_global(+ids: ~[ident], span: span) -> @ast::path { - @ast::path { span: span, +pub fn path_global(+ids: ~[ident], span: span) -> @ast::Path { + @ast::Path { span: span, global: true, idents: ids, rp: None, @@ -51,20 +51,20 @@ pub fn path_global(+ids: ~[ident], span: span) -> @ast::path { } pub trait append_types { - fn add_ty(&self, ty: @ast::Ty) -> @ast::path; - fn add_tys(&self, +tys: ~[@ast::Ty]) -> @ast::path; + fn add_ty(&self, ty: @ast::Ty) -> @ast::Path; + fn add_tys(&self, +tys: ~[@ast::Ty]) -> @ast::Path; } -impl append_types for @ast::path { - fn add_ty(&self, ty: @ast::Ty) -> @ast::path { - @ast::path { +impl append_types for @ast::Path { + fn add_ty(&self, ty: @ast::Ty) -> @ast::Path { + @ast::Path { types: vec::append_one(copy self.types, ty), .. copy **self } } - fn add_tys(&self, +tys: ~[@ast::Ty]) -> @ast::path { - @ast::path { + fn add_tys(&self, +tys: ~[@ast::Ty]) -> @ast::Path { + @ast::Path { types: vec::append(copy self.types, tys), .. copy **self } @@ -108,7 +108,7 @@ pub trait ext_ctxt_ast_builder { span: span, +struct_def: ast::struct_def) -> @ast::item; fn struct_expr(&self, - path: @ast::path, + path: @ast::Path, +fields: ~[ast::field]) -> @ast::expr; fn variant(&self, name: ident, @@ -118,7 +118,7 @@ pub trait ext_ctxt_ast_builder { name: ident, span: span, +items: ~[@ast::item]) -> @ast::item; - fn ty_path_ast_builder(&self, path: @ast::path) -> @ast::Ty; + fn ty_path_ast_builder(&self, path: @ast::Path) -> @ast::Ty; fn item_ty_poly(&self, name: ident, span: span, @@ -328,7 +328,7 @@ impl ext_ctxt_ast_builder for @ext_ctxt { self.item(name, span, ast::item_struct(@struct_def, generics)) } - fn struct_expr(&self, path: @ast::path, + fn struct_expr(&self, path: @ast::Path, +fields: ~[ast::field]) -> @ast::expr { @ast::expr { id: self.next_id(), @@ -397,7 +397,7 @@ impl ext_ctxt_ast_builder for @ext_ctxt { ) } - fn ty_path_ast_builder(&self, path: @ast::path) -> @ast::Ty { + fn ty_path_ast_builder(&self, path: @ast::Path) -> @ast::Ty { @ast::Ty { id: self.next_id(), node: ast::ty_path(path, self.next_id()), diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index f74fbbc3c03f7..afb7e04a53204 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -20,7 +20,7 @@ use parse::token::{Token, EOF, to_str, nonterminal}; use parse::token; use core::prelude::*; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; /* This is an Earley-like parser, without support for in-grammar nonterminals, only by calling out to the main rust parser for named nonterminals (which it @@ -186,9 +186,9 @@ pub enum named_match { pub type earley_item = ~MatcherPos; pub fn nameize(p_s: @mut ParseSess, ms: ~[matcher], res: ~[@named_match]) - -> LinearMap { + -> HashMap { fn n_rec(p_s: @mut ParseSess, m: matcher, res: ~[@named_match], - ret_val: &mut LinearMap) { + ret_val: &mut HashMap) { match m { codemap::spanned {node: match_tok(_), _} => (), codemap::spanned {node: match_seq(ref more_ms, _, _, _, _), _} => { @@ -207,13 +207,13 @@ pub fn nameize(p_s: @mut ParseSess, ms: ~[matcher], res: ~[@named_match]) } } } - let mut ret_val = LinearMap::new(); + let mut ret_val = HashMap::new(); for ms.each() |m| { n_rec(p_s, *m, res, &mut ret_val) } return ret_val; } pub enum parse_result { - success(LinearMap), + success(HashMap), failure(codemap::span, ~str), error(codemap::span, ~str) } @@ -223,7 +223,7 @@ pub fn parse_or_else( +cfg: ast::crate_cfg, rdr: @reader, ms: ~[matcher] -) -> LinearMap { +) -> HashMap { match parse(sess, cfg, rdr, ms) { success(m) => m, failure(sp, str) => sess.span_diagnostic.span_fatal(sp, str), diff --git a/src/libsyntax/ext/tt/transcribe.rs b/src/libsyntax/ext/tt/transcribe.rs index 67c2f438269d8..f39f3a01328ba 100644 --- a/src/libsyntax/ext/tt/transcribe.rs +++ b/src/libsyntax/ext/tt/transcribe.rs @@ -18,7 +18,7 @@ use ext::tt::macro_parser::{named_match, matched_seq, matched_nonterminal}; use parse::token::{EOF, INTERPOLATED, IDENT, Token, nt_ident, ident_interner}; use parse::lexer::TokenAndSpan; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::option; use core::vec; @@ -26,7 +26,7 @@ use core::vec; `~` */ ///an unzipping of `token_tree`s struct TtFrame { - readme: @mut ~[ast::token_tree], + forest: @mut ~[ast::token_tree], idx: uint, dotdotdoted: bool, sep: Option, @@ -37,9 +37,9 @@ pub struct TtReader { sp_diag: @span_handler, interner: @ident_interner, // the unzipped tree: - cur: @mut TtFrame, + stack: @mut TtFrame, /* for MBE-style macro transcription */ - interpolations: LinearMap, + interpolations: HashMap, repeat_idx: ~[uint], repeat_len: ~[uint], /* cached: */ @@ -52,21 +52,21 @@ pub struct TtReader { * should) be none. */ pub fn new_tt_reader(sp_diag: @span_handler, itr: @ident_interner, - interp: Option>, + interp: Option>, +src: ~[ast::token_tree]) -> @mut TtReader { let r = @mut TtReader { sp_diag: sp_diag, interner: itr, - cur: @mut TtFrame { - readme: @mut src, + stack: @mut TtFrame { + forest: @mut src, idx: 0u, dotdotdoted: false, sep: None, up: option::None }, interpolations: match interp { /* just a convienience */ - None => LinearMap::new(), + None => HashMap::new(), Some(x) => x }, repeat_idx: ~[], @@ -81,7 +81,7 @@ pub fn new_tt_reader(sp_diag: @span_handler, fn dup_tt_frame(f: @mut TtFrame) -> @mut TtFrame { @mut TtFrame { - readme: @mut (copy *f.readme), + forest: @mut (copy *f.forest), idx: f.idx, dotdotdoted: f.dotdotdoted, sep: copy f.sep, @@ -96,7 +96,7 @@ pub fn dup_tt_reader(r: @mut TtReader) -> @mut TtReader { @mut TtReader { sp_diag: r.sp_diag, interner: r.interner, - cur: dup_tt_frame(r.cur), + stack: dup_tt_frame(r.stack), interpolations: r.interpolations, repeat_idx: copy r.repeat_idx, repeat_len: copy r.repeat_len, @@ -167,7 +167,8 @@ fn lockstep_iter_size(t: token_tree, r: &mut TtReader) -> lis { } } - +// return the next token from the TtReader. +// EFFECT: advances the reader's token field pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { let ret_val = TokenAndSpan { tok: copy r.cur_tok, @@ -175,37 +176,37 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { }; loop { { - let cur = &mut *r.cur; - let readme = &mut *cur.readme; - if cur.idx < readme.len() { + let stack = &mut *r.stack; + let forest = &mut *stack.forest; + if stack.idx < forest.len() { break; } } /* done with this set; pop or repeat? */ - if ! r.cur.dotdotdoted + if ! r.stack.dotdotdoted || { *r.repeat_idx.last() == *r.repeat_len.last() - 1 } { - match r.cur.up { + match r.stack.up { None => { r.cur_tok = EOF; return ret_val; } Some(tt_f) => { - if r.cur.dotdotdoted { + if r.stack.dotdotdoted { r.repeat_idx.pop(); r.repeat_len.pop(); } - r.cur = tt_f; - r.cur.idx += 1u; + r.stack = tt_f; + r.stack.idx += 1u; } } } else { /* repeat */ - r.cur.idx = 0u; + r.stack.idx = 0u; r.repeat_idx[r.repeat_idx.len() - 1u] += 1u; - match r.cur.sep { + match r.stack.sep { Some(copy tk) => { r.cur_tok = tk; /* repeat same span, I guess */ return ret_val; @@ -216,21 +217,21 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { } loop { /* because it's easiest, this handles `tt_delim` not starting with a `tt_tok`, even though it won't happen */ - match r.cur.readme[r.cur.idx] { + match r.stack.forest[r.stack.idx] { tt_delim(copy tts) => { - r.cur = @mut TtFrame { - readme: @mut tts, + r.stack = @mut TtFrame { + forest: @mut tts, idx: 0u, dotdotdoted: false, sep: None, - up: option::Some(r.cur) + up: option::Some(r.stack) }; // if this could be 0-length, we'd need to potentially recur here } tt_tok(sp, copy tok) => { r.cur_span = sp; r.cur_tok = tok; - r.cur.idx += 1u; + r.stack.idx += 1u; return ret_val; } tt_seq(sp, copy tts, copy sep, zerok) => { @@ -256,17 +257,17 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { once"); } - r.cur.idx += 1u; + r.stack.idx += 1u; return tt_next_token(r); } else { r.repeat_len.push(len); r.repeat_idx.push(0u); - r.cur = @mut TtFrame { - readme: @mut tts, + r.stack = @mut TtFrame { + forest: @mut tts, idx: 0u, dotdotdoted: true, sep: sep, - up: Some(r.cur) + up: Some(r.stack) }; } } @@ -280,13 +281,13 @@ pub fn tt_next_token(r: &mut TtReader) -> TokenAndSpan { (b) we actually can, since it's a token. */ matched_nonterminal(nt_ident(sn,b)) => { r.cur_span = sp; r.cur_tok = IDENT(sn,b); - r.cur.idx += 1u; + r.stack.idx += 1u; return ret_val; } matched_nonterminal(ref other_whole_nt) => { r.cur_span = sp; r.cur_tok = INTERPOLATED(copy *other_whole_nt); - r.cur.idx += 1u; + r.stack.idx += 1u; return ret_val; } matched_seq(*) => { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0a473b1cebeaf..768dba2141250 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -36,7 +36,7 @@ pub trait ast_fold { fn fold_foreign_mod(@self, &foreign_mod) -> foreign_mod; fn fold_variant(@self, &variant) -> variant; fn fold_ident(@self, ident) -> ident; - fn fold_path(@self, @path) -> @path; + fn fold_path(@self, @Path) -> @Path; fn fold_local(@self, @local) -> @local; fn map_exprs(@self, @fn(@expr) -> @expr, &[@expr]) -> ~[@expr]; fn new_id(@self, node_id) -> node_id; @@ -65,7 +65,7 @@ pub struct AstFoldFns { fold_foreign_mod: @fn(&foreign_mod, @ast_fold) -> foreign_mod, fold_variant: @fn(&variant_, span, @ast_fold) -> (variant_, span), fold_ident: @fn(ident, @ast_fold) -> ident, - fold_path: @fn(@path, @ast_fold) -> path, + fold_path: @fn(@Path, @ast_fold) -> Path, fold_local: @fn(&local_, span, @ast_fold) -> (local_, span), map_exprs: @fn(@fn(@expr) -> @expr, &[@expr]) -> ~[@expr], new_id: @fn(node_id) -> node_id, @@ -134,7 +134,7 @@ pub fn fold_fn_decl(decl: &ast::fn_decl, fld: @ast_fold) -> ast::fn_decl { fn fold_ty_param_bound(tpb: &TyParamBound, fld: @ast_fold) -> TyParamBound { match *tpb { - TraitTyParamBound(ty) => TraitTyParamBound(fld.fold_ty(ty)), + TraitTyParamBound(ty) => TraitTyParamBound(fold_trait_ref(ty, fld)), RegionTyParamBound => RegionTyParamBound } } @@ -702,8 +702,8 @@ fn noop_fold_ident(i: ident, _fld: @ast_fold) -> ident { /* FIXME (#2543) */ copy i } -fn noop_fold_path(p: @path, fld: @ast_fold) -> path { - ast::path { +fn noop_fold_path(p: @Path, fld: @ast_fold) -> Path { + ast::Path { span: fld.new_span(p.span), global: p.global, idents: p.idents.map(|x| fld.fold_ident(*x)), @@ -851,7 +851,7 @@ impl ast_fold for AstFoldFns { fn fold_ident(@self, x: ident) -> ident { (self.fold_ident)(x, self as @ast_fold) } - fn fold_path(@self, x: @path) -> @path { + fn fold_path(@self, x: @Path) -> @Path { @(self.fold_path)(x, self as @ast_fold) } fn fold_local(@self, x: @local) -> @local { diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 67c3d19dd0fb7..1604c40f91763 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -61,6 +61,7 @@ impl OptVec { } } + #[cfg(stage0)] fn get(&self, i: uint) -> &'self T { match *self { Empty => fail!(fmt!("Invalid index %u", i)), @@ -68,6 +69,16 @@ impl OptVec { } } + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn get<'a>(&'a self, i: uint) -> &'a T { + match *self { + Empty => fail!(fmt!("Invalid index %u", i)), + Vec(ref v) => &v[i] + } + } + fn is_empty(&self) -> bool { self.len() == 0 } @@ -102,6 +113,16 @@ impl OptVec { self.push(copy *e); } } + + #[inline(always)] + fn mapi_to_vec(&self, op: &fn(uint, &T) -> B) -> ~[B] { + let mut index = 0; + iter::map_to_vec(self, |a| { + let i = index; + index += 1; + op(i, a) + }) + } } impl Eq for OptVec { diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index c14c7bed1399f..ae7dd8ff96fce 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -159,6 +159,9 @@ 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 { self.require_keyword(word); let is_kw = match *self.token { @@ -169,6 +172,9 @@ pub impl Parser { is_kw } + // 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) { self.require_keyword(word); if !self.eat_keyword(word) { @@ -182,10 +188,12 @@ 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) } + // signal an error if the current token is a strict keyword fn check_strict_keywords(&self) { match *self.token { token::IDENT(_, false) => { @@ -196,16 +204,19 @@ pub impl Parser { } } + // signal an error if the given string is a strict keyword fn check_strict_keywords_(&self, w: &~str) { if self.is_strict_keyword(w) { self.fatal(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) } + // signal an error if the current token is a reserved keyword fn check_reserved_keywords(&self) { match *self.token { token::IDENT(_, false) => { @@ -216,6 +227,7 @@ pub impl Parser { } } + // signal an error if the given string is a reserved keyword fn check_reserved_keywords_(&self, w: &~str) { if self.is_reserved_keyword(w) { self.fatal(fmt!("`%s` is a reserved keyword", *w)); @@ -223,7 +235,8 @@ pub impl Parser { } // expect and consume a GT. if a >> is seen, replace it - // with a single > and continue. + // with a single > and continue. If a GT is not seen, + // signal an error. fn expect_gt(&self) { if *self.token == token::GT { self.bump(); diff --git a/src/libsyntax/parse/eval.rs b/src/libsyntax/parse/eval.rs deleted file mode 100644 index 5d44db084d600..0000000000000 --- a/src/libsyntax/parse/eval.rs +++ /dev/null @@ -1,174 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use parser::Parser; -use attr::parser_attr; -use codemap::{span, mk_sp}; - -type ctx = - @{sess: parse::parse_sess, - cfg: ast::crate_cfg}; - -fn eval_crate_directives(cx: ctx, - cdirs: ~[@ast::crate_directive], - prefix: &Path, - view_items: &mut~[@ast::view_item], - items: &mut~[@ast::item]) { - for cdirs.each |sub_cdir| { - eval_crate_directive(cx, *sub_cdir, prefix, view_items, items); - } -} - -pub fn eval_crate_directives_to_mod(cx: ctx, cdirs: ~[@ast::crate_directive], - prefix: &Path, suffix: &Option) - -> (ast::_mod, ~[ast::attribute]) { - let (cview_items, citems, cattrs) - = parse_companion_mod(cx, prefix, suffix); - let mut view_items: ~[@ast::view_item] = ~[]; - let mut items: ~[@ast::item] = ~[]; - eval_crate_directives(cx, cdirs, prefix, &mut view_items, &mut items); - return ({view_items: vec::append(view_items, cview_items), - items: vec::append(items, citems)}, - cattrs); -} - -/* -The 'companion mod'. So .rc crates and directory mod crate directives define -modules but not a .rs file to fill those mods with stuff. The companion mod is -a convention for location a .rs file to go with them. For .rc files the -companion mod is a .rs file with the same name; for directory mods the -companion mod is a .rs file with the same name as the directory. - -We build the path to the companion mod by combining the prefix and the -optional suffix then adding the .rs extension. -*/ -fn parse_companion_mod(cx: ctx, prefix: &Path, suffix: &Option) - -> (~[@ast::view_item], ~[@ast::item], ~[ast::attribute]) { - - fn companion_file(prefix: &Path, suffix: &Option) -> Path { - return match *suffix { - option::Some(s) => prefix.push_many(s.components), - option::None => copy *prefix - }.with_filetype("rs"); - } - - fn file_exists(path: &Path) -> bool { - // Crude, but there's no lib function for this and I'm not - // up to writing it just now - match io::file_reader(path) { - result::Ok(_) => true, - result::Err(_) => false - } - } - - let modpath = &companion_file(prefix, suffix); - if file_exists(modpath) { - debug!("found companion mod"); - // XXX: Using a dummy span, but this code will go away soon - let p0 = new_sub_parser_from_file(cx.sess, cx.cfg, - modpath, - codemap::dummy_sp()); - let (inner, next) = p0.parse_inner_attrs_and_next(); - let m0 = p0.parse_mod_items(token::EOF, next); - return (m0.view_items, m0.items, inner); - } else { - return (~[], ~[], ~[]); - } -} - -fn cdir_path_opt(default: ~str, attrs: ~[ast::attribute]) -> ~str { - match ::attr::first_attr_value_str_by_name(attrs, ~"path") { - Some(d) => d, - None => default - } -} - -pub fn eval_src_mod(cx: ctx, prefix: &Path, - outer_attrs: ~[ast::attribute], - id: ast::ident, sp: span) - -> (ast::item_, ~[ast::attribute]) { - let file_path = Path(cdir_path_opt( - cx.sess.interner.get(id) + ~".rs", outer_attrs)); - eval_src_mod_from_path(cx, prefix, &file_path, outer_attrs, sp) -} - -pub fn eval_src_mod_from_path(cx: ctx, prefix: &Path, path: &Path, - outer_attrs: ~[ast::attribute], - sp: span) - -> (ast::item_, ~[ast::attribute]) { - let full_path = if path.is_absolute { - copy *path - } else { - prefix.push_many(path.components) - }; - let p0 = - new_sub_parser_from_file(cx.sess, cx.cfg, - &full_path, sp); - let (inner, next) = p0.parse_inner_attrs_and_next(); - let mod_attrs = vec::append(outer_attrs, inner); - let first_item_outer_attrs = next; - let m0 = p0.parse_mod_items(token::EOF, first_item_outer_attrs); - return (ast::item_mod(m0), mod_attrs); -} - -// XXX: Duplicated from parser.rs -fn mk_item(ctx: ctx, lo: BytePos, hi: BytePos, +ident: ast::ident, - +node: ast::item_, vis: ast::visibility, - +attrs: ~[ast::attribute]) -> @ast::item { - return @{ident: ident, - attrs: attrs, - id: next_node_id(ctx.sess), - node: node, - vis: vis, - span: mk_sp(lo, hi)}; -} - -fn eval_crate_directive(cx: ctx, cdir: @ast::crate_directive, prefix: &Path, - view_items: &mut ~[@ast::view_item], - items: &mut ~[@ast::item]) { - match cdir.node { - ast::cdir_src_mod(vis, id, attrs) => { - let (m, mod_attrs) = eval_src_mod(cx, prefix, attrs, id, cdir.span); - let i = mk_item(cx, cdir.span.lo, cdir.span.hi, - /* FIXME (#2543) */ copy id, - m, vis, mod_attrs); - items.push(i); - } - ast::cdir_dir_mod(vis, id, cdirs, attrs) => { - let path = Path(cdir_path_opt(*cx.sess.interner.get(id), attrs)); - let full_path = if path.is_absolute { - copy path - } else { - prefix.push_many(path.components) - }; - let (m0, a0) = eval_crate_directives_to_mod( - cx, cdirs, &full_path, &None); - let i = - @{ident: /* FIXME (#2543) */ copy id, - attrs: vec::append(attrs, a0), - id: cx.sess.next_id, - node: ast::item_mod(m0), - vis: vis, - span: cdir.span}; - cx.sess.next_id += 1; - items.push(i); - } - ast::cdir_view_item(vi) => view_items.push(vi), - } -} -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 17d6ba3ac9378..a9edf12f7fa82 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -80,7 +80,8 @@ pub fn new_low_level_string_reader(span_diagnostic: @span_handler, last_pos: filemap.start_pos, col: CharPos(0), curr: initial_char, - filemap: filemap, interner: itr, + filemap: filemap, + interner: itr, /* dummy values; not read */ peek_tok: token::EOF, peek_span: codemap::dummy_sp() @@ -150,6 +151,7 @@ impl reader for TtReader { } // EFFECT: advance peek_tok and peek_span to refer to the next token. +// EFFECT: update the interner, maybe. fn string_advance_token(r: @mut StringReader) { match (consume_whitespace_and_comments(r)) { Some(comment) => { @@ -173,12 +175,10 @@ fn byte_offset(rdr: @mut StringReader) -> BytePos { } pub fn get_str_from(rdr: @mut StringReader, start: BytePos) -> ~str { - unsafe { - // I'm pretty skeptical about this subtraction. What if there's a - // multi-byte character before the mark? - return str::slice(*rdr.src, start.to_uint() - 1u, - byte_offset(rdr).to_uint() - 1u).to_owned(); - } + // I'm pretty skeptical about this subtraction. What if there's a + // multi-byte character before the mark? + return str::slice(*rdr.src, start.to_uint() - 1u, + byte_offset(rdr).to_uint() - 1u).to_owned(); } // EFFECT: advance the StringReader by one character. If a newline is @@ -440,7 +440,11 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { if str::len(num_str) == 0u { rdr.fatal(~"no valid digits found for number"); } - let parsed = u64::from_str_radix(num_str, base as uint).get(); + let parsed = match u64::from_str_radix(num_str, base as uint) { + Some(p) => p, + None => rdr.fatal(~"int literal is too large") + }; + match tp { either::Left(t) => return token::LIT_INT(parsed as i64, t), either::Right(t) => return token::LIT_UINT(parsed, t) @@ -501,7 +505,10 @@ fn scan_number(c: char, rdr: @mut StringReader) -> token::Token { if str::len(num_str) == 0u { rdr.fatal(~"no valid digits found for number"); } - let parsed = u64::from_str_radix(num_str, base as uint).get(); + let parsed = match u64::from_str_radix(num_str, base as uint) { + Some(p) => p, + None => rdr.fatal(~"int literal is too large") + }; debug!("lexing %s as an unsuffixed integer literal", num_str); @@ -528,7 +535,7 @@ fn ident_start(c: char) -> bool { (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' - || (c > 'z' && char::is_XID_start(c)) + || (c > '\x7f' && char::is_XID_start(c)) } fn ident_continue(c: char) -> bool { @@ -536,9 +543,12 @@ fn ident_continue(c: char) -> bool { || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' - || (c > 'z' && char::is_XID_continue(c)) + || (c > '\x7f' && char::is_XID_continue(c)) } +// return the next token from the string +// EFFECT: advances the input past that token +// EFFECT: updates the interner fn next_token_inner(rdr: @mut StringReader) -> token::Token { let mut accum_str = ~""; let mut c = rdr.curr; @@ -771,7 +781,7 @@ fn consume_whitespace(rdr: @mut StringReader) { } #[cfg(test)] -pub mod test { +mod test { use super::*; use ast; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 22e659fa5744e..9348b72981d9e 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -45,10 +45,14 @@ pub mod classify; /// Reporting obsolete syntax pub mod obsolete; +// info about a parsing session. +// This structure and the reader both have +// an interner associated with them. If they're +// not the same, bad things can happen. pub struct ParseSess { - cm: @codemap::CodeMap, + cm: @codemap::CodeMap, // better be the same as the one in the reader! next_id: node_id, - span_diagnostic: @span_handler, + span_diagnostic: @span_handler, // better be the same as the one in the reader! interner: @ident_interner, } @@ -90,6 +94,19 @@ pub fn parse_crate_from_file( // why is there no p.abort_if_errors here? } +pub fn parse_crate_from_file_using_tts( + input: &Path, + cfg: ast::crate_cfg, + sess: @mut ParseSess +) -> @ast::crate { + let p = new_parser_from_file(sess, /*bad*/ copy cfg, input); + let tts = p.parse_all_token_trees(); + new_parser_from_tts(sess,cfg,tts).parse_crate_mod(/*bad*/ copy cfg) + // why is there no p.abort_if_errors here? +} + + + pub fn parse_crate_from_source_str( name: ~str, source: @~str, @@ -313,6 +330,7 @@ mod test { use std; use core::io; use core::option::None; + use ast; #[test] fn to_json_str>(val: @E) -> ~str { do io::with_str_writer |writer| { @@ -320,10 +338,38 @@ mod test { } } + fn string_to_crate (source_str : @~str) -> @ast::crate { + parse_crate_from_source_str( + ~"bogofile", + source_str, + ~[], + new_parse_sess(None)) + } + + fn string_to_tt_to_crate (source_str : @~str) -> @ast::crate { + let tts = parse_tts_from_source_str( + ~"bogofile", + source_str, + ~[], + new_parse_sess(None)); + new_parser_from_tts(new_parse_sess(None),~[],tts) + .parse_crate_mod(~[]) + } + + // make sure that parsing from TTs produces the same result + // as parsing from strings + #[test] fn tts_produce_the_same_result () { + let source_str = @~"fn foo (x : int) { x; }"; + assert_eq!(string_to_tt_to_crate(source_str), + string_to_crate(source_str)); + } + + // check the contents of the tt manually: #[test] fn alltts () { + let source_str = @~"fn foo (x : int) { x; }"; let tts = parse_tts_from_source_str( ~"bogofile", - @~"fn foo (x : int) { x; }", + source_str, ~[], new_parse_sess(None)); assert_eq!( diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index ceafecde3a0b1..fb3e8a5ded5a8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -94,7 +94,7 @@ use opt_vec::OptVec; use core::either::Either; use core::either; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use core::vec; #[deriving(Eq)] @@ -243,11 +243,12 @@ pub fn Parser(sess: @mut ParseSess, keywords: token::keyword_table(), strict_keywords: token::strict_keyword_table(), reserved_keywords: token::reserved_keyword_table(), - obsolete_set: @mut LinearSet::new(), + obsolete_set: @mut HashSet::new(), mod_path_stack: @mut ~[], } } +// ooh, nasty mutable fields everywhere.... pub struct Parser { sess: @mut ParseSess, cfg: crate_cfg, @@ -262,12 +263,12 @@ pub struct Parser { quote_depth: @mut uint, // not (yet) related to the quasiquoter reader: @reader, interner: @token::ident_interner, - keywords: LinearSet<~str>, - strict_keywords: LinearSet<~str>, - reserved_keywords: LinearSet<~str>, + keywords: HashSet<~str>, + strict_keywords: HashSet<~str>, + reserved_keywords: HashSet<~str>, /// The set of seen errors about obsolete syntax. Used to suppress /// extra detail when the same error is seen twice - obsolete_set: @mut LinearSet, + obsolete_set: @mut HashSet, /// Used to determine the path to externally loaded source files mod_path_stack: @mut ~[~str], @@ -340,6 +341,7 @@ pub impl Parser { self.sess.interner.get(id) } + // 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) || @@ -347,6 +349,7 @@ pub impl Parser { self.token_is_keyword(&~"fn", tok) } + // parse a ty_bare_fun type: fn parse_ty_bare_fn(&self) -> ty_ { /* @@ -376,6 +379,7 @@ pub impl Parser { }); } + // parse a ty_closure type fn parse_ty_closure(&self, sigil: ast::Sigil, region: Option<@ast::Lifetime>) -> ty_ @@ -434,6 +438,7 @@ pub impl Parser { } } + // parse a function type (following the 'fn') fn parse_ty_fn_decl(&self) -> (fn_decl, OptVec) { /* @@ -545,12 +550,14 @@ pub impl Parser { } + // parse a possibly mutable type fn parse_mt(&self) -> mt { let mutbl = self.parse_mutability(); let t = self.parse_ty(false); mt { ty: t, mutbl: mutbl } } + // parse [mut/const/imm] ID : TY fn parse_ty_field(&self) -> ty_field { let lo = self.span.lo; let mutbl = self.parse_mutability(); @@ -567,6 +574,7 @@ pub impl Parser { ) } + // parse optional return type [ -> TY ] in function decl fn parse_ret_ty(&self) -> (ret_style, @Ty) { return if self.eat(&token::RARROW) { let lo = self.span.lo; @@ -595,6 +603,7 @@ pub impl Parser { } } + // parse a type. // Useless second parameter for compatibility with quasiquote macros. // Bleh! fn parse_ty(&self, _: bool) -> @Ty { @@ -631,15 +640,19 @@ pub impl Parser { t } } else if *self.token == token::AT { + // MANAGED POINTER self.bump(); self.parse_box_or_uniq_pointee(ManagedSigil, ty_box) } else if *self.token == token::TILDE { + // OWNED POINTER self.bump(); self.parse_box_or_uniq_pointee(OwnedSigil, ty_uniq) } else if *self.token == token::BINOP(token::STAR) { + // STAR POINTER (bare pointer?) self.bump(); ty_ptr(self.parse_mt()) } else if *self.token == token::LBRACE { + // STRUCTURAL RECORD (remove?) let elems = self.parse_unspanned_seq( &token::LBRACE, &token::RBRACE, @@ -652,6 +665,7 @@ pub impl Parser { self.obsolete(*self.last_span, ObsoleteRecordType); ty_nil } else if *self.token == token::LBRACKET { + // VECTOR self.expect(&token::LBRACKET); let mt = self.parse_mt(); if mt.mutbl == m_mutbl { // `m_const` too after snapshot @@ -667,16 +681,20 @@ pub impl Parser { self.expect(&token::RBRACKET); t } else if *self.token == token::BINOP(token::AND) { + // BORROWED POINTER self.bump(); self.parse_borrowed_pointee() } else if self.eat_keyword(&~"extern") { + // EXTERN FUNCTION self.parse_ty_bare_fn() } else if self.token_is_closure_keyword(© *self.token) { + // CLOSURE let result = self.parse_ty_closure(ast::BorrowedSigil, None); self.obsolete(*self.last_span, ObsoleteBareFnType); result } else if *self.token == token::MOD_SEP || is_ident_or_path(&*self.token) { + // NAMED TYPE let path = self.parse_path_with_tps(false); ty_path(path, self.get_id()) } else { @@ -687,6 +705,7 @@ pub impl Parser { @Ty {id: self.get_id(), node: t, span: sp} } + // parse the type following a @ or a ~ fn parse_box_or_uniq_pointee( &self, sigil: ast::Sigil, @@ -879,12 +898,14 @@ pub impl Parser { // parse a path that doesn't have type parameters attached fn parse_path_without_tps(&self) - -> @ast::path { + -> @ast::Path { maybe_whole!(self, nt_path); let lo = self.span.lo; let global = self.eat(&token::MOD_SEP); let mut ids = ~[]; loop { + // if there's a ::< coming, stop processing + // the path. let is_not_last = self.look_ahead(2u) != token::LT && self.look_ahead(1u) == token::MOD_SEP; @@ -897,14 +918,17 @@ pub impl Parser { break; } } - @ast::path { span: mk_sp(lo, self.last_span.hi), + @ast::Path { span: mk_sp(lo, self.last_span.hi), global: global, idents: ids, rp: None, types: ~[] } } - fn parse_path_with_tps(&self, colons: bool) -> @ast::path { + // parse a path optionally with type parameters. If 'colons' + // is true, then type parameters must be preceded by colons, + // as in a::t:: + fn parse_path_with_tps(&self, colons: bool) -> @ast::Path { debug!("parse_path_with_tps(colons=%b)", colons); maybe_whole!(self, nt_path); @@ -959,18 +983,14 @@ pub impl Parser { } }; - @ast::path { span: mk_sp(lo, hi), + @ast::Path { span: mk_sp(lo, hi), rp: rp, types: tps, .. copy *path } } + /// parses 0 or 1 lifetime fn parse_opt_lifetime(&self) -> Option<@ast::Lifetime> { - /*! - * - * Parses 0 or 1 lifetime. - */ - match *self.token { token::LIFETIME(*) => { Some(@self.parse_lifetime()) @@ -999,12 +1019,9 @@ pub impl Parser { } } + /// Parses a single lifetime + // matches lifetime = ( LIFETIME ) | ( IDENT / ) fn parse_lifetime(&self) -> ast::Lifetime { - /*! - * - * Parses a single lifetime. - */ - match *self.token { token::LIFETIME(i) => { let span = copy self.span; @@ -1071,6 +1088,7 @@ pub impl Parser { self.token_is_keyword(&~"const", tok) } + // parse mutability declaration (mut/const/imm) fn parse_mutability(&self) -> mutability { if self.eat_keyword(&~"mut") { m_mutbl @@ -1123,6 +1141,9 @@ pub impl Parser { } } + // at the bottom (top?) of the precedence hierarchy, + // parse things like parenthesized exprs, + // macros, return, etc. fn parse_bottom_expr(&self) -> @expr { maybe_whole_expr!(self); @@ -1326,6 +1347,7 @@ pub impl Parser { return self.mk_expr(blk.span.lo, blk.span.hi, expr_block(blk)); } + // parse a.b or a(13) or just a fn parse_dot_or_call_expr(&self) -> @expr { let b = self.parse_bottom_expr(); self.parse_dot_or_call_expr_with(b) @@ -1594,7 +1616,7 @@ pub impl Parser { return spanned(lo, self.span.hi, m); } - + // parse a prefix-operator expr fn parse_prefix_expr(&self) -> @expr { let lo = self.span.lo; let mut hi; @@ -1605,7 +1627,6 @@ pub impl Parser { self.bump(); let e = self.parse_prefix_expr(); hi = e.span.hi; - self.get_id(); // see ast_util::op_expr_callee_id ex = expr_unary(not, e); } token::BINOP(b) => { @@ -1614,7 +1635,6 @@ pub impl Parser { self.bump(); let e = self.parse_prefix_expr(); hi = e.span.hi; - self.get_id(); // see ast_util::op_expr_callee_id ex = expr_unary(neg, e); } token::STAR => { @@ -1714,7 +1734,6 @@ pub impl Parser { self.bump(); let expr = self.parse_prefix_expr(); let rhs = self.parse_more_binops(expr, cur_prec); - self.get_id(); // see ast_util::op_expr_callee_id let bin = self.mk_expr(lhs.span.lo, rhs.span.hi, expr_binary(cur_op, lhs, rhs)); self.parse_more_binops(bin, min_prec) @@ -1765,7 +1784,6 @@ pub impl Parser { token::SHL => aop = shl, token::SHR => aop = shr } - self.get_id(); // see ast_util::op_expr_callee_id self.mk_expr(lo, rhs.span.hi, expr_assign_op(aop, lhs, rhs)) } @@ -2532,11 +2550,14 @@ pub impl Parser { } fn parse_block(&self) -> blk { + // disallow inner attrs: let (attrs, blk) = self.parse_inner_attrs_and_block(false); assert!(vec::is_empty(attrs)); return blk; } + // I claim the existence of the 'parse_attrs' flag strongly + // suggests a name-change or refactoring for this function. fn parse_inner_attrs_and_block(&self, parse_attrs: bool) -> (~[attribute], blk) { @@ -2577,6 +2598,7 @@ pub impl Parser { self.parse_block_tail_(lo, s, ~[]) } + // parse the rest of a block expression or function body fn parse_block_tail_(&self, lo: BytePos, s: blk_check_mode, +first_item_attrs: ~[attribute]) -> blk { let mut stmts = ~[]; @@ -2726,8 +2748,8 @@ pub impl Parser { self.bump(); } token::MOD_SEP | token::IDENT(*) => { - let maybe_bound = match *self.token { - token::MOD_SEP => None, + let obsolete_bound = match *self.token { + token::MOD_SEP => false, token::IDENT(copy sid, _) => { match *self.id_to_str(sid) { ~"send" | @@ -2737,27 +2759,18 @@ pub impl Parser { self.obsolete( *self.span, ObsoleteLowerCaseKindBounds); - - // Bogus value, but doesn't matter, since - // is an error - Some(TraitTyParamBound( - self.mk_ty_path(sid))) + self.bump(); + true } - _ => None + _ => false } } _ => fail!() }; - match maybe_bound { - Some(bound) => { - self.bump(); - result.push(bound); - } - None => { - let ty = self.parse_ty(true); - result.push(TraitTyParamBound(ty)); - } + if !obsolete_bound { + let tref = self.parse_trait_ref(); + result.push(TraitTyParamBound(tref)); } } _ => break, @@ -2782,6 +2795,10 @@ pub impl Parser { ast::TyParam { ident: ident, id: self.get_id(), bounds: bounds } } + // parse a set of optional generic type parameter declarations + // matches generics = ( ) | ( < > ) | ( < typaramseq ( , )? > ) | ( < lifetimes ( , )? > ) + // | ( < lifetimes , typaramseq ( , )? > ) + // where typaramseq = ( typaram ) | ( typaram , typaramseq ) fn parse_generics(&self) -> ast::Generics { if self.eat(&token::LT) { let lifetimes = self.parse_lifetimes(); @@ -2794,6 +2811,7 @@ pub impl Parser { } } + // parse a generic use site fn parse_generic_values( &self) -> (OptVec, ~[@Ty]) { @@ -3084,6 +3102,7 @@ pub impl Parser { } } + // parse trait Foo { ... } fn parse_item_trait(&self) -> item_info { let ident = self.parse_ident(); self.parse_region_param(); @@ -3162,6 +3181,7 @@ pub impl Parser { (ident, item_impl(generics, opt_trait, ty, meths), None) } + // parse a::B<~str,int> fn parse_trait_ref(&self) -> @trait_ref { @ast::trait_ref { path: self.parse_path_with_tps(false), @@ -3169,6 +3189,7 @@ pub impl Parser { } } + // parse B + C<~str,int> + D fn parse_trait_ref_list(&self, ket: &token::Token) -> ~[@trait_ref] { self.parse_seq_to_before_end( ket, @@ -3177,6 +3198,7 @@ pub impl Parser { ) } + // parse struct Foo { ... } fn parse_item_struct(&self) -> item_info { let class_name = self.parse_ident(); self.parse_region_param(); @@ -3426,6 +3448,7 @@ pub impl Parser { (id, item_const(ty, e), None) } + // parse a mod { ...} item fn parse_item_mod(&self, outer_attrs: ~[ast::attribute]) -> item_info { let id_span = *self.span; let id = self.parse_ident(); @@ -3682,7 +3705,7 @@ pub impl Parser { } }; - // extern mod { ... } + // extern mod foo { ... } or extern { ... } if items_allowed && self.eat(&token::LBRACE) { let abis = opt_abis.get_or_default(AbiSet::C()); @@ -3717,6 +3740,7 @@ pub impl Parser { (lo, id) } + // parse type Foo = Bar; fn parse_item_type(&self) -> item_info { let (_, ident) = self.parse_type_decl(); self.parse_region_param(); @@ -3727,6 +3751,7 @@ pub impl Parser { (ident, item_ty(ty, tps), None) } + // parse obsolete region parameter fn parse_region_param(&self) { if self.eat(&token::BINOP(token::SLASH)) { self.obsolete(*self.last_span, ObsoleteLifetimeNotation); @@ -3844,6 +3869,7 @@ pub impl Parser { let generics = self.parse_generics(); // Newtype syntax if *self.token == token::EQ { + // enum x = ty; self.bump(); let ty = self.parse_ty(false); self.expect(&token::SEMI); @@ -3868,6 +3894,7 @@ pub impl Parser { None ); } + // enum X { ... } self.expect(&token::LBRACE); let enum_definition = self.parse_enum_def(&generics); @@ -3971,7 +3998,7 @@ pub impl Parser { (self.is_keyword(&~"const") || (self.is_keyword(&~"static") && !self.token_is_keyword(&~"fn", &self.look_ahead(1)))) { - // CONST ITEM + // CONST / STATIC ITEM if self.is_keyword(&~"const") { self.obsolete(*self.span, ObsoleteConstItem); } @@ -3987,10 +4014,9 @@ pub impl Parser { let item = self.parse_item_foreign_const(visibility, attrs); return iovi_foreign_item(item); } - if items_allowed && - // FUNCTION ITEM (not sure about lookahead condition...) - self.is_keyword(&~"fn") && + if items_allowed && self.is_keyword(&~"fn") && !self.fn_expr_lookahead(self.look_ahead(1u)) { + // FUNCTION ITEM self.bump(); let (ident, item_, extra_attrs) = self.parse_item_fn(impure_fn, AbiSet::Rust()); @@ -3999,7 +4025,7 @@ pub impl Parser { maybe_append(attrs, extra_attrs))); } if items_allowed && self.eat_keyword(&~"pure") { - // PURE FUNCTION ITEM + // PURE FUNCTION ITEM (obsolete) self.obsolete(*self.last_span, ObsoletePurity); self.expect_keyword(&~"fn"); let (ident, item_, extra_attrs) = @@ -4177,6 +4203,12 @@ pub impl Parser { return view_item_use(self.parse_view_paths()); } + + // matches view_path : MOD? IDENT EQ non_global_path + // | MOD? non_global_path MOD_SEP LBRACE RBRACE + // | MOD? non_global_path MOD_SEP LBRACE ident_seq RBRACE + // | MOD? non_global_path MOD_SEP STAR + // | MOD? non_global_path fn parse_view_path(&self) -> @view_path { let lo = self.span.lo; @@ -4200,7 +4232,7 @@ pub impl Parser { let id = self.parse_ident(); path.push(id); } - let path = @ast::path { span: mk_sp(lo, self.span.hi), + let path = @ast::Path { span: mk_sp(lo, self.span.hi), global: false, idents: path, rp: None, @@ -4229,7 +4261,7 @@ pub impl Parser { seq_sep_trailing_allowed(token::COMMA), |p| p.parse_path_list_ident() ); - let path = @ast::path { span: mk_sp(lo, self.span.hi), + let path = @ast::Path { span: mk_sp(lo, self.span.hi), global: false, idents: path, rp: None, @@ -4241,7 +4273,7 @@ pub impl Parser { // foo::bar::* token::BINOP(token::STAR) => { self.bump(); - let path = @ast::path { span: mk_sp(lo, self.span.hi), + let path = @ast::Path { span: mk_sp(lo, self.span.hi), global: false, idents: path, rp: None, @@ -4257,7 +4289,7 @@ pub impl Parser { _ => () } let last = path[vec::len(path) - 1u]; - let path = @ast::path { span: mk_sp(lo, self.span.hi), + let path = @ast::Path { span: mk_sp(lo, self.span.hi), global: false, idents: path, rp: None, @@ -4266,6 +4298,7 @@ pub impl Parser { view_path_simple(last, path, namespace, self.get_id())); } + // matches view_paths = view_path | view_path , view_paths fn parse_view_paths(&self) -> ~[@view_path] { let mut vp = ~[self.parse_view_path()]; while *self.token == token::COMMA { @@ -4315,6 +4348,9 @@ pub impl Parser { // Parses a sequence of items. Stops when it finds program // text that can't be parsed as an item + // - mod_items uses VIEW_ITEMS_AND_ITEMS_ALLOWED + // - block_tail_ uses IMPORTS_AND_ITEMS_ALLOWED + // - foreign_mod_items uses FOREIGN_ITEMS_ALLOWED fn parse_items_and_view_items(&self, +first_item_attrs: ~[attribute], mode: view_item_parse_mode, macros_allowed: bool) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 5fdf6f7620cc1..54b2ad8514781 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -18,7 +18,7 @@ use util::interner; use core::cast; use core::char; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use core::str; use core::task; @@ -113,7 +113,7 @@ pub enum nonterminal { nt_expr(@ast::expr), nt_ty( @ast::Ty), nt_ident(ast::ident, bool), - nt_path(@ast::path), + nt_path(@ast::Path), nt_tt( @ast::token_tree), //needs @ed to break a circularity nt_matchers(~[ast::matcher]) } @@ -458,8 +458,8 @@ pub fn mk_fake_ident_interner() -> @ident_interner { * appear as identifiers at all. Reserved keywords are not used anywhere in * the language and may not appear as identifiers. */ -pub fn keyword_table() -> LinearSet<~str> { - let mut keywords = LinearSet::new(); +pub fn keyword_table() -> HashSet<~str> { + let mut keywords = HashSet::new(); let mut tmp = temporary_keyword_table(); let mut strict = strict_keyword_table(); let mut reserved = reserved_keyword_table(); @@ -471,8 +471,8 @@ pub fn keyword_table() -> LinearSet<~str> { } /// Keywords that may be used as identifiers -pub fn temporary_keyword_table() -> LinearSet<~str> { - let mut words = LinearSet::new(); +pub fn temporary_keyword_table() -> HashSet<~str> { + let mut words = HashSet::new(); let keys = ~[ ~"self", ~"static", ]; @@ -483,8 +483,8 @@ pub fn temporary_keyword_table() -> LinearSet<~str> { } /// Full keywords. May not appear anywhere else. -pub fn strict_keyword_table() -> LinearSet<~str> { - let mut words = LinearSet::new(); +pub fn strict_keyword_table() -> HashSet<~str> { + let mut words = HashSet::new(); let keys = ~[ ~"as", ~"break", @@ -509,8 +509,8 @@ pub fn strict_keyword_table() -> LinearSet<~str> { return words; } -pub fn reserved_keyword_table() -> LinearSet<~str> { - let mut words = LinearSet::new(); +pub fn reserved_keyword_table() -> HashSet<~str> { + let mut words = HashSet::new(); let keys = ~[ ~"be" ]; diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 0c79cbca039a6..88ecabe28f526 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -95,7 +95,6 @@ pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { } pub static indent_unit: uint = 4u; -pub static match_indent_unit: uint = 2u; pub static default_columns: uint = 78u; @@ -178,7 +177,7 @@ pub fn generics_to_str(generics: &ast::Generics, to_str(generics, print_generics, intr) } -pub fn path_to_str(&&p: @ast::path, intr: @ident_interner) -> ~str { +pub fn path_to_str(&&p: @ast::Path, intr: @ident_interner) -> ~str { to_str(p, |a,b| print_path(a, b, false), intr) } @@ -562,7 +561,7 @@ pub fn print_item(s: @ps, &&item: @ast::item) { match opt_trait { Some(t) => { - print_path(s, t.path, false); + print_trait_ref(s, t); space(s.s); word_space(s, ~"for"); } @@ -619,6 +618,10 @@ pub fn print_item(s: @ps, &&item: @ast::item) { (s.ann.post)(ann_node); } +fn print_trait_ref(s: @ps, t: &ast::trait_ref) { + print_path(s, t.path, false); +} + pub fn print_enum_def(s: @ps, enum_definition: ast::enum_def, generics: &ast::Generics, ident: ast::ident, span: codemap::span, visibility: ast::visibility) { @@ -1223,16 +1226,16 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) { print_block(s, blk); } ast::expr_match(expr, ref arms) => { - cbox(s, match_indent_unit); + cbox(s, indent_unit); ibox(s, 4); word_nbsp(s, ~"match"); print_expr(s, expr); space(s.s); bopen(s); - let len = (*arms).len(); - for (*arms).eachi |i, arm| { + let len = arms.len(); + for arms.eachi |i, arm| { space(s.s); - cbox(s, match_indent_unit); + cbox(s, indent_unit); ibox(s, 0u); let mut first = true; for arm.pats.each |p| { @@ -1265,7 +1268,7 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) { ast::expr_block(ref blk) => { // the block will close the pattern's ibox print_block_unclosed_indent( - s, blk, match_indent_unit); + s, blk, indent_unit); } _ => { end(s); // close the ibox for the pattern @@ -1282,10 +1285,10 @@ pub fn print_expr(s: @ps, &&expr: @ast::expr) { } } else { // the block will close the pattern's ibox - print_block_unclosed_indent(s, &arm.body, match_indent_unit); + print_block_unclosed_indent(s, &arm.body, indent_unit); } } - bclose_(s, expr.span, match_indent_unit); + bclose_(s, expr.span, indent_unit); } ast::expr_fn_block(ref decl, ref body) => { // in do/for blocks we don't want to show an empty @@ -1482,7 +1485,7 @@ pub fn print_for_decl(s: @ps, loc: @ast::local, coll: @ast::expr) { print_expr(s, coll); } -pub fn print_path(s: @ps, &&path: @ast::path, colons_before_params: bool) { +pub fn print_path(s: @ps, &&path: @ast::Path, colons_before_params: bool) { maybe_print_comment(s, path.span.lo); if path.global { word(s.s, ~"::"); } let mut first = true; @@ -1629,6 +1632,10 @@ pub fn print_pat(s: @ps, &&pat: @ast::pat, refutable: bool) { (s.ann.post)(ann_node); } +pub fn self_ty_to_str(self_ty: ast::self_ty_, intr: @ident_interner) -> ~str { + to_str(self_ty, |a, b| { print_self_ty(a, b); () }, intr) +} + // Returns whether it printed anything pub fn print_self_ty(s: @ps, self_ty: ast::self_ty_) -> bool { match self_ty { @@ -1744,7 +1751,7 @@ pub fn print_bounds(s: @ps, bounds: @OptVec) { } match *bound { - TraitTyParamBound(ty) => print_type(s, ty), + TraitTyParamBound(tref) => print_trait_ref(s, tref), RegionTyParamBound => word(s.s, ~"'static"), } } @@ -2241,7 +2248,7 @@ pub fn print_onceness(s: @ps, o: ast::Onceness) { } #[cfg(test)] -pub mod test { +mod test { use super::*; use ast; diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index 21c52f1bfcc06..56b17fb8d0a72 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -9,7 +9,7 @@ // except according to those terms. #[link(name = "syntax", - vers = "0.6", + vers = "0.7-pre", uuid = "9311401b-d6ea-4cd9-a1d9-61f89499c645")]; @@ -25,8 +25,8 @@ #[no_core]; -extern mod core(vers = "0.6"); -extern mod std(vers = "0.6"); +extern mod core(vers = "0.7-pre"); +extern mod std(vers = "0.7-pre"); use core::*; diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 159a205637b59..1133fd850d84b 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -13,10 +13,10 @@ // type, and vice versa. use core::prelude::*; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; pub struct Interner { - priv map: @mut LinearMap, + priv map: @mut HashMap, priv vect: @mut ~[T], } @@ -24,7 +24,7 @@ pub struct Interner { pub impl Interner { fn new() -> Interner { Interner { - map: @mut LinearMap::new(), + map: @mut HashMap::new(), vect: @mut ~[], } } @@ -66,43 +66,47 @@ pub impl Interner { fn len(&self) -> uint { let vect = &*self.vect; vect.len() } } -#[test] -#[should_fail] -pub fn i1 () { - let i : Interner<@~str> = Interner::new(); - i.get(13); -} +#[cfg(test)] +mod tests { + use super::*; + #[test] + #[should_fail] + fn i1 () { + let i : Interner<@~str> = Interner::new(); + i.get(13); + } -#[test] -pub fn i2 () { - let i : Interner<@~str> = Interner::new(); - // first one is zero: - assert_eq!(i.intern (@~"dog"), 0); - // re-use gets the same entry: - assert_eq!(i.intern (@~"dog"), 0); - // different string gets a different #: - assert_eq!(i.intern (@~"cat"), 1); - assert_eq!(i.intern (@~"cat"), 1); - // dog is still at zero - assert_eq!(i.intern (@~"dog"), 0); - // gensym gets 3 - assert_eq!(i.gensym (@~"zebra" ), 2); - // gensym of same string gets new number : - assert_eq!(i.gensym (@~"zebra" ), 3); - // gensym of *existing* string gets new number: - assert_eq!(i.gensym (@~"dog"), 4); - assert_eq!(i.get(0), @~"dog"); - assert_eq!(i.get(1), @~"cat"); - assert_eq!(i.get(2), @~"zebra"); - assert_eq!(i.get(3), @~"zebra"); - assert_eq!(i.get(4), @~"dog"); -} + #[test] + fn i2 () { + let i : Interner<@~str> = Interner::new(); + // first one is zero: + assert_eq!(i.intern (@~"dog"), 0); + // re-use gets the same entry: + assert_eq!(i.intern (@~"dog"), 0); + // different string gets a different #: + assert_eq!(i.intern (@~"cat"), 1); + assert_eq!(i.intern (@~"cat"), 1); + // dog is still at zero + assert_eq!(i.intern (@~"dog"), 0); + // gensym gets 3 + assert_eq!(i.gensym (@~"zebra" ), 2); + // gensym of same string gets new number : + assert_eq!(i.gensym (@~"zebra" ), 3); + // gensym of *existing* string gets new number: + assert_eq!(i.gensym (@~"dog"), 4); + assert_eq!(i.get(0), @~"dog"); + assert_eq!(i.get(1), @~"cat"); + assert_eq!(i.get(2), @~"zebra"); + assert_eq!(i.get(3), @~"zebra"); + assert_eq!(i.get(4), @~"dog"); + } -#[test] -pub fn i3 () { - let i : Interner<@~str> = Interner::prefill([@~"Alan",@~"Bob",@~"Carol"]); - assert_eq!(i.get(0), @~"Alan"); - assert_eq!(i.get(1), @~"Bob"); - assert_eq!(i.get(2), @~"Carol"); - assert_eq!(i.intern(@~"Bob"), 1); -} + #[test] + fn i3 () { + let i : Interner<@~str> = Interner::prefill([@~"Alan",@~"Bob",@~"Carol"]); + assert_eq!(i.get(0), @~"Alan"); + assert_eq!(i.get(1), @~"Bob"); + assert_eq!(i.get(2), @~"Carol"); + assert_eq!(i.intern(@~"Bob"), 1); + } +} \ No newline at end of file diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index a994f2b5b2280..c4c187bc4c7c4 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -147,6 +147,10 @@ pub fn visit_local(loc: @local, e: E, v: vt) { } } +fn visit_trait_ref(tref: @ast::trait_ref, e: E, v: vt) { + visit_path(tref.path, e, v); +} + pub fn visit_item(i: @item, e: E, v: vt) { match i.node { item_const(t, ex) => { @@ -189,9 +193,9 @@ pub fn visit_item(i: @item, e: E, v: vt) { } item_impl(ref tps, ref traits, ty, ref methods) => { (v.visit_generics)(tps, e, v); - for traits.each |p| { - visit_path(p.path, e, v); - } + for traits.each |&p| { + visit_trait_ref(p, e, v); + } (v.visit_ty)(ty, e, v); for methods.each |m| { visit_method_helper(*m, e, v) @@ -261,7 +265,7 @@ pub fn visit_ty(t: @Ty, e: E, v: vt) { } } -pub fn visit_path(p: @path, e: E, v: vt) { +pub fn visit_path(p: @Path, e: E, v: vt) { for p.types.each |tp| { (v.visit_ty)(*tp, e, v); } } @@ -327,8 +331,8 @@ pub fn visit_ty_param_bounds(bounds: @OptVec, e: E, v: vt) { for bounds.each |bound| { match *bound { - TraitTyParamBound(ty) => (v.visit_ty)(ty, e, v), - RegionTyParamBound => () + TraitTyParamBound(ty) => visit_trait_ref(ty, e, v), + RegionTyParamBound => {} } } } diff --git a/src/llvm b/src/llvm index accc36b3e3f22..56dd407f4f97a 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit accc36b3e3f22319b16609460f4cdf964f33f6cb +Subproject commit 56dd407f4f97a01b8df6554c569170d2fc276fcb diff --git a/src/rt/arch/arm/morestack.S b/src/rt/arch/arm/morestack.S index 1afce5bd848b7..4f1431a33927a 100644 --- a/src/rt/arch/arm/morestack.S +++ b/src/rt/arch/arm/morestack.S @@ -8,6 +8,64 @@ .arm .align -.globl __morestack +.global upcall_new_stack +.global upcall_del_stack +.global __morestack .hidden __morestack + +// r4 and r5 are scratch registers for __morestack due to llvm +// ARMFrameLowering::adjustForSegmentedStacks() implementation. + .type __morestack,%function __morestack: + .fnstart + // Save frame pointer and return address + .save {r4, r5} + .save {lr} + .save {r6, fp, lr} + push {r6, fp, lr} + + .movsp r6 + mov r6, sp + .setfp fp, sp, #4 + add fp, sp, #4 + + // Save argument registers of the original function + push {r0, r1, r2, r3, lr} + + mov r0, r4 // The amount of stack needed + add r1, fp, #20 // Address of stack arguments + mov r2, r5 // Size of stack arguments + + // Create new stack + bl upcall_new_stack@plt + + // Hold new stack pointer + mov r5, r0 + + // Pop the saved arguments + pop {r0, r1, r2, r3, lr} + + // Grab the return pointer + add r4, lr, #16 // Skip past the return + mov sp, r5 // Swich to the new stack + mov lr, pc + mov pc, r4 // Call the original function + + // Switch back to rust stack + mov sp, r6 + + // Save return value + mov r4, r0 + mov r5, r1 + + // Remove the new allocated stack + bl upcall_del_stack@plt + + // Restore return value + mov r0, r4 + mov r1, r5 + + // Return + pop {r6, fp, lr} + mov pc, lr + .fnend diff --git a/src/rt/arch/arm/record_sp.S b/src/rt/arch/arm/record_sp.S index abd8fbb6a5b05..fe680004a89aa 100644 --- a/src/rt/arch/arm/record_sp.S +++ b/src/rt/arch/arm/record_sp.S @@ -14,53 +14,18 @@ .globl get_sp record_sp_limit: - mov r3, r0 - ldr r0, =my_cpu - mov r1, #0 - mov r2, #0 - stmfd sp!, {r3, r7} - ldr r7, =345 - swi #0 - ldmfd sp!, {r3, r7} - movs r0, r0 - movmi r0, #0 - - ldr r1, =my_array - str r3, [r1, r0] + mrc p15, #0, r3, c13, c0, #3 + add r3, r3, #252 + str r0, [r3] mov pc, lr - get_sp_limit: - ldr r0, =my_cpu - mov r1, #0 - mov r2, #0 - stmfd sp!, {r4, r7} - ldr r7, =345 - swi #0 - ldmfd sp!, {r4, r7} - movs r0, r0 - movmi r0, #0 - mov r3, r0 - - ldr r1, =my_array - ldr r0, [r1, r3] + mrc p15, #0, r3, c13, c0, #3 + add r3, r3, #252 + ldr r0, [r3] mov pc, lr - get_sp: mov r0, sp mov pc, lr -.data -my_cpu: .long 0 -.global my_array -my_array: - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 - .long 0 -.end diff --git a/src/rt/arch/mips/_context.S b/src/rt/arch/mips/_context.S index c926a03798d2d..6d8207d97d094 100644 --- a/src/rt/arch/mips/_context.S +++ b/src/rt/arch/mips/_context.S @@ -51,7 +51,6 @@ swap_registers: lw $2, 2 * 4($5) lw $3, 3 * 4($5) lw $4, 4 * 4($5) - lw $5, 5 * 4($5) lw $6, 6 * 4($5) lw $7, 7 * 4($5) @@ -82,6 +81,8 @@ swap_registers: lw $30, 30 * 4($5) lw $31, 31 * 4($5) + lw $5, 5 * 4($5) + jr $31 nop .end swap_registers diff --git a/src/rt/arch/mips/ccall.S b/src/rt/arch/mips/ccall.S index f41d8e721f66f..abbbad164fd37 100644 --- a/src/rt/arch/mips/ccall.S +++ b/src/rt/arch/mips/ccall.S @@ -5,30 +5,39 @@ .text +.align 2 .globl __morestack .hidden __morestack -.align 2 +.cfi_sections .eh_frame_entry +.cfi_startproc .set nomips16 .ent __morestack __morestack: .set noreorder .set nomacro - move $7, $29 - move $29, $6 - sw $7, 0($29) - sw $31, -4($29) + addiu $29, $29, -8 + sw $31, 4($29) + sw $30, 0($29) - addiu $29, $29, -24 + .cfi_def_cfa_offset 8 + .cfi_offset 31, -4 + .cfi_offset 30, -8 + + move $30, $29 + .cfi_def_cfa_register 30 + + move $29, $6 move $25, $5 jalr $25 nop - addiu $29, $29, 24 + move $29, $30 - lw $31, -4($29) - lw $7, 0($29) + lw $30, 0($29) + lw $31, 4($29) + addiu $29, $29, 8 - move $29, $7 jr $31 nop .end __morestack +.cfi_endproc diff --git a/src/rt/arch/mips/context.cpp b/src/rt/arch/mips/context.cpp index d8c3c38daa6df..7347a92e98b92 100644 --- a/src/rt/arch/mips/context.cpp +++ b/src/rt/arch/mips/context.cpp @@ -40,6 +40,7 @@ void context::call(void *f, void *arg, void *stack) regs.data[4] = (uint32_t)arg; regs.data[29] = (uint32_t)sp; + regs.data[25] = (uint32_t)f; regs.data[31] = (uint32_t)f; // Last base pointer on the stack should be 0 diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index f586e05772b76..3c6cc9d924522 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -866,6 +866,16 @@ rust_dbg_extern_identity_TwoU64s(TwoU64s u) { return u; } +struct TwoDoubles { + double one; + double two; +}; + +extern "C" CDECL TwoDoubles +rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) { + return u; +} + extern "C" CDECL double rust_dbg_extern_identity_double(double u) { return u; diff --git a/src/rt/rust_log.cpp b/src/rt/rust_log.cpp index 2b86db6defe09..32723cf31bc6f 100644 --- a/src/rt/rust_log.cpp +++ b/src/rt/rust_log.cpp @@ -314,7 +314,7 @@ void update_log_settings(void* crate_map, char* settings) { n_dirs, &n_matches); if (n_matches < n_dirs) { - // NOTE: Android compiler is complaining about format specifiers here + // NB: Android compiler is complaining about format specifiers here // and I don't understand why /*printf("warning: got %" PRIdPTR " RUST_LOG specs, " "enabled %" PRIdPTR " flags.", diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 59fd8991622c6..73dbe661d3f86 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -199,6 +199,7 @@ rust_opendir rust_dbg_extern_identity_u32 rust_dbg_extern_identity_u64 rust_dbg_extern_identity_TwoU64s +rust_dbg_extern_identity_TwoDoubles rust_dbg_extern_identity_double rust_dbg_extern_identity_u8 rust_get_rt_env diff --git a/src/rt/sync/rust_thread.cpp b/src/rt/sync/rust_thread.cpp index 70fa08d7f2e5d..824642fc435d0 100644 --- a/src/rt/sync/rust_thread.cpp +++ b/src/rt/sync/rust_thread.cpp @@ -10,6 +10,7 @@ #include "rust_thread.h" +#include const size_t default_stack_sz = 1024*1024; @@ -41,6 +42,11 @@ rust_thread::start() { #if defined(__WIN32__) thread = CreateThread(NULL, stack_sz, rust_thread_start, this, 0, NULL); #else + // PTHREAD_STACK_MIN of some system is larger than default size + // so we check stack_sz to prevent assertion failure. + if (stack_sz < PTHREAD_STACK_MIN) { + stack_sz = PTHREAD_STACK_MIN; + } pthread_attr_t attr; CHECKED(pthread_attr_init(&attr)); CHECKED(pthread_attr_setstacksize(&attr, stack_sz)); diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index c4846c1a62bc3..5d422b2d2edc3 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -15,14 +15,12 @@ // //===----------------------------------------------------------------------=== -#include "llvm/InlineAsm.h" -#include "llvm/LLVMContext.h" #include "llvm/Linker.h" #include "llvm/PassManager.h" +#include "llvm/IR/InlineAsm.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Analysis/Verifier.h" #include "llvm/Analysis/Passes.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/IPO.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Assembly/Parser.h" @@ -31,11 +29,9 @@ #include "llvm/Support/FormattedStream.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/SourceMgr.h" -#include "llvm/Target/TargetOptions.h" #include "llvm/Support/Host.h" #include "llvm/Support/Debug.h" #include "llvm/Support/DynamicLibrary.h" @@ -45,6 +41,10 @@ #include "llvm/ExecutionEngine/JITMemoryManager.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/ExecutionEngine/Interpreter.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/IPO.h" #include "llvm-c/Core.h" #include "llvm-c/BitReader.h" #include "llvm-c/Object.h" @@ -62,6 +62,8 @@ using namespace llvm::sys; static const char *LLVMRustError; +extern cl::opt EnableARMEHABI; + extern "C" LLVMMemoryBufferRef LLVMRustCreateMemoryBufferWithContentsOfFile(const char *Path) { LLVMMemoryBufferRef MemBuf = NULL; @@ -216,6 +218,12 @@ class RustMCJITMemoryManager : public JITMemoryManager { virtual void deallocateExceptionTable(void *ET) { llvm_unreachable("Unimplemented call"); } + virtual uint8_t* allocateDataSection(uintptr_t, unsigned int, unsigned int, bool) { + llvm_unreachable("Unimplemented call"); + } + virtual bool applyPermissions(std::string*) { + llvm_unreachable("Unimplemented call"); + } }; bool RustMCJITMemoryManager::loadCrate(const char* file, std::string* err) { @@ -429,15 +437,23 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, LLVMRustInitializeTargets(); - int argc = 3; - const char* argv[] = {"rustc", "-arm-enable-ehabi", - "-arm-enable-ehabi-descriptors"}; - cl::ParseCommandLineOptions(argc, argv); + // Initializing the command-line options more than once is not + // allowed. So, check if they've already been initialized. + // (This could happen if we're being called from rustpkg, for + // example.) + if (!EnableARMEHABI) { + int argc = 3; + const char* argv[] = {"rustc", "-arm-enable-ehabi", + "-arm-enable-ehabi-descriptors"}; + cl::ParseCommandLineOptions(argc, argv); + } TargetOptions Options; Options.NoFramePointerElim = true; Options.EnableSegmentedStacks = EnableSegmentedStacks; + PassManager *PM = unwrap(PMR); + std::string Err; std::string Trip(Triple::normalize(triple)); std::string FeaturesStr; @@ -447,8 +463,9 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr, Options, Reloc::PIC_, CodeModel::Default, OptLevel); + Target->addAnalysisPasses(*PM); + bool NoVerify = false; - PassManager *PM = unwrap(PMR); std::string ErrorInfo; raw_fd_ostream OS(path, ErrorInfo, raw_fd_ostream::F_Binary); @@ -473,7 +490,7 @@ extern "C" LLVMModuleRef LLVMRustParseAssemblyFile(const char *Filename) { if (m) { return wrap(m); } else { - LLVMRustError = d.getMessage().c_str(); + LLVMRustError = d.getMessage().data(); return NULL; } } diff --git a/src/rustllvm/rustllvm.def.in b/src/rustllvm/rustllvm.def.in index 8b1c9d5ec7fbc..73bf1af90cd34 100644 --- a/src/rustllvm/rustllvm.def.in +++ b/src/rustllvm/rustllvm.def.in @@ -383,8 +383,6 @@ LLVMInitializeInstCombine LLVMInitializeScalarOpts LLVMInitializeTarget LLVMInitializeTransformUtils -LLVMInitializeARMAsmLexer -LLVMInitializeX86AsmLexer LLVMInitializeARMAsmParser LLVMInitializeMipsAsmParser LLVMInitializeX86AsmParser diff --git a/src/test/auxiliary/issue-2631-a.rs b/src/test/auxiliary/issue-2631-a.rs index fad72ee4eb360..bee754f5bd448 100644 --- a/src/test/auxiliary/issue-2631-a.rs +++ b/src/test/auxiliary/issue-2631-a.rs @@ -13,9 +13,9 @@ extern mod std; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; -pub type header_map = LinearMap<~str, @mut ~[@~str]>; +pub type header_map = HashMap<~str, @mut ~[@~str]>; // the unused ty param is necessary so this gets monomorphized pub fn request(req: &header_map) { diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index d6ebf4d346bcc..8a8962fb9d637 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -13,7 +13,7 @@ extern mod std; use core::io; use std::time; use std::treemap::TreeMap; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::trie::TrieMap; fn timed(label: &str, f: &fn()) { @@ -102,7 +102,7 @@ fn main() { { let rng = core::rand::seeded_rng([1, 1, 1, 1, 1, 1, 1]); - let mut set = LinearSet::new(); + let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.next() as uint; if set.insert(next) { @@ -131,21 +131,21 @@ fn main() { vector(&mut map, n_keys, rand); } - io::println("\nLinearMap:"); + io::println("\nHashMap:"); { - let mut map = LinearMap::new::(); + let mut map = HashMap::new::(); ascending(&mut map, n_keys); } { - let mut map = LinearMap::new::(); + let mut map = HashMap::new::(); descending(&mut map, n_keys); } { io::println(" Random integers:"); - let mut map = LinearMap::new::(); + let mut map = HashMap::new::(); vector(&mut map, n_keys, rand); } diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index a3210108dcc17..5f8f13896fb95 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -9,7 +9,7 @@ // except according to those terms. extern mod std; -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; use std::bitv::BitvSet; use std::treemap::TreeSet; use core::io::WriterUtil; @@ -158,9 +158,9 @@ fn main() { { let rng = rand::seeded_rng(seed); let mut results = empty_results(); - results.bench_int(rng, num_keys, max, || LinearSet::new::()); - results.bench_str(rng, num_keys, || LinearSet::new::<~str>()); - write_results("core::hashmap::LinearSet", &results); + results.bench_int(rng, num_keys, max, || HashSet::new::()); + results.bench_str(rng, num_keys, || HashSet::new::<~str>()); + write_results("core::hashmap::HashSet", &results); } { diff --git a/src/test/bench/graph500-bfs.rs b/src/test/bench/graph500-bfs.rs index a156f915faca7..396ea08136281 100644 --- a/src/test/bench/graph500-bfs.rs +++ b/src/test/bench/graph500-bfs.rs @@ -24,7 +24,7 @@ use std::arc; use std::time; use std::deque::Deque; use std::par; -use core::hashmap::linear::{LinearMap, LinearSet}; +use core::hashmap::{HashMap, HashSet}; use core::io::WriterUtil; use core::int::abs; use core::rand::RngUtil; @@ -81,7 +81,7 @@ fn make_edges(scale: uint, edgefactor: uint) -> ~[(node_id, node_id)] { fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph { let mut graph = do vec::from_fn(N) |_i| { - LinearSet::new() + HashSet::new() }; do vec::each(edges) |e| { @@ -104,7 +104,7 @@ fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph { } fn gen_search_keys(graph: &[~[node_id]], n: uint) -> ~[node_id] { - let mut keys = LinearSet::new(); + let mut keys = HashSet::new(); let r = rand::Rng(); while keys.len() < n { diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index d28382abaa386..4397dcd5247f5 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -1,25 +1,28 @@ // Perlin noise benchmark from https://gist.github.com/1170424 -use core::rand::RngUtil; +use core::rand::{Rng, RngUtil}; struct Vec2 { x: f32, y: f32, } -fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v } -fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) } +#[inline(always)] +fn lerp(a: f32, b: f32, v: f32) -> f32 { a * (1.0 - v) + b * v } -fn random_gradient(r: @rand::Rng) -> Vec2 { +#[inline(always)] +fn smooth(v: f32) -> f32 { v * v * (3.0 - 2.0 * v) } + +fn random_gradient(r: @Rng) -> Vec2 { let v = r.gen_float() * float::consts::pi * 2.0; - Vec2{ + Vec2 { x: float::cos(v) as f32, y: float::sin(v) as f32, } } fn gradient(orig: Vec2, grad: Vec2, p: Vec2) -> f32 { - let sp = Vec2{x: p.x - orig.x, y: p.y - orig.y}; + let sp = Vec2 {x: p.x - orig.x, y: p.y - orig.y}; grad.x * sp.x + grad.y + sp.y } @@ -28,28 +31,28 @@ struct Noise2DContext { permutations: [int, ..256], } -fn Noise2DContext() -> ~Noise2DContext { - let r = rand::Rng(); - let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ]; - for int::range(0, 256) |i| { rgradients[i] = random_gradient(r); } - let mut permutations = [ 0, ..256 ]; - for int::range(0, 256) |i| { permutations[i] = i; } - r.shuffle_mut(permutations); - - ~Noise2DContext{ - rgradients: rgradients, - permutations: permutations, +pub impl Noise2DContext { + fn new() -> Noise2DContext { + let r = rand::Rng(); + let mut rgradients = [ Vec2 { x: 0.0, y: 0.0 }, ..256 ]; + for int::range(0, 256) |i| { rgradients[i] = random_gradient(r); } + let mut permutations = [ 0, ..256 ]; + for int::range(0, 256) |i| { permutations[i] = i; } + r.shuffle_mut(permutations); + + Noise2DContext { + rgradients: rgradients, + permutations: permutations, + } } -} -pub impl Noise2DContext { #[inline(always)] fn get_gradient(&self, x: int, y: int) -> Vec2 { let idx = self.permutations[x & 255] + self.permutations[y & 255]; self.rgradients[idx & 255] } - #[inline(always)] + #[inline] fn get_gradients(&self, gradients: &mut [Vec2, ..4], origins: &mut [Vec2, ..4], x: f32, y: f32) { let x0f = f32::floor(x); let y0f = f32::floor(y); @@ -63,14 +66,15 @@ pub impl Noise2DContext { gradients[2] = self.get_gradient(x0, y1); gradients[3] = self.get_gradient(x1, y1); - origins[0] = Vec2{x: x0f + 0.0, y: y0f + 0.0}; - origins[1] = Vec2{x: x0f + 1.0, y: y0f + 0.0}; - origins[2] = Vec2{x: x0f + 0.0, y: y0f + 1.0}; - origins[3] = Vec2{x: x0f + 1.0, y: y0f + 1.0}; + origins[0] = Vec2 {x: x0f + 0.0, y: y0f + 0.0}; + origins[1] = Vec2 {x: x0f + 1.0, y: y0f + 0.0}; + origins[2] = Vec2 {x: x0f + 0.0, y: y0f + 1.0}; + origins[3] = Vec2 {x: x0f + 1.0, y: y0f + 1.0}; } + #[inline] fn get(&self, x: f32, y: f32) -> f32 { - let p = Vec2{x: x, y: y}; + let p = Vec2 {x: x, y: y}; let mut gradients = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ]; let mut origins = [ Vec2 { x: 0.0, y: 0.0 }, ..4 ]; self.get_gradients(&mut gradients, &mut origins, x, y); @@ -88,9 +92,9 @@ pub impl Noise2DContext { fn main() { let symbols = [" ", "░", "▒", "▓", "█", "█"]; - let mut pixels = vec::from_elem(256*256, 0f32); - let n2d = Noise2DContext(); - for int::range(0, 100) |_| { + let mut pixels = [0f32, ..256*256]; + let n2d = ~Noise2DContext::new(); + for 100.times { for int::range(0, 256) |y| { for int::range(0, 256) |x| { let v = n2d.get( @@ -109,4 +113,3 @@ fn main() { io::println(""); }*/ } - diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 3bc40a46cfb2c..c8b13a6e27fa3 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -15,13 +15,13 @@ extern mod std; use std::sort; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use core::io::ReaderUtil; use core::comm::{stream, Port, Chan}; use core::cmp::Ord; // given a map, print a sorted version of it -fn sort_and_fmt(mm: &LinearMap<~[u8], uint>, total: uint) -> ~str { +fn sort_and_fmt(mm: &HashMap<~[u8], uint>, total: uint) -> ~str { fn pct(xx: uint, yy: uint) -> float { return (xx as float) * 100f / (yy as float); } @@ -48,7 +48,7 @@ fn sort_and_fmt(mm: &LinearMap<~[u8], uint>, total: uint) -> ~str { let mut pairs = ~[]; // map -> [(k,%)] - for mm.each |&(&key, &val)| { + for mm.each |&key, &val| { pairs.push((key, pct(val, total))); } @@ -67,7 +67,7 @@ fn sort_and_fmt(mm: &LinearMap<~[u8], uint>, total: uint) -> ~str { } // given a map, search for the frequency of a pattern -fn find(mm: &LinearMap<~[u8], uint>, key: ~str) -> uint { +fn find(mm: &HashMap<~[u8], uint>, key: ~str) -> uint { match mm.find(&str::to_bytes(str::to_lower(key))) { option::None => { return 0u; } option::Some(&num) => { return num; } @@ -75,7 +75,7 @@ fn find(mm: &LinearMap<~[u8], uint>, key: ~str) -> uint { } // given a map, increment the counter for a key -fn update_freq(mm: &mut LinearMap<~[u8], uint>, key: &[u8]) { +fn update_freq(mm: &mut HashMap<~[u8], uint>, key: &[u8]) { let key = vec::slice(key, 0, key.len()).to_vec(); let newval = match mm.pop(&key) { Some(v) => v + 1, @@ -103,7 +103,7 @@ fn windows_with_carry(bb: &[u8], nn: uint, fn make_sequence_processor(sz: uint, from_parent: comm::Port<~[u8]>, to_parent: comm::Chan<~str>) { - let mut freqs: LinearMap<~[u8], uint> = LinearMap::new(); + let mut freqs: HashMap<~[u8], uint> = HashMap::new(); let mut carry: ~[u8] = ~[]; let mut total: uint = 0u; diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 1764ef48412cc..f5d1661fa52bd 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -25,7 +25,7 @@ // writes pbm image to output path use core::io::WriterUtil; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; struct cmplx { re: f64, @@ -125,7 +125,7 @@ fn writer(path: ~str, pport: comm::Port, size: uint) }; cout.write_line("P4"); cout.write_line(fmt!("%u %u", size, size)); - let mut lines: LinearMap = LinearMap::new(); + let mut lines: HashMap = HashMap::new(); let mut done = 0_u; let mut i = 0_u; while i < size { diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs index 6dbfa5dd53847..bda659aa7b97e 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs @@ -10,11 +10,11 @@ //buggy.rs -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; fn main() { - let mut buggy_map :LinearMap = - LinearMap::new::(); + let mut buggy_map :HashMap = + HashMap::new::(); buggy_map.insert(42, &*~1); //~ ERROR illegal borrow // but it is ok if we use a temporary diff --git a/src/test/compile-fail/borrowck-insert-during-each.rs b/src/test/compile-fail/borrowck-insert-during-each.rs index 788c5397e35d0..17c0efe225e4d 100644 --- a/src/test/compile-fail/borrowck-insert-during-each.rs +++ b/src/test/compile-fail/borrowck-insert-during-each.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::hashmap::linear::LinearSet; +use core::hashmap::HashSet; struct Foo { - n: LinearSet, + n: HashSet, } pub impl Foo { @@ -29,6 +29,6 @@ fn bar(f: &mut Foo) { } fn main() { - let mut f = Foo { n: LinearSet::new() }; + let mut f = Foo { n: HashSet::new() }; bar(&mut f); } diff --git a/src/test/compile-fail/elided-test.rs b/src/test/compile-fail/elided-test.rs index b62214b12f9a0..eaae721e0e555 100644 --- a/src/test/compile-fail/elided-test.rs +++ b/src/test/compile-fail/elided-test.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern: main function not found +// error-pattern: entry function not found // Since we're not compiling a test runner this function should be elided // and the build will fail because main doesn't exist diff --git a/src/test/compile-fail/extern-no-call.rs b/src/test/compile-fail/extern-no-call.rs index 8c6deb3481674..58649f3209bb1 100644 --- a/src/test/compile-fail/extern-no-call.rs +++ b/src/test/compile-fail/extern-no-call.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:expected function or foreign function but found `*u8` +// error-pattern:expected function but found `*u8` extern fn f() { } diff --git a/src/test/compile-fail/for-loop-decl.rs b/src/test/compile-fail/for-loop-decl.rs index 918d8f00d7842..de28d72677728 100644 --- a/src/test/compile-fail/for-loop-decl.rs +++ b/src/test/compile-fail/for-loop-decl.rs @@ -11,10 +11,10 @@ // error-pattern: mismatched types extern mod std; use std::bitv; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; struct FnInfo { - vars: LinearMap + vars: HashMap } struct VarInfo { diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index da3728ff3ae12..2842d884c9918 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -22,6 +22,6 @@ impl vec_monad for ~[A] { } fn main() { ["hi"].bind(|x| [x] ); - //~^ ERROR type `[&'static str * 1]` does not implement any method in scope named `bind` + //~^ ERROR type `[&'static str, .. 1]` does not implement any method in scope named `bind` //~^^ ERROR Unconstrained region variable } diff --git a/src/test/compile-fail/issue-2330.rs b/src/test/compile-fail/issue-2330.rs index d8acbf2893aa5..6152e82294d1b 100644 --- a/src/test/compile-fail/issue-2330.rs +++ b/src/test/compile-fail/issue-2330.rs @@ -15,7 +15,7 @@ trait channel { } // `chan` is not a trait, it's an enum -impl chan for int { //~ ERROR can only implement trait types +impl chan for int { //~ ERROR chan is not a trait fn send(&self, v: int) { fail!() } } diff --git a/src/test/compile-fail/issue-3563.rs b/src/test/compile-fail/issue-3563.rs index 0388f0fd29083..38f28bd79dfa1 100644 --- a/src/test/compile-fail/issue-3563.rs +++ b/src/test/compile-fail/issue-3563.rs @@ -10,7 +10,7 @@ trait A { fn a(&self) { - || self.b() //~ ERROR type `&'self self` does not implement any method in scope named `b` + || self.b() //~ ERROR type `&Self` does not implement any method in scope named `b` } } fn main() {} diff --git a/src/test/compile-fail/issue-3888.rs b/src/test/compile-fail/issue-3888.rs deleted file mode 100644 index 35f8557c32b60..0000000000000 --- a/src/test/compile-fail/issue-3888.rs +++ /dev/null @@ -1,42 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// n.b. This should be a run-pass test, but for now I'm testing -// that we don't see an "unknown scope" error. -fn vec_peek<'r, T>(v: &'r [T]) -> Option< (&'r T, &'r [T]) > { - if v.len() == 0 { - None - } else { - let vec_len = v.len(); - let head = &v[0]; - // note: this *shouldn't* be an illegal borrow! See #3888 - let tail = v.slice(1, vec_len); //~ ERROR illegal borrow: borrowed value does not live long enough - Some( (head, tail) ) - } -} - - -fn test_peek_empty_stack() { - let v : &[int] = &[]; - assert!((None == vec_peek(v))); -} - -fn test_peek_empty_unique() { - let v : ~[int] = ~[]; - assert!((None == vec_peek(v))); -} - -fn test_peek_empty_managed() { - let v : @[int] = @[]; - assert!((None == vec_peek(v))); -} - - -fn main() {} diff --git a/src/test/compile-fail/issue-3969.rs b/src/test/compile-fail/issue-3969.rs index 60991d40a54c3..b60a54a44bbfd 100644 --- a/src/test/compile-fail/issue-3969.rs +++ b/src/test/compile-fail/issue-3969.rs @@ -18,7 +18,7 @@ trait BikeMethods { impl BikeMethods for Bike { fn woops() -> ~str { ~"foo" } - //~^ ERROR method `woops` is declared as static in its impl, but not in its trait + //~^ ERROR has a `&const self` declaration in the trait, but not in the impl } pub fn main() { diff --git a/src/test/compile-fail/issue-4517.rs b/src/test/compile-fail/issue-4517.rs index 23cfeecc520e7..0fbc79b1bc7bd 100644 --- a/src/test/compile-fail/issue-4517.rs +++ b/src/test/compile-fail/issue-4517.rs @@ -2,5 +2,5 @@ fn bar(int_param: int) {} fn main() { let foo: [u8, ..4] = [1u8, ..4u8]; - bar(foo); //~ ERROR mismatched types: expected `int` but found `[u8 * 4]` (expected int but found vector) + bar(foo); //~ ERROR mismatched types: expected `int` but found `[u8, .. 4]` (expected int but found vector) } diff --git a/src/test/compile-fail/issue-5544-a.rs b/src/test/compile-fail/issue-5544-a.rs new file mode 100644 index 0000000000000..42a18ba5fb765 --- /dev/null +++ b/src/test/compile-fail/issue-5544-a.rs @@ -0,0 +1,14 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let _i = 18446744073709551616; // 2^64 + //~^ ERROR int literal is too large +} diff --git a/src/test/compile-fail/issue-5544-b.rs b/src/test/compile-fail/issue-5544-b.rs new file mode 100644 index 0000000000000..bbe43e652a800 --- /dev/null +++ b/src/test/compile-fail/issue-5544-b.rs @@ -0,0 +1,14 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn main() { + let _i = 0xff_ffff_ffff_ffff_ffff; + //~^ ERROR int literal is too large +} diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/kindck-owned-trait-contains.rs index f5153265308e1..54ee8bcc70e37 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/kindck-owned-trait-contains.rs @@ -27,5 +27,6 @@ fn main() { let x: &'blk int = &3; repeater(@x) }; - assert!(3 == *(y.get())); //~ ERROR reference is not valid + assert!(3 == *(y.get())); //~ ERROR dereference of reference outside its lifetime + //~^ ERROR reference is not valid outside of its lifetime } diff --git a/src/test/compile-fail/liveness-unused.rs b/src/test/compile-fail/liveness-unused.rs index 9e4d16f96e6c3..27db4ff5aaae2 100644 --- a/src/test/compile-fail/liveness-unused.rs +++ b/src/test/compile-fail/liveness-unused.rs @@ -8,38 +8,57 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[deny(unused_variable)]; +#[deny(dead_assignment)]; + fn f1(x: int) { - //~^ WARNING unused variable: `x` + //~^ ERROR unused variable: `x` } fn f1b(x: &mut int) { - //~^ WARNING unused variable: `x` + //~^ ERROR unused variable: `x` } +#[allow(unused_variable)] +fn f1c(x: int) {} + fn f2() { let x = 3; - //~^ WARNING unused variable: `x` + //~^ ERROR unused variable: `x` } fn f3() { let mut x = 3; - //~^ WARNING variable `x` is assigned to, but never used + //~^ ERROR variable `x` is assigned to, but never used x += 4; - //~^ WARNING value assigned to `x` is never read + //~^ ERROR value assigned to `x` is never read } fn f3b() { let mut z = 3; - //~^ WARNING variable `z` is assigned to, but never used + //~^ ERROR variable `z` is assigned to, but never used loop { z += 4; } } +#[allow(unused_variable)] +fn f3c() { + let mut z = 3; + loop { z += 4; } +} + +#[allow(unused_variable)] +#[allow(dead_assignment)] +fn f3d() { + let mut x = 3; + x += 4; +} + fn f4() { match Some(3) { Some(i) => { - //~^ WARNING unused variable: `i` + //~^ ERROR unused variable: `i` } None => {} } @@ -57,16 +76,5 @@ fn f4b() -> int { } } -// leave this in here just to trigger compile-fail: -struct r { - x: (), -} - -impl Drop for r { - fn finalize(&self) {} -} - fn main() { - let x = r { x: () }; - || { copy x; }; //~ ERROR copying a value of non-copyable type } diff --git a/src/test/compile-fail/map-types.rs b/src/test/compile-fail/map-types.rs index 6f71bd40affe5..ebc5b015d2752 100644 --- a/src/test/compile-fail/map-types.rs +++ b/src/test/compile-fail/map-types.rs @@ -9,12 +9,12 @@ // except according to those terms. use core::container::Map; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; // Test that trait types printed in error msgs include the type arguments. fn main() { - let x: @Map<~str, ~str> = @LinearMap::new::<~str, ~str>() as + let x: @Map<~str, ~str> = @HashMap::new::<~str, ~str>() as @Map<~str, ~str>; let y: @Map = @x; //~^ ERROR mismatched types: expected `@core::container::Map` diff --git a/src/test/compile-fail/missing-main.rs b/src/test/compile-fail/missing-main.rs index 4bfdaf69480e6..4f1b604b5070d 100644 --- a/src/test/compile-fail/missing-main.rs +++ b/src/test/compile-fail/missing-main.rs @@ -8,5 +8,5 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:main function not found +// error-pattern:entry function not found fn mian() { } diff --git a/src/test/compile-fail/packed-struct-generic-transmute.rs b/src/test/compile-fail/packed-struct-generic-transmute.rs new file mode 100644 index 0000000000000..3ed9d00be28b1 --- /dev/null +++ b/src/test/compile-fail/packed-struct-generic-transmute.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This assumes the packed and non-packed structs are different sizes. + +// the error points to the start of the file, not the line with the +// transmute + +// error-pattern: reinterpret_cast called on types with different size + +#[packed] +struct Foo { + bar: T, + baz: S +} + +struct Oof { + rab: T, + zab: S +} + +fn main() { + let foo = Foo { bar: [1u8, 2, 3, 4, 5], baz: 10i32 }; + unsafe { + let oof: Oof<[u8, .. 5], i32> = cast::transmute(foo); + debug!(oof); + } +} diff --git a/src/test/run-pass/regions-parameterization-self-types-issue-5224.rs b/src/test/compile-fail/packed-struct-transmute.rs similarity index 50% rename from src/test/run-pass/regions-parameterization-self-types-issue-5224.rs rename to src/test/compile-fail/packed-struct-transmute.rs index 346a0fcfe0793..d2aca3c0d6b61 100644 --- a/src/test/run-pass/regions-parameterization-self-types-issue-5224.rs +++ b/src/test/compile-fail/packed-struct-transmute.rs @@ -8,31 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test how region-parameterization inference -// interacts with explicit self types. -// -// Issue #5224. +// This assumes the packed and non-packed structs are different sizes. -trait Getter { - // This trait does not need to be - // region-parameterized, because 'self - // is bound in the self type: - fn get(&self) -> &'self int; -} +// the error points to the start of the file, not the line with the +// transmute -struct Foo { - field: int -} +// error-pattern: reinterpret_cast called on types with different size -impl Getter for Foo { - fn get(&self) -> &'self int { &self.field } +#[packed] +struct Foo { + bar: u8, + baz: uint } -fn get_int(g: &G) -> int { - *g.get() +struct Oof { + rab: u8, + zab: uint } -pub fn main() { - let foo = Foo { field: 22 }; - assert!(get_int(&foo) == 22); +fn main() { + let foo = Foo { bar: 1, baz: 10 }; + unsafe { + let oof: Oof = cast::transmute(foo); + debug!(oof); + } } diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs index fb9d963dc80a7..f7165784c7975 100644 --- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs +++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs @@ -24,9 +24,9 @@ fn with(f: &fn(x: &int) -> R) -> int { fn return_it() -> int { with(|o| o) - //~^ ERROR reference is not valid outside of its lifetime + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements //~^^ ERROR reference is not valid outside of its lifetime - //~^^^ ERROR cannot infer an appropriate lifetime + //~^^^ ERROR reference is not valid outside of its lifetime } fn main() { diff --git a/src/test/compile-fail/regions-free-region-ordering-callee.rs b/src/test/compile-fail/regions-free-region-ordering-callee.rs new file mode 100644 index 0000000000000..e5399fc7fa3b9 --- /dev/null +++ b/src/test/compile-fail/regions-free-region-ordering-callee.rs @@ -0,0 +1,37 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that callees correctly infer an ordering between free regions +// that appear in their parameter list. See also +// regions-free-region-ordering-caller.rs + +fn ordering1<'a, 'b>(x: &'a &'b uint) -> &'a uint { + // It is safe to assume that 'a <= 'b due to the type of x + let y: &'b uint = &**x; + return y; +} + +fn ordering2<'a, 'b>(x: &'a &'b uint, y: &'a uint) -> &'b uint { + // However, it is not safe to assume that 'b <= 'a + &*y //~ ERROR cannot infer an appropriate lifetime +} + +fn ordering3<'a, 'b>(x: &'a uint, y: &'b uint) -> &'a &'b uint { + // Do not infer an ordering from the return value. + let z: &'b uint = &*x; + //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements + fail!(); +} + +fn ordering4<'a, 'b>(a: &'a uint, b: &'b uint, x: &fn(&'a &'b uint)) { + let z: Option<&'a &'b uint> = None; +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/regions-free-region-ordering-caller.rs b/src/test/compile-fail/regions-free-region-ordering-caller.rs new file mode 100644 index 0000000000000..d06dcd8aa86b8 --- /dev/null +++ b/src/test/compile-fail/regions-free-region-ordering-caller.rs @@ -0,0 +1,40 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test various ways to construct a pointer with a longer lifetime +// than the thing it points at and ensure that they result in +// errors. See also regions-free-region-ordering-callee.rs + +struct Paramd<'self> { x: &'self uint } + +fn call1<'a>(x: &'a uint) { + let y: uint = 3; + let z: &'a &'blk uint = &(&y); + //~^ ERROR pointer has a longer lifetime than the data it references +} + +fn call2<'a, 'b>(a: &'a uint, b: &'b uint) { + let z: Option<&'b &'a uint> = None; + //~^ ERROR pointer has a longer lifetime than the data it references +} + +fn call3<'a, 'b>(a: &'a uint, b: &'b uint) { + let y: Paramd<'a> = Paramd { x: a }; + let z: Option<&'b Paramd<'a>> = None; + //~^ ERROR pointer has a longer lifetime than the data it references +} + +fn call4<'a, 'b>(a: &'a uint, b: &'b uint) { + let z: Option<&fn(&'a &'b uint)> = None; + //~^ ERROR pointer has a longer lifetime than the data it references +} + + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/regions-infer-paramd-indirect.rs b/src/test/compile-fail/regions-infer-paramd-indirect.rs index e4ad93bde17e6..e8d66ab297b71 100644 --- a/src/test/compile-fail/regions-infer-paramd-indirect.rs +++ b/src/test/compile-fail/regions-infer-paramd-indirect.rs @@ -18,12 +18,12 @@ struct c<'self> { f: @b<'self> } -trait set_f { +trait set_f<'self> { fn set_f_ok(&self, b: @b<'self>); fn set_f_bad(&self, b: @b); } -impl<'self> set_f for c<'self> { +impl<'self> set_f<'self> for c<'self> { fn set_f_ok(&self, b: @b<'self>) { self.f = b; } diff --git a/src/test/compile-fail/regions-trait-2.rs b/src/test/compile-fail/regions-trait-2.rs index 5811496cab451..9855a234618ab 100644 --- a/src/test/compile-fail/regions-trait-2.rs +++ b/src/test/compile-fail/regions-trait-2.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test #5723 + +// Test that you cannot escape a borrowed pointer +// into a trait. + struct ctxt { v: uint } trait get_ctxt { @@ -24,8 +29,9 @@ fn make_gc() -> @get_ctxt { let ctxt = ctxt { v: 22u }; let hc = has_ctxt { c: &ctxt }; return @hc as @get_ctxt; + //^~ ERROR source contains borrowed pointer } fn main() { - make_gc().get_ctxt().v; //~ ERROR illegal borrow + make_gc().get_ctxt().v; } diff --git a/src/test/compile-fail/selftype-traittype.rs b/src/test/compile-fail/selftype-traittype.rs index 467154244b760..220573660c5b0 100644 --- a/src/test/compile-fail/selftype-traittype.rs +++ b/src/test/compile-fail/selftype-traittype.rs @@ -12,7 +12,7 @@ trait add { fn plus(&self, x: Self) -> Self; } -fn do_add(x: add, y: add) -> add { +fn do_add(x: @add, y: @add) -> @add { x.plus(y) //~ ERROR cannot call a method whose type contains a self-type through a boxed trait } diff --git a/src/test/compile-fail/staticness-mismatch.rs b/src/test/compile-fail/staticness-mismatch.rs index 719da233335e1..9bcf0777bbd34 100644 --- a/src/test/compile-fail/staticness-mismatch.rs +++ b/src/test/compile-fail/staticness-mismatch.rs @@ -14,7 +14,7 @@ trait foo { } impl foo for int { - fn bar(&self) {} //~ ERROR method `bar` is declared as static in its trait, but not in its impl + fn bar(&self) {} //~ ERROR method `bar` has a `&self` declaration in the impl, but not in the trait } fn main() {} diff --git a/src/test/compile-fail/unused-unsafe.rs b/src/test/compile-fail/unused-unsafe.rs new file mode 100644 index 0000000000000..368a0fbe9bece --- /dev/null +++ b/src/test/compile-fail/unused-unsafe.rs @@ -0,0 +1,44 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Exercise the unused_unsafe attribute in some positive and negative cases + +#[deny(unused_unsafe)]; + +use core::libc; + +fn callback(_f: &fn() -> T) -> T { fail!() } + +fn bad1() { unsafe {} } //~ ERROR: unnecessary "unsafe" block +fn bad2() { unsafe { bad1() } } //~ ERROR: unnecessary "unsafe" block +unsafe fn bad3() {} //~ ERROR: unnecessary "unsafe" function +unsafe fn bad4() { unsafe {} } //~ ERROR: unnecessary "unsafe" function + //~^ ERROR: unnecessary "unsafe" block +fn bad5() { unsafe { do callback {} } } //~ ERROR: unnecessary "unsafe" block + +unsafe fn good0() { libc::exit(1) } +fn good1() { unsafe { libc::exit(1) } } +fn good2() { + /* bug uncovered when implementing warning about unused unsafe blocks. Be + sure that when purity is inherited that the source of the unsafe-ness + is tracked correctly */ + unsafe { + unsafe fn what() -> ~[~str] { libc::exit(2) } + + do callback { + what(); + } + } +} + +#[allow(unused_unsafe)] unsafe fn allowed0() {} +#[allow(unused_unsafe)] fn allowed1() { unsafe {} } + +fn main() { } diff --git a/src/test/debug-info/basic-types.rs b/src/test/debug-info/basic-types.rs index 2441b35bc320b..20da6b557f18d 100644 --- a/src/test/debug-info/basic-types.rs +++ b/src/test/debug-info/basic-types.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test + // Caveats - gdb prints any 8-bit value (meaning rust i8 and u8 values) // as its numerical value along with its associated ASCII char, there // doesn't seem to be any way around this. Also, gdb doesn't know diff --git a/src/test/debug-info/struct.rs b/src/test/debug-info/struct.rs index 30f4b657c4e35..16ba6cda5900a 100644 --- a/src/test/debug-info/struct.rs +++ b/src/test/debug-info/struct.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test + // compile-flags:-Z extra-debug-info // debugger:set print pretty off // debugger:break 29 diff --git a/src/test/debug-info/tuple.rs b/src/test/debug-info/tuple.rs index a2cdc689fad47..35e2977f562e9 100644 --- a/src/test/debug-info/tuple.rs +++ b/src/test/debug-info/tuple.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test + // compile-flags:-Z extra-debug-info // debugger:set print pretty off // debugger:break 20 diff --git a/src/test/pretty/alt-naked-expr-long.rs b/src/test/pretty/alt-naked-expr-long.rs index 67253c9753ede..66ad3d558201d 100644 --- a/src/test/pretty/alt-naked-expr-long.rs +++ b/src/test/pretty/alt-naked-expr-long.rs @@ -17,9 +17,9 @@ fn main() { let x = Some(3); let y = match x { - Some(_) => - ~"some" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" - + ~"very" + ~"very" + ~"long" + ~"string", - None => ~"none" + Some(_) => + ~"some" + ~"very" + ~"very" + ~"very" + ~"very" + ~"very" + + ~"very" + ~"very" + ~"very" + ~"long" + ~"string", + None => ~"none" }; } diff --git a/src/test/pretty/alt-naked-expr-medium.rs b/src/test/pretty/alt-naked-expr-medium.rs index 6c6398c3e52c2..4ae129c7b7307 100644 --- a/src/test/pretty/alt-naked-expr-medium.rs +++ b/src/test/pretty/alt-naked-expr-medium.rs @@ -14,7 +14,7 @@ fn main() { let x = Some(3); let _y = match x { - Some(_) => ~[~"some(_)", ~"not", ~"SO", ~"long", ~"string"], - None => ~[~"none"] + Some(_) => ~[~"some(_)", ~"not", ~"SO", ~"long", ~"string"], + None => ~[~"none"] }; } diff --git a/src/test/run-fail/unwind-misc-1.rs b/src/test/run-fail/unwind-misc-1.rs index 06a3f0113b01c..7e3318f865228 100644 --- a/src/test/run-fail/unwind-misc-1.rs +++ b/src/test/run-fail/unwind-misc-1.rs @@ -14,7 +14,7 @@ fn main() { let count = @mut 0u; - let mut map = core::hashmap::linear::LinearMap::new(); + let mut map = core::hashmap::HashMap::new(); let mut arr = ~[]; for uint::range(0u, 10u) |i| { arr += ~[@~"key stuff"]; diff --git a/src/test/run-pass/attr-start.rs b/src/test/run-pass/attr-start.rs new file mode 100644 index 0000000000000..933405bfc448d --- /dev/null +++ b/src/test/run-pass/attr-start.rs @@ -0,0 +1,16 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//xfail-fast + +#[start] +fn start(argc:int, argv: **u8, crate_map: *u8) -> int { + return 0; +} diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index e0720876900ff..bfc15acaa763c 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -22,7 +22,7 @@ use EBWriter = std::ebml::writer; use core::cmp::Eq; use core::io::Writer; use std::ebml; -use std::serialize::{Encodable, Decodable}; +use std::serialize::{Decodable, Encodable}; use std::time; fn test_ebml bool { !self.eq(other) } } -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] +#[deriving(Decodable, Encodable, Eq)] struct Spanned { lo: uint, hi: uint, node: T, } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] struct SomeStruct { v: ~[uint] } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] struct Point {x: uint, y: uint} -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] enum Quark { Top(T), Bottom(T) } -#[auto_encode] -#[auto_decode] +#[deriving(Decodable, Encodable)] enum CLike { A, B, C } pub fn main() { diff --git a/src/test/run-pass/bind-by-move.rs b/src/test/run-pass/bind-by-move.rs index 1e836740f8e81..d3d0e48f5b0f7 100644 --- a/src/test/run-pass/bind-by-move.rs +++ b/src/test/run-pass/bind-by-move.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test // xfail-fast extern mod std; use std::arc; -fn dispose(+_x: arc::ARC) unsafe { } +fn dispose(+_x: arc::ARC) { unsafe { } } pub fn main() { - let p = arc::arc(true); + let p = arc::ARC(true); let x = Some(p); match x { Some(z) => { dispose(z); }, diff --git a/src/test/run-pass/borrowck-borrow-from-expr-block.rs b/src/test/run-pass/borrowck-borrow-from-expr-block.rs index 401985023bcc7..afa312ea35e7e 100644 --- a/src/test/run-pass/borrowck-borrow-from-expr-block.rs +++ b/src/test/run-pass/borrowck-borrow-from-expr-block.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -13,7 +13,7 @@ fn borrow(x: &int, f: &fn(x: &int)) { } fn test1(x: @~int) { - do borrow(&*x.clone()) |p| { + do borrow(&*(*x).clone()) |p| { let x_a = ptr::addr_of(&(**x)); assert!((x_a as uint) != ptr::to_uint(p)); assert!(unsafe{*x_a} == *p); diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index 30ca5ea3881c9..e4374e4d225a7 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -49,18 +49,6 @@ pub impl cat { } } -impl<'self,T> BaseIter<(int, &'self T)> for cat { - fn each(&self, f: &fn(&(int, &'self T)) -> bool) { - let mut n = int::abs(self.meows); - while n > 0 { - if !f(&(n, &self.name)) { break; } - n -= 1; - } - } - - fn size_hint(&self) -> Option { Some(self.len()) } -} - impl Container for cat { fn len(&const self) -> uint { self.meows as uint } fn is_empty(&const self) -> bool { self.meows == 0 } @@ -71,17 +59,25 @@ impl Mutable for cat { } impl Map for cat { + fn each<'a>(&'a self, f: &fn(&int, &'a T) -> bool) { + let mut n = int::abs(self.meows); + while n > 0 { + if !f(&n, &self.name) { break; } + n -= 1; + } + } + fn contains_key(&self, k: &int) -> bool { *k <= self.meows } fn each_key(&self, f: &fn(v: &int) -> bool) { - for self.each |&(k, _)| { if !f(&k) { break; } loop;}; + for self.each |k, _| { if !f(k) { break; } loop;}; } - fn each_value(&self, f: &fn(v: &T) -> bool) { - for self.each |&(_, v)| { if !f(v) { break; } loop;}; + fn each_value<'a>(&'a self, f: &fn(v: &'a T) -> bool) { + for self.each |_, v| { if !f(v) { break; } loop;}; } - fn mutate_values(&mut self, f: &fn(&int, &mut T) -> bool) { + fn mutate_values(&mut self, _f: &fn(&int, &mut T) -> bool) { fail!(~"nope") } @@ -90,7 +86,7 @@ impl Map for cat { true } - fn find(&self, k: &int) -> Option<&'self T> { + fn find<'a>(&'a self, k: &int) -> Option<&'a T> { if *k <= self.meows { Some(&self.name) } else { @@ -98,7 +94,7 @@ impl Map for cat { } } - fn find_mut(&mut self, k: &int) -> Option<&'self mut T> { fail!() } + fn find_mut<'a>(&'a mut self, _k: &int) -> Option<&'a mut T> { fail!() } fn remove(&mut self, k: &int) -> bool { if self.find(k).is_some() { @@ -110,7 +106,7 @@ impl Map for cat { } pub impl cat { - fn get(&self, k: &int) -> &'self T { + fn get<'a>(&'a self, k: &int) -> &'a T { match self.find(k) { Some(v) => { v } None => { fail!(~"epic fail"); } diff --git a/src/test/run-pass/deriving-cmp-generic-enum.rs b/src/test/run-pass/deriving-cmp-generic-enum.rs new file mode 100644 index 0000000000000..a2651ddac3d19 --- /dev/null +++ b/src/test/run-pass/deriving-cmp-generic-enum.rs @@ -0,0 +1,50 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Eq, TotalEq, Ord, TotalOrd)] +enum E { + E0, + E1(T), + E2(T,T) +} + +pub fn main() { + let e0 = E0, e11 = E1(1), e12 = E1(2), e21 = E2(1,1), e22 = E2(1, 2); + + // in order for both Ord and TotalOrd + let es = [e0, e11, e12, e21, e22]; + + for es.eachi |i, e1| { + for es.eachi |j, e2| { + let ord = i.cmp(&j); + + let eq = i == j; + let lt = i < j, le = i <= j; + let gt = i > j, ge = i >= j; + + // Eq + assert_eq!(*e1 == *e2, eq); + assert_eq!(*e1 != *e2, !eq); + + // TotalEq + assert_eq!(e1.equals(e2), eq); + + // Ord + assert_eq!(*e1 < *e2, lt); + assert_eq!(*e1 > *e2, gt); + + assert_eq!(*e1 <= *e2, le); + assert_eq!(*e1 >= *e2, ge); + + // TotalOrd + assert_eq!(e1.cmp(e2), ord); + } + } +} diff --git a/src/test/run-pass/deriving-cmp-generic-struct-enum.rs b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs new file mode 100644 index 0000000000000..6f6e8d79d8b92 --- /dev/null +++ b/src/test/run-pass/deriving-cmp-generic-struct-enum.rs @@ -0,0 +1,52 @@ +// xfail-test #5530 + +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Eq, TotalEq, Ord, TotalOrd)] +enum ES { + ES1 { x: T }, + ES2 { x: T, y: T } +} + + +pub fn main() { + let es11 = ES1 {x: 1}, es12 = ES1 {x: 2}, es21 = ES2 {x: 1, y: 1}, es22 = ES2 {x: 1, y: 2}; + + // in order for both Ord and TotalOrd + let ess = [es11, es12, es21, es22]; + + for ess.eachi |i, es1| { + for ess.eachi |j, es2| { + let ord = i.cmp(&j); + + let eq = i == j; + let lt = i < j, le = i <= j; + let gt = i > j, ge = i >= j; + + // Eq + assert_eq!(*es1 == *es2, eq); + assert_eq!(*es1 != *es2, !eq); + + // TotalEq + assert_eq!(es1.equals(es2), eq); + + // Ord + assert_eq!(*es1 < *es2, lt); + assert_eq!(*es1 > *es2, gt); + + assert_eq!(*es1 <= *es2, le); + assert_eq!(*es1 >= *es2, ge); + + // TotalOrd + assert_eq!(es1.cmp(es2), ord); + } + } +} \ No newline at end of file diff --git a/src/test/run-pass/deriving-cmp-generic-struct.rs b/src/test/run-pass/deriving-cmp-generic-struct.rs new file mode 100644 index 0000000000000..bd3e02ba29b30 --- /dev/null +++ b/src/test/run-pass/deriving-cmp-generic-struct.rs @@ -0,0 +1,49 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Eq, TotalEq, Ord, TotalOrd)] +struct S { + x: T, + y: T +} + +pub fn main() { + let s1 = S {x: 1, y: 1}, s2 = S {x: 1, y: 2}; + + // in order for both Ord and TotalOrd + let ss = [s1, s2]; + + for ss.eachi |i, s1| { + for ss.eachi |j, s2| { + let ord = i.cmp(&j); + + let eq = i == j; + let lt = i < j, le = i <= j; + let gt = i > j, ge = i >= j; + + // Eq + assert_eq!(*s1 == *s2, eq); + assert_eq!(*s1 != *s2, !eq); + + // TotalEq + assert_eq!(s1.equals(s2), eq); + + // Ord + assert_eq!(*s1 < *s2, lt); + assert_eq!(*s1 > *s2, gt); + + assert_eq!(*s1 <= *s2, le); + assert_eq!(*s1 >= *s2, ge); + + // TotalOrd + assert_eq!(s1.cmp(s2), ord); + } + } +} \ No newline at end of file diff --git a/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs new file mode 100644 index 0000000000000..733b19a9ae2da --- /dev/null +++ b/src/test/run-pass/deriving-cmp-generic-tuple-struct.rs @@ -0,0 +1,47 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Eq, TotalEq, Ord, TotalOrd)] +struct TS(T,T); + + +pub fn main() { + let ts1 = TS(1, 1), ts2 = TS(1,2); + + // in order for both Ord and TotalOrd + let tss = [ts1, ts2]; + + for tss.eachi |i, ts1| { + for tss.eachi |j, ts2| { + let ord = i.cmp(&j); + + let eq = i == j; + let lt = i < j, le = i <= j; + let gt = i > j, ge = i >= j; + + // Eq + assert_eq!(*ts1 == *ts2, eq); + assert_eq!(*ts1 != *ts2, !eq); + + // TotalEq + assert_eq!(ts1.equals(ts2), eq); + + // Ord + assert_eq!(*ts1 < *ts2, lt); + assert_eq!(*ts1 > *ts2, gt); + + assert_eq!(*ts1 <= *ts2, le); + assert_eq!(*ts1 >= *ts2, ge); + + // TotalOrd + assert_eq!(ts1.cmp(ts2), ord); + } + } +} \ No newline at end of file diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs index fdf733d0314bc..1a2a8cab3032c 100644 --- a/src/test/run-pass/explicit-self-generic.rs +++ b/src/test/run-pass/explicit-self-generic.rs @@ -20,17 +20,17 @@ type EqFn = ~fn(K, K) -> bool; struct LM { resize_at: uint, size: uint } -enum LinearMap { - LinearMap_(LM) +enum HashMap { + HashMap_(LM) } -fn linear_map() -> LinearMap { - LinearMap_(LM{ +fn linear_map() -> HashMap { + HashMap_(LM{ resize_at: 32, size: 0}) } -pub impl LinearMap { +pub impl HashMap { fn len(&mut self) -> uint { self.size } diff --git a/src/test/run-pass/explicit-self.rs b/src/test/run-pass/explicit-self.rs index c5b5016572caa..7e46bf22c4d92 100644 --- a/src/test/run-pass/explicit-self.rs +++ b/src/test/run-pass/explicit-self.rs @@ -58,7 +58,7 @@ pub impl thing { fn foo(@self) -> int { *self.x.a } fn bar(~self) -> int { *self.x.a } fn quux(&self) -> int { *self.x.a } - fn baz(&self) -> &'self A { &self.x } + fn baz<'a>(&'a self) -> &'a A { &self.x } fn spam(self) -> int { *self.x.a } } diff --git a/src/test/run-pass/hashmap-memory.rs b/src/test/run-pass/hashmap-memory.rs index 4234c064e8d38..910708b710602 100644 --- a/src/test/run-pass/hashmap-memory.rs +++ b/src/test/run-pass/hashmap-memory.rs @@ -19,7 +19,7 @@ pub fn map(filename: ~str, emit: map_reduce::putter) { emit(filename, ~"1"); } mod map_reduce { - use core::hashmap::linear::LinearMap; + use core::hashmap::HashMap; use core::comm::*; pub type putter = @fn(~str, ~str); @@ -37,9 +37,9 @@ mod map_reduce { } fn map_task(ctrl: SharedChan, input: ~str) { - let intermediates = @mut LinearMap::new(); + let intermediates = @mut HashMap::new(); - fn emit(im: &mut LinearMap<~str, int>, ctrl: SharedChan, key: ~str, + fn emit(im: &mut HashMap<~str, int>, ctrl: SharedChan, key: ~str, _val: ~str) { if im.contains_key(&key) { return; @@ -65,9 +65,9 @@ mod map_reduce { // This task becomes the master control task. It spawns others // to do the rest. - let mut reducers: LinearMap<~str, int>; + let mut reducers: HashMap<~str, int>; - reducers = LinearMap::new(); + reducers = HashMap::new(); start_mappers(ctrl_chan, inputs.clone()); diff --git a/src/test/run-pass/issue-1696.rs b/src/test/run-pass/issue-1696.rs index 5f8b8d2983072..5b40d0abff818 100644 --- a/src/test/run-pass/issue-1696.rs +++ b/src/test/run-pass/issue-1696.rs @@ -10,10 +10,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; pub fn main() { - let mut m = LinearMap::new(); + let mut m = HashMap::new(); m.insert(str::to_bytes(~"foo"), str::to_bytes(~"bar")); error!(m); } diff --git a/src/test/run-pass/issue-2631-b.rs b/src/test/run-pass/issue-2631-b.rs index b22c423ed0412..f6e40fa247d5e 100644 --- a/src/test/run-pass/issue-2631-b.rs +++ b/src/test/run-pass/issue-2631-b.rs @@ -14,11 +14,11 @@ extern mod req; use req::*; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; pub fn main() { let v = ~[@~"hi"]; - let mut m: req::header_map = LinearMap::new(); + let mut m: req::header_map = HashMap::new(); m.insert(~"METHOD", @mut v); request::(&m); } diff --git a/src/test/run-pass/issue-2804-2.rs b/src/test/run-pass/issue-2804-2.rs index 8934c3935c087..b25e4095b185e 100644 --- a/src/test/run-pass/issue-2804-2.rs +++ b/src/test/run-pass/issue-2804-2.rs @@ -13,9 +13,9 @@ // Minimized version of issue-2804.rs. Both check that callee IDs don't // clobber the previous node ID in a macro expr -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; -fn add_interfaces(managed_ip: ~str, device: LinearMap<~str, int>) { +fn add_interfaces(managed_ip: ~str, device: HashMap<~str, int>) { error!("%s, %?", managed_ip, device.get(&~"interfaces")); } diff --git a/src/test/run-pass/issue-2804.rs b/src/test/run-pass/issue-2804.rs index 3d1a2c3df5d3b..4614c26fa5fc8 100644 --- a/src/test/run-pass/issue-2804.rs +++ b/src/test/run-pass/issue-2804.rs @@ -11,7 +11,7 @@ // except according to those terms. extern mod std; -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; use std::json; enum object { @@ -58,7 +58,7 @@ fn add_interface(store: int, managed_ip: ~str, data: std::json::Json) -> (~str, } } -fn add_interfaces(store: int, managed_ip: ~str, device: LinearMap<~str, std::json::Json>) -> ~[(~str, object)] +fn add_interfaces(store: int, managed_ip: ~str, device: HashMap<~str, std::json::Json>) -> ~[(~str, object)] { match device.get(&~"interfaces") { diff --git a/src/test/run-pass/issue-3026.rs b/src/test/run-pass/issue-3026.rs index 022d3f6fceb05..16e9b4753f830 100644 --- a/src/test/run-pass/issue-3026.rs +++ b/src/test/run-pass/issue-3026.rs @@ -10,10 +10,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; pub fn main() { - let mut buggy_map: LinearMap = LinearMap::new::(); + let mut buggy_map: HashMap = HashMap::new::(); let x = ~1; buggy_map.insert(42, &*x); } diff --git a/src/test/run-pass/issue-3559.rs b/src/test/run-pass/issue-3559.rs index f7b7605523c25..334831fea4d03 100644 --- a/src/test/run-pass/issue-3559.rs +++ b/src/test/run-pass/issue-3559.rs @@ -29,7 +29,7 @@ fn check_strs(actual: &str, expected: &str) -> bool #[test] fn tester() { - let mut table = core::hashmap::linear::LinearMap(); + let mut table = core::hashmap::HashMap(); table.insert(@~"one", 1); table.insert(@~"two", 2); assert!(check_strs(table.to_str(), ~"xxx")); // not sure what expected should be diff --git a/src/test/run-pass/issue-3702.rs b/src/test/run-pass/issue-3702.rs index eaa2ac4c4baf2..7c2f8cf98cb8a 100644 --- a/src/test/run-pass/issue-3702.rs +++ b/src/test/run-pass/issue-3702.rs @@ -13,7 +13,7 @@ pub fn main() { fn to_str(&self) -> ~str; } - fn to_string(t: Text) { + fn to_string(t: @Text) { io::println(t.to_str()); } diff --git a/src/test/run-pass/issue-3860.rs b/src/test/run-pass/issue-3860.rs index 18839fa3c7fc4..46aa7187c9a02 100644 --- a/src/test/run-pass/issue-3860.rs +++ b/src/test/run-pass/issue-3860.rs @@ -11,7 +11,7 @@ struct Foo { x: int } pub impl Foo { - fn stuff(&mut self) -> &'self mut Foo { + fn stuff<'a>(&'a mut self) -> &'a mut Foo { return self; } } diff --git a/src/test/run-pass/issue-4016.rs b/src/test/run-pass/issue-4016.rs index 69cd1a2a19d86..2384b0e859393 100644 --- a/src/test/run-pass/issue-4016.rs +++ b/src/test/run-pass/issue-4016.rs @@ -11,7 +11,7 @@ // xfail-test extern mod std; -use hashmap::linear; +use hashmap; use std::json; use std::serialization::{Deserializable, deserialize}; diff --git a/src/test/run-pass/issue-4092.rs b/src/test/run-pass/issue-4092.rs index 85cb3e3207ee7..e129e0a88687a 100644 --- a/src/test/run-pass/issue-4092.rs +++ b/src/test/run-pass/issue-4092.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::hashmap::linear::LinearMap; +use core::hashmap::HashMap; pub fn main() { - let mut x = LinearMap::new(); + let mut x = HashMap::new(); x.insert((@"abc", 0), 0); } diff --git a/src/test/run-pass/issue-5754.rs b/src/test/run-pass/issue-5754.rs new file mode 100644 index 0000000000000..c440fe525eef9 --- /dev/null +++ b/src/test/run-pass/issue-5754.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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct TwoDoubles { + r: float, + i: float +} + +extern "C" { + fn rust_dbg_extern_identity_TwoDoubles(arg1: TwoDoubles) -> TwoDoubles; +} + +pub fn main() {} diff --git a/src/test/run-pass/packed-struct-borrow-element.rs b/src/test/run-pass/packed-struct-borrow-element.rs new file mode 100644 index 0000000000000..a331b80a894ea --- /dev/null +++ b/src/test/run-pass/packed-struct-borrow-element.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct Foo { + bar: u8, + baz: uint +} + +fn main() { + let foo = Foo { bar: 1, baz: 2 }; + let brw = &foo.baz; + + assert_eq!(*brw, 2); +} diff --git a/src/test/run-pass/packed-struct-generic-layout.rs b/src/test/run-pass/packed-struct-generic-layout.rs new file mode 100644 index 0000000000000..fd6e3b670f5ab --- /dev/null +++ b/src/test/run-pass/packed-struct-generic-layout.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct S { + a: T, + b: u8, + c: S +} + +fn main() { + unsafe { + let s = S { a: 0xff_ff_ff_ffu32, b: 1, c: 0xaa_aa_aa_aa as i32 }; + let transd : [u8, .. 9] = cast::transmute(s); + // Don't worry about endianness, the numbers are palindromic. + assert_eq!(transd, + [0xff, 0xff, 0xff, 0xff, + 1, + 0xaa, 0xaa, 0xaa, 0xaa]); + + + let s = S { a: 1u8, b: 2u8, c: 0b10000001_10000001 as i16}; + let transd : [u8, .. 4] = cast::transmute(s); + // Again, no endianness problems. + assert_eq!(transd, + [1, 2, 0b10000001, 0b10000001]); + } +} diff --git a/src/test/run-pass/packed-struct-generic-size.rs b/src/test/run-pass/packed-struct-generic-size.rs new file mode 100644 index 0000000000000..a5c4d5385a297 --- /dev/null +++ b/src/test/run-pass/packed-struct-generic-size.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct S { + a: T, + b: u8, + c: S +} + +fn main() { + assert_eq!(sys::size_of::>(), 3); + + assert_eq!(sys::size_of::>(), 11); + + assert_eq!(sys::size_of::>(), + 1 + sys::size_of::<~str>() + sys::size_of::<@mut [int]>()); +} diff --git a/src/test/run-pass/packed-struct-layout.rs b/src/test/run-pass/packed-struct-layout.rs new file mode 100644 index 0000000000000..8d27e55e191a4 --- /dev/null +++ b/src/test/run-pass/packed-struct-layout.rs @@ -0,0 +1,34 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct S4 { + a: u8, + b: [u8, .. 3], +} + +#[packed] +struct S5 { + a: u8, + b: u32 +} + +fn main() { + unsafe { + let s4 = S4 { a: 1, b: [2,3,4] }; + let transd : [u8, .. 4] = cast::transmute(s4); + assert_eq!(transd, [1, 2, 3, 4]); + + let s5 = S5 { a: 1, b: 0xff_00_00_ff }; + let transd : [u8, .. 5] = cast::transmute(s5); + // Don't worry about endianness, the u32 is palindromic. + assert_eq!(transd, [1, 0xff, 0, 0, 0xff]); + } +} diff --git a/src/test/run-pass/packed-struct-match.rs b/src/test/run-pass/packed-struct-match.rs new file mode 100644 index 0000000000000..15e7b6b0ce0c5 --- /dev/null +++ b/src/test/run-pass/packed-struct-match.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct Foo { + bar: u8, + baz: uint +} + +fn main() { + let foo = Foo { bar: 1, baz: 2 }; + match foo { + Foo {bar, baz} => { + assert_eq!(bar, 1); + assert_eq!(baz, 2); + } + } +} diff --git a/src/test/run-pass/packed-struct-size.rs b/src/test/run-pass/packed-struct-size.rs new file mode 100644 index 0000000000000..372fe3d37f69d --- /dev/null +++ b/src/test/run-pass/packed-struct-size.rs @@ -0,0 +1,58 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct S4 { + a: u8, + b: [u8, .. 3], +} + +#[packed] +struct S5 { + a: u8, + b: u32 +} + +#[packed] +struct S13_str { + a: i64, + b: f32, + c: u8, + d: ~str +} + +enum Foo { + Bar = 1, + Baz = 2 +} + +#[packed] +struct S3_Foo { + a: u8, + b: u16, + c: Foo +} + +#[packed] +struct S7_Option { + a: f32, + b: u8, + c: u16, + d: Option<@mut f64> +} + + +fn main() { + assert_eq!(sys::size_of::(), 4); + assert_eq!(sys::size_of::(), 5); + assert_eq!(sys::size_of::(), 13 + sys::size_of::<~str>()); + assert_eq!(sys::size_of::(), 3 + sys::size_of::()); + assert_eq!(sys::size_of::(), 7 + sys::size_of::>()); +} diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs new file mode 100644 index 0000000000000..b1ac29b7721a8 --- /dev/null +++ b/src/test/run-pass/packed-struct-vec.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +#[deriving(Eq)] +struct Foo { + bar: u8, + baz: u64 +} + +fn main() { + let foos = [Foo { bar: 1, baz: 2 }, .. 10]; + + assert_eq!(sys::size_of::<[Foo, .. 10]>(), 90); + + for uint::range(0, 10) |i| { + assert_eq!(foos[i], Foo { bar: 1, baz: 2}); + } + + for foos.each |&foo| { + assert_eq!(foo, Foo { bar: 1, baz: 2 }); + } +} diff --git a/src/test/run-pass/packed-tuple-struct-layout.rs b/src/test/run-pass/packed-tuple-struct-layout.rs new file mode 100644 index 0000000000000..9c2fe621a321a --- /dev/null +++ b/src/test/run-pass/packed-tuple-struct-layout.rs @@ -0,0 +1,28 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct S4(u8,[u8, .. 3]); + +#[packed] +struct S5(u8,u32); + +fn main() { + unsafe { + let s4 = S4(1, [2,3,4]); + let transd : [u8, .. 4] = cast::transmute(s4); + assert_eq!(transd, [1, 2, 3, 4]); + + let s5 = S5(1, 0xff_00_00_ff); + let transd : [u8, .. 5] = cast::transmute(s5); + // Don't worry about endianness, the u32 is palindromic. + assert_eq!(transd, [1, 0xff, 0, 0, 0xff]); + } +} diff --git a/src/test/run-pass/packed-tuple-struct-size.rs b/src/test/run-pass/packed-tuple-struct-size.rs new file mode 100644 index 0000000000000..23faa2eb0adc9 --- /dev/null +++ b/src/test/run-pass/packed-tuple-struct-size.rs @@ -0,0 +1,44 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[packed] +struct S4(u8,[u8, .. 3]); + +#[packed] +struct S5(u8, u32); + +#[packed] +struct S13_str(i64, f32, u8, ~str); + +enum Foo { + Bar = 1, + Baz = 2 +} + +#[packed] +struct S3_Foo(u8, u16, Foo); + +#[packed] +struct S7_Option(f32, u8, u16, Option<@mut f64>); + +fn main() { + assert_eq!(sys::size_of::(), 4); + + assert_eq!(sys::size_of::(), 5); + + assert_eq!(sys::size_of::(), + 13 + sys::size_of::<~str>()); + + assert_eq!(sys::size_of::(), + 3 + sys::size_of::()); + + assert_eq!(sys::size_of::(), + 7 + sys::size_of::>()); +} diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index 565c06fb8c890..8f3a1dd90c24c 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -13,7 +13,7 @@ use core::bool; use core::libc::c_void; use core::vec::UnboxedVecRepr; -use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor}; +use intrinsic::{TyDesc, get_tydesc, visit_tydesc, TyVisitor, Opaque}; #[doc = "High-level interfaces to `intrinsic::visit_ty` reflection system."] @@ -376,10 +376,12 @@ impl TyVisitor for ptr_visit_adaptor { true } - fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) + fn visit_enter_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, + sz: uint, align: uint) -> bool { self.align(align); - if ! self.inner.visit_enter_enum(n_variants, sz, align) { return false; } + if ! self.inner.visit_enter_enum(n_variants, get_disr, sz, align) { return false; } true } @@ -394,8 +396,8 @@ impl TyVisitor for ptr_visit_adaptor { true } - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { - if ! self.inner.visit_enum_variant_field(i, inner) { return false; } + fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool { + if ! self.inner.visit_enum_variant_field(i, offset, inner) { return false; } true } @@ -410,16 +412,18 @@ impl TyVisitor for ptr_visit_adaptor { true } - fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) + fn visit_leave_enum(&self, n_variants: uint, + get_disr: extern unsafe fn(ptr: *Opaque) -> int, + sz: uint, align: uint) -> bool { - if ! self.inner.visit_leave_enum(n_variants, sz, align) { return false; } + if ! self.inner.visit_leave_enum(n_variants, get_disr, sz, align) { return false; } true } fn visit_trait(&self) -> bool { - self.align_to::(); + self.align_to::<@TyVisitor>(); if ! self.inner.visit_trait() { return false; } - self.bump_past::(); + self.bump_past::<@TyVisitor>(); true } @@ -586,6 +590,7 @@ impl TyVisitor for my_visitor { _sz: uint, _align: uint) -> bool { true } fn visit_enter_enum(&self, _n_variants: uint, + _get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { // FIXME (#3732): this needs to rewind between enum variants, or something. true @@ -594,7 +599,7 @@ impl TyVisitor for my_visitor { _disr_val: int, _n_fields: uint, _name: &str) -> bool { true } - fn visit_enum_variant_field(&self, _i: uint, inner: *TyDesc) -> bool { + fn visit_enum_variant_field(&self, _i: uint, _offset: uint, inner: *TyDesc) -> bool { self.visit_inner(inner) } fn visit_leave_enum_variant(&self, _variant: uint, @@ -602,6 +607,7 @@ impl TyVisitor for my_visitor { _n_fields: uint, _name: &str) -> bool { true } fn visit_leave_enum(&self, _n_variants: uint, + _get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { true } fn visit_enter_fn(&self, _purity: uint, _proto: uint, diff --git a/src/test/run-pass/region-dependent-addr-of.rs b/src/test/run-pass/region-dependent-addr-of.rs index 42784200b6639..dd33f7f1e309b 100644 --- a/src/test/run-pass/region-dependent-addr-of.rs +++ b/src/test/run-pass/region-dependent-addr-of.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test lifetimes are linked properly when we create dependent region pointers. +// Issue #3148. + struct A { value: B } diff --git a/src/test/run-pass/by-val-and-by-move.rs b/src/test/run-pass/region-dependent-autofn.rs similarity index 66% rename from src/test/run-pass/by-val-and-by-move.rs rename to src/test/run-pass/region-dependent-autofn.rs index 47d2f9e1df080..82d4115d66d9f 100644 --- a/src/test/run-pass/by-val-and-by-move.rs +++ b/src/test/run-pass/region-dependent-autofn.rs @@ -8,19 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test #2443 -// exec-env:RUST_POISON_ON_FREE +// Test lifetimes are linked properly when we autoslice a vector. +// Issue #3148. -fn it_takes_two(x: @int, -y: @int) -> int { - free(y); - debug!("about to deref"); - *x -} +fn subslice<'r>(v: &'r fn()) -> &'r fn() { v } -fn free(-_t: T) { +fn both<'r>(v: &'r fn()) -> &'r fn() { + subslice(subslice(v)) } -pub fn main() { - let z = @3; - assert!(3 == it_takes_two(z, z)); +fn main() { + both(main); } diff --git a/src/test/compile-fail/issue-3311.rs b/src/test/run-pass/region-dependent-autoslice.rs similarity index 59% rename from src/test/compile-fail/issue-3311.rs rename to src/test/run-pass/region-dependent-autoslice.rs index 67059e4623e8f..10c2988fc9f26 100644 --- a/src/test/compile-fail/issue-3311.rs +++ b/src/test/run-pass/region-dependent-autoslice.rs @@ -8,24 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[legacy_mode] -struct Foo<'self> { - s: &'self str, - u: ~() -} +// Test lifetimes are linked properly when we autoslice a vector. +// Issue #3148. -pub impl<'self> Foo<'self> { - fn get_s(&self) -> &'self str { - self.s - } -} +fn subslice1<'r>(v: &'r [uint]) -> &'r [uint] { v } -fn bar(s: &str, f: &fn(Option)) { - f(Some(Foo {s: s, u: ~()})); +fn both<'r>(v: &'r [uint]) -> &'r [uint] { + subslice1(subslice1(v)) } fn main() { - do bar(~"testing") |opt| { - io::println(opt.unwrap().get_s()); //~ ERROR illegal borrow: - }; + let v = ~[1,2,3]; + both(v); } diff --git a/src/test/run-pass/regions-expl-self.rs b/src/test/run-pass/regions-expl-self.rs index 05f0994c7655d..174b9a206ccdf 100644 --- a/src/test/run-pass/regions-expl-self.rs +++ b/src/test/run-pass/regions-expl-self.rs @@ -15,7 +15,7 @@ struct Foo { } pub impl Foo { - fn foo(&'a self) {} + fn foo<'a>(&'a self) {} } pub fn main() {} \ No newline at end of file diff --git a/src/test/run-pass/regions-self-impls.rs b/src/test/run-pass/regions-self-impls.rs index 16b6364093e2e..2f4eefe5243ad 100644 --- a/src/test/run-pass/regions-self-impls.rs +++ b/src/test/run-pass/regions-self-impls.rs @@ -16,7 +16,7 @@ trait get_chowder<'self> { fn get_chowder(&self) -> &'self int; } -impl<'self> get_chowder for Clam<'self> { +impl<'self> get_chowder<'self> for Clam<'self> { fn get_chowder(&self) -> &'self int { return self.chowder; } } diff --git a/src/test/run-pass/regions-trait.rs b/src/test/run-pass/regions-trait.rs index f453272057975..a2ed9da67f264 100644 --- a/src/test/run-pass/regions-trait.rs +++ b/src/test/run-pass/regions-trait.rs @@ -16,7 +16,7 @@ trait get_ctxt<'self> { struct HasCtxt<'self> { c: &'self Ctxt } -impl<'self> get_ctxt for HasCtxt<'self> { +impl<'self> get_ctxt<'self> for HasCtxt<'self> { fn get_ctxt(&self) -> &'self Ctxt { self.c } diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs index b800ffefeb694..0fb2a6b2e724b 100644 --- a/src/test/run-pass/trait-inheritance-num.rs +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -16,7 +16,7 @@ use core::cmp::{Eq, Ord}; use core::num::NumCast::from; use std::cmp::FuzzyEq; -pub trait NumExt: NumCast + Eq + Ord {} +pub trait NumExt: Num + NumCast + Eq + Ord {} pub trait FloatExt: NumExt + FuzzyEq {} diff --git a/src/test/run-pass/trait-inheritance-num1.rs b/src/test/run-pass/trait-inheritance-num1.rs index 07b9772af2970..d580b99012fa5 100644 --- a/src/test/run-pass/trait-inheritance-num1.rs +++ b/src/test/run-pass/trait-inheritance-num1.rs @@ -11,7 +11,7 @@ use core::cmp::Ord; use core::num::NumCast::from; -pub trait NumExt: NumCast + Ord { } +pub trait NumExt: Num + NumCast + Ord { } fn greater_than_one(n: &T) -> bool { *n > from(1) diff --git a/src/test/run-pass/trait-inheritance-num2.rs b/src/test/run-pass/trait-inheritance-num2.rs index 66d7ee96bb250..b40f647814f0c 100644 --- a/src/test/run-pass/trait-inheritance-num2.rs +++ b/src/test/run-pass/trait-inheritance-num2.rs @@ -38,7 +38,7 @@ impl TypeExt for f64 {} impl TypeExt for float {} -pub trait NumExt: TypeExt + Eq + Ord + NumCast {} +pub trait NumExt: TypeExt + Eq + Ord + Num + NumCast {} impl NumExt for u8 {} impl NumExt for u16 {} diff --git a/src/test/run-pass/trait-inheritance-num3.rs b/src/test/run-pass/trait-inheritance-num3.rs index 67861709e76f2..5f1fef80ef201 100644 --- a/src/test/run-pass/trait-inheritance-num3.rs +++ b/src/test/run-pass/trait-inheritance-num3.rs @@ -11,7 +11,7 @@ use core::cmp::{Eq, Ord}; use core::num::NumCast::from; -pub trait NumExt: Eq + Ord + NumCast {} +pub trait NumExt: Eq + Ord + Num + NumCast {} impl NumExt for f32 {} diff --git a/src/test/run-pass/trait-inheritance-num5.rs b/src/test/run-pass/trait-inheritance-num5.rs index 2efe5b23eb57b..02cc9a3d221f8 100644 --- a/src/test/run-pass/trait-inheritance-num5.rs +++ b/src/test/run-pass/trait-inheritance-num5.rs @@ -11,7 +11,7 @@ use core::cmp::{Eq, Ord}; use core::num::NumCast::from; -pub trait NumExt: Eq + NumCast {} +pub trait NumExt: Eq + Num + NumCast {} impl NumExt for f32 {} impl NumExt for int {} diff --git a/src/test/run-pass/trait-inheritance-self-in-supertype.rs b/src/test/run-pass/trait-inheritance-self-in-supertype.rs new file mode 100644 index 0000000000000..8105cf23d8004 --- /dev/null +++ b/src/test/run-pass/trait-inheritance-self-in-supertype.rs @@ -0,0 +1,61 @@ +// Test for issue #4183: use of Self in supertraits. + +pub static FUZZY_EPSILON: float = 0.1; + +pub trait FuzzyEq { + fn fuzzy_eq(&self, other: &Self) -> bool; + fn fuzzy_eq_eps(&self, other: &Self, epsilon: &Eps) -> bool; +} + +trait Float: FuzzyEq { + fn two_pi() -> Self; +} + +impl FuzzyEq for f32 { + fn fuzzy_eq(&self, other: &f32) -> bool { + self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f32)) + } + + fn fuzzy_eq_eps(&self, other: &f32, epsilon: &f32) -> bool { + f32::abs(*self - *other) < *epsilon + } +} + +impl Float for f32 { + fn two_pi() -> f32 { 6.28318530717958647692528676655900576_f32 } +} + +impl FuzzyEq for f64 { + fn fuzzy_eq(&self, other: &f64) -> bool { + self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f64)) + } + + fn fuzzy_eq_eps(&self, other: &f64, epsilon: &f64) -> bool { + f64::abs(*self - *other) < *epsilon + } +} + +impl Float for f64 { + fn two_pi() -> f64 { 6.28318530717958647692528676655900576_f64 } +} + +fn compare(f1: F) -> bool { + let f2 = Float::two_pi(); + f1.fuzzy_eq(&f2) +} + +pub fn main() { + assert!(compare::(6.28318530717958647692528676655900576)); + assert!(compare::(6.29)); + assert!(compare::(6.3)); + assert!(compare::(6.19)); + assert!(!compare::(7.28318530717958647692528676655900576)); + assert!(!compare::(6.18)); + + assert!(compare::(6.28318530717958647692528676655900576)); + assert!(compare::(6.29)); + assert!(compare::(6.3)); + assert!(compare::(6.19)); + assert!(!compare::(7.28318530717958647692528676655900576)); + assert!(!compare::(6.18)); +} \ No newline at end of file diff --git a/src/test/run-pass/use.rs b/src/test/run-pass/use.rs index 2a24bfe72d295..0bd4175d39043 100644 --- a/src/test/run-pass/use.rs +++ b/src/test/run-pass/use.rs @@ -13,7 +13,7 @@ #[no_core]; extern mod core; extern mod zed(name = "core"); -extern mod bar(name = "core", vers = "0.6"); +extern mod bar(name = "core", vers = "0.7-pre"); use core::str;