This implementation does have the minor issue of not handling things correctly when a codepoint is split across multiple writes or reads, but its better than not having unicode support at all.
Adds a Windows specific struct `WindowsTTY` in `libnative` and make `tty_open` create that struct on Windows. Adds needed functions and constants to `c_win32.rs`.
Libuv still needs to be updated before #15028 can be closed.
if [[ $LLVM_VERSION != '3.4' ]]; then exit 0; fi
fi &&
make tidy &&
- travis_wait make -j4 rustc-stage1 &&
+ make -j4 rustc-stage1 RUSTFLAGS='-Z time-passes' &&
make check-stage1-std check-stage1-rpass check-stage1-cfail check-stage1-rfail check-stage1-doc
env:
-.TH RUSTC "1" "March 2014" "rustc 0.11-pre" "User Commands"
+.TH RUSTC "1" "March 2014" "rustc 0.11.0" "User Commands"
.SH NAME
rustc \- The Rust compiler
.SH SYNOPSIS
-.TH RUSTDOC "1" "March 2014" "rustdoc 0.11-pre" "User Commands"
+.TH RUSTDOC "1" "March 2014" "rustdoc 0.11.0" "User Commands"
.SH NAME
rustdoc \- generate documentation from Rust source code
.SH SYNOPSIS
# The version number
CFG_RELEASE_NUM=0.11.0
-CFG_RELEASE_LABEL=-pre
+CFG_RELEASE_LABEL=
ifndef CFG_ENABLE_NIGHTLY
# This is the normal version string
CFG_LDPATH_i686-pc-mingw32 :=$(CFG_LDPATH_i686-pc-mingw32):$(PATH)
CFG_RUN_i686-pc-mingw32=PATH="$(CFG_LDPATH_i686-pc-mingw32):$(1)" $(2)
CFG_RUN_TARG_i686-pc-mingw32=$(call CFG_RUN_i686-pc-mingw32,$(HLIB$(1)_H_$(CFG_BUILD)),$(2))
+RUSTC_FLAGS_i686-pc-mingw32=-C link-args="-Wl,--large-address-aware"
# i586-mingw32msvc configuration
CC_i586-mingw32msvc=$(CFG_MINGW32_CROSS_PATH)/bin/i586-mingw32msvc-gcc
~~~~
po4a --copyright-holder="The Rust Project Developers" \
--package-name="Rust" \
- --package-version="0.11.0-pre" \
+ --package-version="0.11.0" \
-M UTF-8 -L UTF-8 \
src/doc/po4a.conf
~~~~
-(the version number must be changed if it is not 0.11.0-pre now.)
+(the version number must be changed if it is not 0.11.0 now.)
Now you can translate documents with .po files, commonly used with gettext. If
you are not familiar with gettext-based translation, please read the online
You can re-run this script any time you want to update Rust. Which, at this
point, is often. Rust is still pre-1.0, and so people assume that you're using
-a very recent Rust.
+a very recent Rust.
This brings me to one other point: some people, and somewhat rightfully so, get
very upset when we tell you to `curl | sudo sh`. And they should be! Basically,
```
fn main() {
-
+
}
```
```{bash}
$ cargo build
Compiling hello_world v0.1.0 (file:/home/yourname/projects/hello_world)
-$ ./target/hello_world
+$ ./target/hello_world
Hello, world!
```
```
If I asked you to read this out loud to the rest of the class, you'd say "`x`
-is a binding with the type `int` and the value `five`." Rust requires you to
-initialize the binding with a value before you're allowed to use it. If
-we try...
+is a binding with the type `int` and the value `five`."
+
+By default, bindings are **immutable**. This code will not compile:
+
+```{ignore}
+let x = 5i;
+x = 10i;
+```
+
+It will give you this error:
+
+```{ignore,notrust}
+error: re-assignment of immutable variable `x`
+ x = 10i;
+ ^~~~~~~
+```
+
+If you want a binding to be mutable, you can use `mut`:
+
+```{rust}
+let mut x = 5i;
+x = 10i;
+```
+
+There is no single reason that bindings are immutable by default, but we can
+think about it through one of Rust's primary focuses: safety. If you forget to
+say `mut`, the compiler will catch it, and let you know that you have mutated
+something you may not have cared to mutate. If bindings were mutable by
+default, the compiler would not be able to tell you this. If you _did_ intend
+mutation, then the solution is quite easy: add `mut`.
+
+There are other good reasons to avoid mutable state when possible, but they're
+out of the scope of this guide. In general, you can often avoid explicit
+mutation, and so it is preferable in Rust. That said, sometimes, mutation is
+what you need, so it's not verboten.
+
+Let's get back to bindings. Rust variable bindings have one more aspect that
+differs from other languages: bindings are required to be initialized with a
+value before you're allowed to use it. If we try...
```{ignore}
let x;
## If
+Rust's take on `if` is not particularly complex, but it's much more like the
+`if` you'll find in a dynamically typed language than in a more traditional
+systems language. So let's talk about it, to make sure you grasp the nuances.
+
+`if` is a specific form of a more general concept, the 'branch.' The name comes
+from a branch in a tree: a decision point, where depending on a choice,
+multiple paths can be taken.
+
+In the case of `if`, there is one choice that leads down two paths:
+
+```rust
+let x = 5i;
+
+if x == 5i {
+ println!("x is five!");
+}
+```
+
+If we changed the value of `x` to something else, this line would not print.
+More specifically, if the expression after the `if` evaluates to `true`, then
+the block is executed. If it's `false`, then it is not.
+
+If you want something to happen in the `false` case, use an `else`:
+
+```
+let x = 5i;
+
+if x == 5i {
+ println!("x is five!");
+} else {
+ println!("x is not five :(");
+}
+```
+
+This is all pretty standard. However, you can also do this:
+
+
+```
+let x = 5i;
+
+let y = if x == 5i {
+ 10i
+} else {
+ 15i
+};
+```
+
+Which we can (and probably should) write like this:
+
+```
+let x = 5i;
+
+let y = if x == 5i { 10i } else { 15i };
+```
+
+This reveals two interesting things about Rust: it is an expression-based
+language, and semicolons are different than in other 'curly brace and
+semicolon'-based languages. These two things are related.
+
+### Expressions vs. Statements
+
+Rust is primarily an expression based language. There are only two kinds of
+statements, and everything else is an expression.
+
+So what's the difference? Expressions return a value, and statements do not.
+In many languages, `if` is a statement, and therefore, `let x = if ...` would
+make no sense. But in Rust, `if` is an expression, which means that it returns
+a value. We can then use this value to initialize the binding.
+
+Speaking of which, bindings are a kind of the first of Rust's two statements.
+The proper name is a **declaration statement**. So far, `let` is the only kind
+of declaration statement we've seen. Let's talk about that some more.
+
+In some languages, variable bindings can be written as expressions, not just
+statements. Like Ruby:
+
+```{ruby}
+x = y = 5
+```
+
+In Rust, however, using `let` to introduce a binding is _not_ an expression. The
+following will produce a compile-time error:
+
+```{ignore}
+let x = (let y = 5i); // found `let` in ident position
+```
+
+The compiler is telling us here that it was expecting to see the beginning of
+an expression, and a `let` can only begin a statement, not an expression.
+
+However, re-assigning to a mutable binding is an expression:
+
+```{rust}
+let mut x = 0i;
+let y = x = 5i;
+```
+
+In this case, we have an assignment expression (`x = 5`) whose value is
+being used as part of a `let` declaration statement (`let y = ...`).
+
+The second kind of statement in Rust is the **expression statement**. Its
+purpose is to turn any expression into a statement. In practical terms, Rust's
+grammar expects statements to follow other statements. This means that you use
+semicolons to separate expressions from each other. This means that Rust
+looks a lot like most other languages that require you to use semicolons
+at the end of every line, and you will see semicolons at the end of almost
+every line of Rust code you see.
+
+What is this exception that makes us say 'almost?' You saw it already, in this
+code:
+
+```
+let x = 5i;
+
+let y: int = if x == 5i { 10i } else { 15i };
+```
+
+Note that I've added the type annotation to `y`, to specify explicitly that I
+want `y` to be an integer.
+
+This is not the same as this, which won't compile:
+
+```{ignore}
+let x = 5i;
+
+let y: int = if x == 5 { 10i; } else { 15i; };
+```
+
+Note the semicolons after the 10 and 15. Rust will give us the following error:
+
+```{ignore,notrust}
+error: mismatched types: expected `int` but found `()` (expected int but found ())
+```
+
+We expected an integer, but we got `()`. `()` is pronounced 'unit', and is a
+special type in Rust's type system. `()` is different than `null` in other
+languages, because `()` is distinct from other types. For example, in C, `null`
+is a valid value for a variable of type `int`. In Rust, `()` is _not_ a valid
+value for a variable of type `int`. It's only a valid value for variables of
+the type `()`, which aren't very useful. Remember how we said statements don't
+return a value? Well, that's the purpose of unit in this case. The semicolon
+turns any expression into a statement by throwing away its value and returning
+unit instead.
+
+There's one more time in which you won't see a semicolon at the end of a line
+of Rust code. For that, we'll need our next concept: functions.
+
## Functions
+You've already seen one function so far, the `main` function:
+
+```{rust}
+fn main() {
+}
+```
+
+This is the simplest possible function declaration. As we mentioned before,
+`fn` says 'this is a function,' followed by the name, some parenthesis because
+this function takes no arguments, and then some curly braces to indicate the
+body. Here's a function named `foo`:
+
+```{rust}
+fn foo() {
+}
+```
+
+So, what about taking arguments? Here's a function that prints a number:
+
+```{rust}
+fn print_number(x: int) {
+ println!("x is: {}", x);
+}
+```
+
+Here's a complete program that uses `print_number`:
+
+```{rust}
+fn main() {
+ print_number(5);
+}
+
+fn print_number(x: int) {
+ println!("x is: {}", x);
+}
+```
+
+As you can see, function arguments work very similar to `let` declarations:
+you add a type to the argument name, after a colon.
+
+Here's a complete program that adds two numbers together and prints them:
+
+```{rust}
+fn main() {
+ print_sum(5, 6);
+}
+
+fn print_sum(x: int, y: int) {
+ println!("sum is: {}", x + y);
+}
+```
+
+You separate arguments with a comma, both when you call the function, as well
+as when you declare it.
+
+Unlike `let`, you _must_ declare the types of function arguments. This does
+not work:
+
+```{ignore}
+fn print_number(x, y) {
+ println!("x is: {}", x + y);
+}
+```
+
+You get this error:
+
+```{ignore,notrust}
+hello.rs:5:18: 5:19 error: expected `:` but found `,`
+hello.rs:5 fn print_number(x, y) {
+```
+
+This is a deliberate design decision. While full-program inference is possible,
+languages which have it, like Haskell, often suggest that documenting your
+types explicitly is a best-practice. We agree that forcing functions to declare
+types while allowing for inference inside of function bodies is a wonderful
+compromise between full inference and no inference.
+
+What about returning a value? Here's a function that adds one to an integer:
+
+```{rust}
+fn add_one(x: int) -> int {
+ x + 1
+}
+```
+
+Rust functions return exactly one value, and you declare the type after an
+'arrow', which is a dash (`-`) followed by a greater-than sign (`>`).
+
+You'll note the lack of a semicolon here. If we added it in:
+
+```{ignore}
+fn add_one(x: int) -> int {
+ x + 1;
+}
+```
+
+We would get an error:
+
+```{ignore,notrust}
+note: consider removing this semicolon:
+ x + 1;
+ ^
+error: not all control paths return a value
+fn add_one(x: int) -> int {
+ x + 1;
+}
+```
+
+Remember our earlier discussions about semicolons and `()`? Our function claims
+to return an `int`, but with a semicolon, it would return `()` instead. Rust
+realizes this probably isn't what we want, and suggests removing the semicolon.
+
+This is very much like our `if` statement before: the result of the block
+(`{}`) is the value of the expression. Other expression-oriented languages,
+such as Ruby, work like this, but it's a bit unusual in the systems programming
+world. When people first learn about this, they usually assume that it
+introduces bugs. But because Rust's type system is so strong, and because unit
+is its own unique type, we have never seen an issue where adding or removing a
+semicolon in a return position would cause a bug.
+
+But what about early returns? Rust does have a keyword for that, `return`:
+
+```{rust}
+fn foo(x: int) -> int {
+ if x < 5 { return x; }
+
+ x + 1
+}
+```
+
+Using a `return` as the last line of a function works, but is considered poor
+style:
+
+```{rust}
+fn foo(x: int) -> int {
+ if x < 5 { return x; }
+
+ return x + 1;
+}
+```
+
+There are some additional ways to define functions, but they involve features
+that we haven't learned about yet, so let's just leave it at that for now.
+
+## Comments
+
return
comments
-moz-column-count: 2;
-webkit-column-count: 2;
font-size: 15px;
+ margin: 0 0 1em 0;
}
p {
margin: 0 0 1em 0;
nav ul {
list-style-type: none;
- margin: 0 0 20px 0;
+ margin: 0;
padding-left: 0px;
}
* `str_eq`
: Compare two strings (`&str`) for equality.
-* `uniq_str_eq`
- : Compare two owned strings (`String`) for equality.
* `strdup_uniq`
: Return a new unique string
containing a copy of the contents of a unique string.
#### Moved and copied types
When a [local variable](#memory-slots) is used
-as an [rvalue](#lvalues-rvalues-and-temporaries)
+as an [rvalue](#lvalues,-rvalues-and-temporaries)
the variable will either be moved or copied, depending on its type.
For types that contain [owning pointers](#pointer-types)
or values that implement the special trait `Drop`,
### Path expressions
A [path](#paths) used as an expression context denotes either a local variable or an item.
-Path expressions are [lvalues](#lvalues-rvalues-and-temporaries).
+Path expressions are [lvalues](#lvalues,-rvalues-and-temporaries).
### Tuple expressions
(Struct {a: 10, b: 20}).a;
~~~~
-A field access is an [lvalue](#lvalues-rvalues-and-temporaries) referring to the value of that field.
+A field access is an [lvalue](#lvalues,-rvalues-and-temporaries) referring to the value of that field.
When the type providing the field inherits mutabilty, it can be [assigned](#assignment-expressions) to.
Also, if the type of the expression to the left of the dot is a pointer,
[Vector](#vector-types)-typed expressions can be indexed by writing a
square-bracket-enclosed expression (the index) after them. When the
-vector is mutable, the resulting [lvalue](#lvalues-rvalues-and-temporaries) can be assigned to.
+vector is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to.
Indices are zero-based, and may be of any integral type. Vector access
is bounds-checked at run-time. When the check fails, it will put the
: Negation. May only be applied to numeric types.
* `*`
: Dereference. When applied to a [pointer](#pointer-types) it denotes the pointed-to location.
- For pointers to mutable locations, the resulting [lvalue](#lvalues-rvalues-and-temporaries) can be assigned to.
+ For pointers to mutable locations, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can be assigned to.
On non-pointer types, it calls the `deref` method of the `std::ops::Deref` trait, or the
`deref_mut` method of the `std::ops::DerefMut` trait (if implemented by the type and required
for an outer expression that will or could mutate the dereference), and produces the
#### Assignment expressions
-An _assignment expression_ consists of an [lvalue](#lvalues-rvalues-and-temporaries) expression followed by an
-equals sign (`=`) and an [rvalue](#lvalues-rvalues-and-temporaries) expression.
+An _assignment expression_ consists of an [lvalue](#lvalues,-rvalues-and-temporaries) expression followed by an
+equals sign (`=`) and an [rvalue](#lvalues,-rvalues-and-temporaries) expression.
Evaluating an assignment expression [either copies or moves](#moved-and-copied-types) its right-hand operand to its left-hand operand.
~~~~
A `match` behaves differently depending on whether or not the head expression
-is an [lvalue or an rvalue](#lvalues-rvalues-and-temporaries).
+is an [lvalue or an rvalue](#lvalues,-rvalues-and-temporaries).
If the head expression is an rvalue, it is
first evaluated into a temporary location, and the resulting value
is sequentially compared to the patterns in the arms until a match
: These point to memory _owned by some other value_.
References arise by (automatic) conversion from owning pointers, managed pointers,
or by applying the borrowing operator `&` to some other value,
- including [lvalues, rvalues or temporaries](#lvalues-rvalues-and-temporaries).
+ including [lvalues, rvalues or temporaries](#lvalues,-rvalues-and-temporaries).
References are written `&content`, or in some cases `&'f content` for some lifetime-variable `f`,
for example `&int` means a reference to an integer.
Copying a reference is a "shallow" operation:
A task's stack contains slots.
A _slot_ is a component of a stack frame, either a function parameter,
-a [temporary](#lvalues-rvalues-and-temporaries), or a local variable.
+a [temporary](#lvalues,-rvalues-and-temporaries), or a local variable.
A _local variable_ (or *stack-local* allocation) holds a value directly,
allocated within the stack's memory. The value is a part of the stack frame.
Given the input integer `n`, this function will calculate `n!` and return it.
"]
-pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n)} }
+pub fn factorial(n: int) -> int { if n < 2 {1} else {n * factorial(n - 1)} }
# fn main() {}
~~~
Rust's `match` construct is a generalized, cleaned-up version of C's
`switch` construct. You provide it with a value and a number of
-*arms*, each labelled with a pattern, and the code compares the value
+*arms*, each labeled with a pattern, and the code compares the value
against each pattern in order until one matches. The matching pattern
executes its corresponding arm.
of their contents and so the compiler cannot reason about those properties.
You can instruct the compiler, however, that the contents of a trait object must
-acribe to a particular bound with a trailing colon (`:`). These are examples of
+ascribe to a particular bound with a trailing colon (`:`). These are examples of
valid types:
~~~rust
In type-parameterized functions,
methods of the supertrait may be called on values of subtrait-bound type parameters.
-Refering to the previous example of `trait Circle : Shape`:
+Referring to the previous example of `trait Circle : Shape`:
~~~
# trait Shape { fn area(&self) -> f64; }
fi
}
+need_cmd() {
+ if command -v $1 >/dev/null 2>&1
+ then msg "found $1"
+ else err "need $1"
+ fi
+}
+
putvar() {
local T
eval T=\$$1
ABSOLUTIFIED="${FILE_PATH}"
}
-CFG_SRC_DIR="$(cd $(dirname $0) && pwd)/"
+msg "looking for install programs"
+need_cmd mkdir
+need_cmd printf
+need_cmd cut
+need_cmd grep
+need_cmd uname
+need_cmd tr
+need_cmd sed
+
+CFG_SRC_DIR="$(cd $(dirname $0) && pwd)"
CFG_SELF="$0"
CFG_ARGS="$@"
step_msg "processing $CFG_SELF args"
fi
+# Check for mingw or cygwin in order to special case $CFG_LIBDIR_RELATIVE.
+# This logic is duplicated from configure in order to get the correct libdir
+# for Windows installs.
+CFG_OSTYPE=$(uname -s)
+
+case $CFG_OSTYPE in
+
+ MINGW32*)
+ CFG_OSTYPE=pc-mingw32
+ ;;
+
+ MINGW64*)
+ # msys2, MSYSTEM=MINGW64
+ CFG_OSTYPE=w64-mingw32
+ ;;
+
+# Thad's Cygwin identifers below
+
+# Vista 32 bit
+ CYGWIN_NT-6.0)
+ CFG_OSTYPE=pc-mingw32
+ ;;
+
+# Vista 64 bit
+ CYGWIN_NT-6.0-WOW64)
+ CFG_OSTYPE=w64-mingw32
+ ;;
+
+# Win 7 32 bit
+ CYGWIN_NT-6.1)
+ CFG_OSTYPE=pc-mingw32
+ ;;
+
+# Win 7 64 bit
+ CYGWIN_NT-6.1-WOW64)
+ CFG_OSTYPE=w64-mingw32
+ ;;
+esac
+
OPTIONS=""
BOOL_OPTIONS=""
VAL_OPTIONS=""
+# On windows we just store the libraries in the bin directory because
+# there's no rpath. This is where the build system itself puts libraries;
+# --libdir is used to configure the installation directory.
+# FIXME: Thise needs to parameterized over target triples. Do it in platform.mk
+CFG_LIBDIR_RELATIVE=lib
+if [ "$CFG_OSTYPE" = "pc-mingw32" ] || [ "$CFG_OSTYPE" = "w64-mingw32" ]
+then
+ CFG_LIBDIR_RELATIVE=bin
+fi
+
flag uninstall "only uninstall from the installation prefix"
opt verify 1 "verify that the installed binaries run correctly"
valopt prefix "/usr/local" "set installation prefix"
# NB This isn't quite the same definition as in `configure`.
# just using 'lib' instead of CFG_LIBDIR_RELATIVE
-valopt libdir "${CFG_PREFIX}/lib" "install libraries"
+valopt libdir "${CFG_PREFIX}/${CFG_LIBDIR_RELATIVE}" "install libraries"
valopt mandir "${CFG_PREFIX}/share/man" "install man pages in PATH"
if [ $HELP -eq 1 ]
need_ok "failed to update manifest"
# The manifest lists all files to install
-done < "${CFG_SRC_DIR}/lib/rustlib/manifest.in"
+done < "${CFG_SRC_DIR}/${CFG_LIBDIR_RELATIVE}/rustlib/manifest.in"
# Sanity check: can we run the installed binaries?
if [ -z "${CFG_DISABLE_VERIFY}" ]
<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
<!ENTITY rustIntSuf "([iu](8|16|32|64)?)?">
]>
-<language name="Rust" version="0.11.0-pre" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15">
+<language name="Rust" version="0.11.0" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15">
<highlighting>
<list name="fn">
<item> fn </item>
// deletion of the data. Because it is marked `Release`, the
// decreasing of the reference count synchronizes with this `Acquire`
// fence. This means that use of the data happens before decreasing
- // the refernce count, which happens before this fence, which
+ // the reference count, which happens before this fence, which
// happens before the deletion of the data.
//
// As explained in the [Boost documentation][1],
//! by libc malloc/free. The `libc_heap` module is defined to be wired up to
//! the system malloc/free.
-#![crate_id = "alloc#0.11.0-pre"]
+#![crate_id = "alloc#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
//! arena but can only hold objects of a single type, and Arena, which is a
//! more complex, slower Arena which can hold objects of any type.
-#![crate_id = "arena#0.11.0-pre"]
+#![crate_id = "arena#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(unsafe_destructor)]
#![allow(missing_doc)]
* Collection types.
*/
-#![crate_id = "collections#0.11.0-pre"]
+#![crate_id = "collections#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase, globs)]
/// Methods for vectors of strings
pub trait StrVector {
/// Concatenate a vector of strings.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// let first = "Restaurant at the End of the".to_string();
+ /// let second = " Universe".to_string();
+ /// let string_vec = vec![first, second];
+ /// assert_eq!(string_vec.concat(), "Restaurant at the End of the Universe".to_string());
+ /// ```
fn concat(&self) -> String;
/// Concatenate a vector of strings, placing a given separator between each.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// let first = "Roast".to_string();
+ /// let second = "Sirloin Steak".to_string();
+ /// let string_vec = vec![first, second];
+ /// assert_eq!(string_vec.connect(", "), "Roast, Sirloin Steak".to_string());
+ /// ```
fn connect(&self, sep: &str) -> String;
}
return String::new();
}
- // `len` calculation may overflow but push_str but will check boundaries
+ // `len` calculation may overflow but push_str will check boundaries
let len = self.iter().map(|s| s.as_slice().len()).sum();
let mut result = String::with_capacity(len);
/// assert_eq!(vec, vec!("hello", "world", "world"));
/// ```
pub fn grow(&mut self, n: uint, value: &T) {
- let new_len = self.len() + n;
- self.reserve(new_len);
+ self.reserve_additional(n);
let mut i: uint = 0u;
while i < n {
/// assert!(vec.capacity() >= 10);
/// ```
pub fn reserve(&mut self, capacity: uint) {
- if capacity >= self.len {
+ if capacity > self.cap {
self.reserve_exact(num::next_power_of_two(capacity))
}
}
// Since libcore defines many fundamental lang items, all tests live in a
// separate crate, libcoretest, to avoid bizarre issues.
-#![crate_id = "core#0.11.0-pre"]
+#![crate_id = "core#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![no_std]
pub mod slice;
pub mod str;
pub mod tuple;
+// FIXME #15320: primitive documentation needs top-level modules, this
+// should be `core::tuple::unit`.
+#[path = "tuple/unit.rs"]
+pub mod unit;
pub mod fmt;
#[doc(hidden)]
fn rotate_left(self, n: uint) -> $T {
// Protect against undefined behaviour for over-long bit shifts
let n = n % $BITS;
- (self << n) | (self >> ($BITS - n))
+ (self << n) | (self >> (($BITS - n) % $BITS))
}
#[inline]
fn rotate_right(self, n: uint) -> $T {
// Protect against undefined behaviour for over-long bit shifts
let n = n % $BITS;
- (self >> n) | (self << ($BITS - n))
+ (self >> n) | (self << (($BITS - n) % $BITS))
}
#[inline]
+++ /dev/null
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Operations on tuples
-//!
-//! To access a single element of a tuple one can use the following
-//! methods:
-//!
-//! * `valN` - returns a value of _N_-th element
-//! * `refN` - returns a reference to _N_-th element
-//! * `mutN` - returns a mutable reference to _N_-th element
-//!
-//! Indexing starts from zero, so `val0` returns first value, `val1`
-//! returns second value, and so on. In general, a tuple with _S_
-//! elements provides aforementioned methods suffixed with numbers
-//! from `0` to `S-1`. Traits which contain these methods are
-//! implemented for tuples with up to 12 elements.
-//!
-//! If every type inside a tuple implements one of the following
-//! traits, then a tuple itself also implements it.
-//!
-//! * `Clone`
-//! * `PartialEq`
-//! * `Eq`
-//! * `PartialOrd`
-//! * `Ord`
-//! * `Default`
-//!
-//! # Examples
-//!
-//! Using methods:
-//!
-//! ```
-//! let pair = ("pi", 3.14f64);
-//! assert_eq!(pair.val0(), "pi");
-//! assert_eq!(pair.val1(), 3.14f64);
-//! ```
-//!
-//! Using traits implemented for tuples:
-//!
-//! ```
-//! use std::default::Default;
-//!
-//! let a = (1i, 2i);
-//! let b = (3i, 4i);
-//! assert!(a != b);
-//!
-//! let c = b.clone();
-//! assert!(b == c);
-//!
-//! let d : (u32, f32) = Default::default();
-//! assert_eq!(d, (0u32, 0.0f32));
-//! ```
-
-#![doc(primitive = "tuple")]
-
-use clone::Clone;
-use cmp::*;
-use default::Default;
-use option::{Option, Some};
-
-// macro for implementing n-ary tuple functions and operations
-macro_rules! tuple_impls {
- ($(
- $Tuple:ident {
- $(($valN:ident, $refN:ident, $mutN:ident) -> $T:ident {
- ($($x:ident),+) => $ret:expr
- })+
- }
- )+) => {
- $(
- #[allow(missing_doc)]
- pub trait $Tuple<$($T),+> {
- $(fn $valN(self) -> $T;)+
- $(fn $refN<'a>(&'a self) -> &'a $T;)+
- $(fn $mutN<'a>(&'a mut self) -> &'a mut $T;)+
- }
-
- impl<$($T),+> $Tuple<$($T),+> for ($($T,)+) {
- $(
- #[inline]
- #[allow(unused_variable)]
- fn $valN(self) -> $T {
- let ($($x,)+) = self; $ret
- }
-
- #[inline]
- #[allow(unused_variable)]
- fn $refN<'a>(&'a self) -> &'a $T {
- let ($(ref $x,)+) = *self; $ret
- }
-
- #[inline]
- #[allow(unused_variable)]
- fn $mutN<'a>(&'a mut self) -> &'a mut $T {
- let ($(ref mut $x,)+) = *self; $ret
- }
- )+
- }
-
- #[unstable]
- impl<$($T:Clone),+> Clone for ($($T,)+) {
- fn clone(&self) -> ($($T,)+) {
- ($(self.$refN().clone(),)+)
- }
- }
-
- impl<$($T:PartialEq),+> PartialEq for ($($T,)+) {
- #[inline]
- fn eq(&self, other: &($($T,)+)) -> bool {
- $(*self.$refN() == *other.$refN())&&+
- }
- #[inline]
- fn ne(&self, other: &($($T,)+)) -> bool {
- $(*self.$refN() != *other.$refN())||+
- }
- }
-
- impl<$($T:Eq),+> Eq for ($($T,)+) {}
-
- impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+) {
- #[inline]
- fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
- lexical_partial_cmp!($(self.$refN(), other.$refN()),+)
- }
- #[inline]
- fn lt(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(lt, $(self.$refN(), other.$refN()),+)
- }
- #[inline]
- fn le(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(le, $(self.$refN(), other.$refN()),+)
- }
- #[inline]
- fn ge(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(ge, $(self.$refN(), other.$refN()),+)
- }
- #[inline]
- fn gt(&self, other: &($($T,)+)) -> bool {
- lexical_ord!(gt, $(self.$refN(), other.$refN()),+)
- }
- }
-
- impl<$($T:Ord),+> Ord for ($($T,)+) {
- #[inline]
- fn cmp(&self, other: &($($T,)+)) -> Ordering {
- lexical_cmp!($(self.$refN(), other.$refN()),+)
- }
- }
-
- impl<$($T:Default),+> Default for ($($T,)+) {
- #[inline]
- fn default() -> ($($T,)+) {
- ($({ let x: $T = Default::default(); x},)+)
- }
- }
- )+
- }
-}
-
-// Constructs an expression that performs a lexical ordering using method $rel.
-// The values are interleaved, so the macro invocation for
-// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
-// a3, b3)` (and similarly for `lexical_cmp`)
-macro_rules! lexical_ord {
- ($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
- if *$a != *$b { lexical_ord!($rel, $a, $b) }
- else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
- };
- ($rel: ident, $a:expr, $b:expr) => { (*$a) . $rel ($b) };
-}
-
-macro_rules! lexical_partial_cmp {
- ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
- match ($a).partial_cmp($b) {
- Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+),
- ordering => ordering
- }
- };
- ($a:expr, $b:expr) => { ($a).partial_cmp($b) };
-}
-
-macro_rules! lexical_cmp {
- ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
- match ($a).cmp($b) {
- Equal => lexical_cmp!($($rest_a, $rest_b),+),
- ordering => ordering
- }
- };
- ($a:expr, $b:expr) => { ($a).cmp($b) };
-}
-
-tuple_impls! {
- Tuple1 {
- (val0, ref0, mut0) -> A { (a) => a }
- }
- Tuple2 {
- (val0, ref0, mut0) -> A { (a, b) => a }
- (val1, ref1, mut1) -> B { (a, b) => b }
- }
- Tuple3 {
- (val0, ref0, mut0) -> A { (a, b, c) => a }
- (val1, ref1, mut1) -> B { (a, b, c) => b }
- (val2, ref2, mut2) -> C { (a, b, c) => c }
- }
- Tuple4 {
- (val0, ref0, mut0) -> A { (a, b, c, d) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d) => d }
- }
- Tuple5 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e) => e }
- }
- Tuple6 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e, f) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e, f) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e, f) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e, f) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e, f) => e }
- (val5, ref5, mut5) -> F { (a, b, c, d, e, f) => f }
- }
- Tuple7 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g) => e }
- (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g) => f }
- (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g) => g }
- }
- Tuple8 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h) => e }
- (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h) => f }
- (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h) => g }
- (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h) => h }
- }
- Tuple9 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i) => e }
- (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i) => f }
- (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i) => g }
- (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i) => h }
- (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i) => i }
- }
- Tuple10 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i, j) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i, j) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i, j) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i, j) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i, j) => e }
- (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i, j) => f }
- (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i, j) => g }
- (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i, j) => h }
- (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i, j) => i }
- (val9, ref9, mut9) -> J { (a, b, c, d, e, f, g, h, i, j) => j }
- }
- Tuple11 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i, j, k) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i, j, k) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i, j, k) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i, j, k) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i, j, k) => e }
- (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i, j, k) => f }
- (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i, j, k) => g }
- (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i, j, k) => h }
- (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i, j, k) => i }
- (val9, ref9, mut9) -> J { (a, b, c, d, e, f, g, h, i, j, k) => j }
- (val10, ref10, mut10) -> K { (a, b, c, d, e, f, g, h, i, j, k) => k }
- }
- Tuple12 {
- (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i, j, k, l) => a }
- (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i, j, k, l) => b }
- (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i, j, k, l) => c }
- (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i, j, k, l) => d }
- (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i, j, k, l) => e }
- (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i, j, k, l) => f }
- (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i, j, k, l) => g }
- (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i, j, k, l) => h }
- (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i, j, k, l) => i }
- (val9, ref9, mut9) -> J { (a, b, c, d, e, f, g, h, i, j, k, l) => j }
- (val10, ref10, mut10) -> K { (a, b, c, d, e, f, g, h, i, j, k, l) => k }
- (val11, ref11, mut11) -> L { (a, b, c, d, e, f, g, h, i, j, k, l) => l }
- }
-}
-
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Operations on tuples
+//!
+//! To access a single element of a tuple one can use the following
+//! methods:
+//!
+//! * `valN` - returns a value of _N_-th element
+//! * `refN` - returns a reference to _N_-th element
+//! * `mutN` - returns a mutable reference to _N_-th element
+//!
+//! Indexing starts from zero, so `val0` returns first value, `val1`
+//! returns second value, and so on. In general, a tuple with _S_
+//! elements provides aforementioned methods suffixed with numbers
+//! from `0` to `S-1`. Traits which contain these methods are
+//! implemented for tuples with up to 12 elements.
+//!
+//! If every type inside a tuple implements one of the following
+//! traits, then a tuple itself also implements it.
+//!
+//! * `Clone`
+//! * `PartialEq`
+//! * `Eq`
+//! * `PartialOrd`
+//! * `Ord`
+//! * `Default`
+//!
+//! # Examples
+//!
+//! Using methods:
+//!
+//! ```
+//! let pair = ("pi", 3.14f64);
+//! assert_eq!(pair.val0(), "pi");
+//! assert_eq!(pair.val1(), 3.14f64);
+//! ```
+//!
+//! Using traits implemented for tuples:
+//!
+//! ```
+//! use std::default::Default;
+//!
+//! let a = (1i, 2i);
+//! let b = (3i, 4i);
+//! assert!(a != b);
+//!
+//! let c = b.clone();
+//! assert!(b == c);
+//!
+//! let d : (u32, f32) = Default::default();
+//! assert_eq!(d, (0u32, 0.0f32));
+//! ```
+
+#![doc(primitive = "tuple")]
+
+pub use unit;
+
+use clone::Clone;
+use cmp::*;
+use default::Default;
+use option::{Option, Some};
+
+// macro for implementing n-ary tuple functions and operations
+macro_rules! tuple_impls {
+ ($(
+ $Tuple:ident {
+ $(($valN:ident, $refN:ident, $mutN:ident) -> $T:ident {
+ ($($x:ident),+) => $ret:expr
+ })+
+ }
+ )+) => {
+ $(
+ #[allow(missing_doc)]
+ pub trait $Tuple<$($T),+> {
+ $(fn $valN(self) -> $T;)+
+ $(fn $refN<'a>(&'a self) -> &'a $T;)+
+ $(fn $mutN<'a>(&'a mut self) -> &'a mut $T;)+
+ }
+
+ impl<$($T),+> $Tuple<$($T),+> for ($($T,)+) {
+ $(
+ #[inline]
+ #[allow(unused_variable)]
+ fn $valN(self) -> $T {
+ let ($($x,)+) = self; $ret
+ }
+
+ #[inline]
+ #[allow(unused_variable)]
+ fn $refN<'a>(&'a self) -> &'a $T {
+ let ($(ref $x,)+) = *self; $ret
+ }
+
+ #[inline]
+ #[allow(unused_variable)]
+ fn $mutN<'a>(&'a mut self) -> &'a mut $T {
+ let ($(ref mut $x,)+) = *self; $ret
+ }
+ )+
+ }
+
+ #[unstable]
+ impl<$($T:Clone),+> Clone for ($($T,)+) {
+ fn clone(&self) -> ($($T,)+) {
+ ($(self.$refN().clone(),)+)
+ }
+ }
+
+ impl<$($T:PartialEq),+> PartialEq for ($($T,)+) {
+ #[inline]
+ fn eq(&self, other: &($($T,)+)) -> bool {
+ $(*self.$refN() == *other.$refN())&&+
+ }
+ #[inline]
+ fn ne(&self, other: &($($T,)+)) -> bool {
+ $(*self.$refN() != *other.$refN())||+
+ }
+ }
+
+ impl<$($T:Eq),+> Eq for ($($T,)+) {}
+
+ impl<$($T:PartialOrd + PartialEq),+> PartialOrd for ($($T,)+) {
+ #[inline]
+ fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
+ lexical_partial_cmp!($(self.$refN(), other.$refN()),+)
+ }
+ #[inline]
+ fn lt(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(lt, $(self.$refN(), other.$refN()),+)
+ }
+ #[inline]
+ fn le(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(le, $(self.$refN(), other.$refN()),+)
+ }
+ #[inline]
+ fn ge(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(ge, $(self.$refN(), other.$refN()),+)
+ }
+ #[inline]
+ fn gt(&self, other: &($($T,)+)) -> bool {
+ lexical_ord!(gt, $(self.$refN(), other.$refN()),+)
+ }
+ }
+
+ impl<$($T:Ord),+> Ord for ($($T,)+) {
+ #[inline]
+ fn cmp(&self, other: &($($T,)+)) -> Ordering {
+ lexical_cmp!($(self.$refN(), other.$refN()),+)
+ }
+ }
+
+ impl<$($T:Default),+> Default for ($($T,)+) {
+ #[inline]
+ fn default() -> ($($T,)+) {
+ ($({ let x: $T = Default::default(); x},)+)
+ }
+ }
+ )+
+ }
+}
+
+// Constructs an expression that performs a lexical ordering using method $rel.
+// The values are interleaved, so the macro invocation for
+// `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, a1, b1, a2, b2,
+// a3, b3)` (and similarly for `lexical_cmp`)
+macro_rules! lexical_ord {
+ ($rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
+ if *$a != *$b { lexical_ord!($rel, $a, $b) }
+ else { lexical_ord!($rel, $($rest_a, $rest_b),+) }
+ };
+ ($rel: ident, $a:expr, $b:expr) => { (*$a) . $rel ($b) };
+}
+
+macro_rules! lexical_partial_cmp {
+ ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
+ match ($a).partial_cmp($b) {
+ Some(Equal) => lexical_partial_cmp!($($rest_a, $rest_b),+),
+ ordering => ordering
+ }
+ };
+ ($a:expr, $b:expr) => { ($a).partial_cmp($b) };
+}
+
+macro_rules! lexical_cmp {
+ ($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
+ match ($a).cmp($b) {
+ Equal => lexical_cmp!($($rest_a, $rest_b),+),
+ ordering => ordering
+ }
+ };
+ ($a:expr, $b:expr) => { ($a).cmp($b) };
+}
+
+tuple_impls! {
+ Tuple1 {
+ (val0, ref0, mut0) -> A { (a) => a }
+ }
+ Tuple2 {
+ (val0, ref0, mut0) -> A { (a, b) => a }
+ (val1, ref1, mut1) -> B { (a, b) => b }
+ }
+ Tuple3 {
+ (val0, ref0, mut0) -> A { (a, b, c) => a }
+ (val1, ref1, mut1) -> B { (a, b, c) => b }
+ (val2, ref2, mut2) -> C { (a, b, c) => c }
+ }
+ Tuple4 {
+ (val0, ref0, mut0) -> A { (a, b, c, d) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d) => d }
+ }
+ Tuple5 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e) => e }
+ }
+ Tuple6 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e, f) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e, f) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e, f) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e, f) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e, f) => e }
+ (val5, ref5, mut5) -> F { (a, b, c, d, e, f) => f }
+ }
+ Tuple7 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g) => e }
+ (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g) => f }
+ (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g) => g }
+ }
+ Tuple8 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h) => e }
+ (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h) => f }
+ (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h) => g }
+ (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h) => h }
+ }
+ Tuple9 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i) => e }
+ (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i) => f }
+ (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i) => g }
+ (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i) => h }
+ (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i) => i }
+ }
+ Tuple10 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i, j) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i, j) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i, j) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i, j) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i, j) => e }
+ (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i, j) => f }
+ (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i, j) => g }
+ (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i, j) => h }
+ (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i, j) => i }
+ (val9, ref9, mut9) -> J { (a, b, c, d, e, f, g, h, i, j) => j }
+ }
+ Tuple11 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i, j, k) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i, j, k) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i, j, k) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i, j, k) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i, j, k) => e }
+ (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i, j, k) => f }
+ (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i, j, k) => g }
+ (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i, j, k) => h }
+ (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i, j, k) => i }
+ (val9, ref9, mut9) -> J { (a, b, c, d, e, f, g, h, i, j, k) => j }
+ (val10, ref10, mut10) -> K { (a, b, c, d, e, f, g, h, i, j, k) => k }
+ }
+ Tuple12 {
+ (val0, ref0, mut0) -> A { (a, b, c, d, e, f, g, h, i, j, k, l) => a }
+ (val1, ref1, mut1) -> B { (a, b, c, d, e, f, g, h, i, j, k, l) => b }
+ (val2, ref2, mut2) -> C { (a, b, c, d, e, f, g, h, i, j, k, l) => c }
+ (val3, ref3, mut3) -> D { (a, b, c, d, e, f, g, h, i, j, k, l) => d }
+ (val4, ref4, mut4) -> E { (a, b, c, d, e, f, g, h, i, j, k, l) => e }
+ (val5, ref5, mut5) -> F { (a, b, c, d, e, f, g, h, i, j, k, l) => f }
+ (val6, ref6, mut6) -> G { (a, b, c, d, e, f, g, h, i, j, k, l) => g }
+ (val7, ref7, mut7) -> H { (a, b, c, d, e, f, g, h, i, j, k, l) => h }
+ (val8, ref8, mut8) -> I { (a, b, c, d, e, f, g, h, i, j, k, l) => i }
+ (val9, ref9, mut9) -> J { (a, b, c, d, e, f, g, h, i, j, k, l) => j }
+ (val10, ref10, mut10) -> K { (a, b, c, d, e, f, g, h, i, j, k, l) => k }
+ (val11, ref11, mut11) -> L { (a, b, c, d, e, f, g, h, i, j, k, l) => l }
+ }
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![doc(primitive = "unit")]
+
+//! The `()` type, sometimes called "unit" or "nil".
+//!
+//! The `()` type has exactly one value `()`, and is used when there
+//! is no other meaningful value that could be returned. `()` is most
+//! commonly seen implicitly: functions without a `-> ...` implicitly
+//! have return type `()`, that is, these are equivalent:
+//!
+//! ```rust
+//! fn long() -> () {}
+//!
+//! fn short() {}
+//! ```
+//!
+//! The semicolon `;` can be used to discard the result of an
+//! expression at the end of a block, making the expression (and thus
+//! the block) evaluate to `()`. For example,
+//!
+//! ```rust
+//! fn returns_i64() -> i64 {
+//! 1i64
+//! }
+//! fn returns_unit() {
+//! 1i64;
+//! }
+//!
+//! let is_i64 = {
+//! returns_i64()
+//! };
+//! let is_unit = {
+//! returns_i64();
+//! };
+//! ```
assert_eq!(_1.rotate_left(124), _1);
assert_eq!(_0.rotate_right(124), _0);
assert_eq!(_1.rotate_right(124), _1);
+
+ // Rotating by 0 should have no effect
+ assert_eq!(A.rotate_left(0), A);
+ assert_eq!(B.rotate_left(0), B);
+ assert_eq!(C.rotate_left(0), C);
+ // Rotating by a multiple of word size should also have no effect
+ assert_eq!(A.rotate_left(64), A);
+ assert_eq!(B.rotate_left(64), B);
+ assert_eq!(C.rotate_left(64), C);
}
#[test]
assert_eq!(_1.rotate_left(124), _1);
assert_eq!(_0.rotate_right(124), _0);
assert_eq!(_1.rotate_right(124), _1);
+
+ // Rotating by 0 should have no effect
+ assert_eq!(A.rotate_left(0), A);
+ assert_eq!(B.rotate_left(0), B);
+ assert_eq!(C.rotate_left(0), C);
+ // Rotating by a multiple of word size should also have no effect
+ assert_eq!(A.rotate_left(64), A);
+ assert_eq!(B.rotate_left(64), B);
+ assert_eq!(C.rotate_left(64), C);
}
#[test]
//! Additionally, it is not guaranteed that functionality such as reflection
//! will persist into the future.
-#![crate_id = "debug#0.11.0-pre"]
+#![crate_id = "debug#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![experimental]
#![feature(managed_boxes, macro_rules)]
#![allow(experimental)]
*/
-#![crate_id = "flate#0.11.0-pre"]
+#![crate_id = "flate#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(phase)]
#[cfg(test)] #[phase(plugin, link)] extern crate log;
//! Parsing does not happen at runtime: structures of `std::fmt::rt` are
//! generated instead.
-#![crate_id = "fmt_macros#0.11.0-pre"]
+#![crate_id = "fmt_macros#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
*/
-#![crate_id = "fourcc#0.11.0-pre"]
+#![crate_id = "fourcc#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(plugin_registrar, managed_boxes)]
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
-use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;
use rustc::plugin::Registry;
fn parse_tts(cx: &ExtCtxt,
tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
- let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
- cx.cfg(),
- tts.iter()
- .map(|x| (*x).clone())
- .collect());
+ let p = &mut cx.new_parser_from_tts(tts);
let ex = p.parse_expr();
let id = if p.token == token::EOF {
None
//! }
//! ~~~
-#![crate_id = "getopts#0.11.0-pre"]
+#![crate_id = "getopts#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(globs, phase)]
#![deny(missing_doc)]
* `glob`/`fnmatch` functions.
*/
-#![crate_id = "glob#0.11.0-pre"]
+#![crate_id = "glob#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
use std::cell::Cell;
*/
-#![crate_id = "graphviz#0.11.0-pre"]
+#![crate_id = "graphviz#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![experimental]
//! pool.shutdown();
//! ```
-#![crate_id = "green#0.11.0-pre"]
+#![crate_id = "green#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
// NB this does *not* include globs, please keep it that way.
}
pub struct StackPool {
- // Ideally this would be some datastructure that preserved ordering on
+ // Ideally this would be some data structure that preserved ordering on
// Stack.min_size.
stacks: Vec<Stack>,
}
*/
-#![crate_id = "hexfloat#0.11.0-pre"]
+#![crate_id = "hexfloat#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(plugin_registrar, managed_boxes)]
extern crate syntax;
use syntax::ext::base;
use syntax::ext::base::{ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
-use syntax::parse;
use syntax::parse::token;
use rustc::plugin::Registry;
fn parse_tts(cx: &ExtCtxt,
tts: &[ast::TokenTree]) -> (Gc<ast::Expr>, Option<Ident>) {
- let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
- cx.cfg(),
- tts.iter()
- .map(|x| (*x).clone())
- .collect());
+ let p = &mut cx.new_parser_from_tts(tts);
let ex = p.parse_expr();
let id = if p.token == token::EOF {
None
// except according to those terms.
#![feature(globs)]
-#![crate_id = "libc#0.11.0-pre"]
+#![crate_id = "libc#0.11.0"]
#![experimental]
#![no_std] // we don't need std, and we can't have std, since it doesn't exist
// yet. std depends on us.
#![crate_type = "rlib"]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_playground_url = "http://play.rust-lang.org/")]
/*!
* Bindings for the C standard library and other platform libraries
*/
-#![crate_id = "log#0.11.0-pre"]
+#![crate_id = "log#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules)]
unsafe { INIT.doit(init); }
// It's possible for many threads are in this function, only one of them
- // will peform the global initialization, but all of them will need to check
+ // will perform the global initialization, but all of them will need to check
// again to whether they should really be here or not. Hence, despite this
// check being expanded manually in the logging macro, this function checks
// the log level again.
}
// Also as with read(), we use MSG_DONTWAIT to guard ourselves
- // against unforseen circumstances.
+ // against unforeseen circumstances.
let _guard = lock();
let ptr = buf.slice_from(written).as_ptr();
let len = buf.len() - written;
if ret != 0 { return Ok(bytes_read as uint) }
// If our errno doesn't say that the I/O is pending, then we hit some
- // legitimate error and reeturn immediately.
+ // legitimate error and return immediately.
if os::errno() != libc::ERROR_IO_PENDING as uint {
return Err(super::last_error())
}
}
}
-
-// Note: although the last parameter isn't used there is no way now to
-// convert it to unit type, because LLVM dies in SjLj preparation
-// step (unfortunately iOS uses SjLJ exceptions)
-//
-// It's definitely a temporary workaround just to get it working.
-// So far it looks like an LLVM issue and it was reported:
-// http://llvm.org/bugs/show_bug.cgi?id=19855
-// Actually this issue is pretty common while compiling for armv7 iOS
-// and in most cases it is simply solved by using --opt-level=2 (or -O)
-//
-// For this specific case unfortunately turning optimizations wasn't
-// enough.
-fn helper(input: libc::c_int, messages: Receiver<Req>, _: int) {
+fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
let mut set: c::fd_set = unsafe { mem::zeroed() };
let mut fd = FileDesc::new(input, true);
pub fn new() -> IoResult<Timer> {
// See notes above regarding using int return value
// instead of ()
- unsafe { HELPER.boot(|| {0}, helper); }
+ unsafe { HELPER.boot(|| {}, helper); }
static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
let id = unsafe { ID.fetch_add(1, atomics::Relaxed) };
//! }
//! ```
-#![crate_id = "native#0.11.0-pre"]
+#![crate_id = "native#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![deny(unused_result, unused_must_use)]
#![allow(non_camel_case_types, deprecated)]
#![feature(macro_rules)]
-#![crate_id = "num#0.11.0-pre"]
+#![crate_id = "num#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![allow(deprecated)] // from_str_radix
Num for Ratio<T> {}
/* String conversions */
-impl<T: fmt::Show> fmt::Show for Ratio<T> {
- /// Renders as `numer/denom`.
+impl<T: fmt::Show + Eq + One> fmt::Show for Ratio<T> {
+ /// Renders as `numer/denom`. If denom=1, renders as numer.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}/{}", self.numer, self.denom)
+ if self.denom == One::one() {
+ write!(f, "{}", self.numer)
+ } else {
+ write!(f, "{}/{}", self.numer, self.denom)
+ }
}
}
+
impl<T: ToStrRadix> ToStrRadix for Ratio<T> {
/// Renders as `numer/denom` where the numbers are in base `radix`.
fn to_str_radix(&self, radix: uint) -> String {
impl<T: FromStr + Clone + Integer + PartialOrd>
FromStr for Ratio<T> {
- /// Parses `numer/denom`.
+ /// Parses `numer/denom` or just `numer`
fn from_str(s: &str) -> Option<Ratio<T>> {
- let split: Vec<&str> = s.splitn('/', 1).collect();
- if split.len() < 2 {
- return None
+ let mut split = s.splitn('/', 1);
+
+ let num = split.next().and_then(|n| FromStr::from_str(n));
+ let den = split.next().or(Some("1")).and_then(|d| FromStr::from_str(d));
+
+ match (num, den) {
+ (Some(n), Some(d)) => Some(Ratio::new(n, d)),
+ _ => None
}
- let a_option: Option<T> = FromStr::from_str(*split.get(0));
- a_option.and_then(|a| {
- let b_option: Option<T> = FromStr::from_str(*split.get(1));
- b_option.and_then(|b| {
- Some(Ratio::new(a.clone(), b.clone()))
- })
- })
}
}
+
impl<T: FromStrRadix + Clone + Integer + PartialOrd>
FromStrRadix for Ratio<T> {
/// Parses `numer/denom` where the numbers are in base `radix`.
assert!(!_neg1_2.is_integer());
}
+ #[test]
+ fn test_show() {
+ assert_eq!(format!("{}", _2), "2".to_string());
+ assert_eq!(format!("{}", _1_2), "1/2".to_string());
+ assert_eq!(format!("{}", _0), "0".to_string());
+ assert_eq!(format!("{}", Ratio::from_integer(-2i)), "-2".to_string());
+ }
mod arith {
use super::{_0, _1, _2, _1_2, _3_2, _neg1_2, to_big};
assert_eq!(FromStr::from_str(s.as_slice()), Some(r));
assert_eq!(r.to_str(), s);
}
- test(_1, "1/1".to_string());
- test(_0, "0/1".to_string());
+ test(_1, "1".to_string());
+ test(_0, "0".to_string());
test(_1_2, "1/2".to_string());
test(_3_2, "3/2".to_string());
- test(_2, "2/1".to_string());
+ test(_2, "2".to_string());
test(_neg1_2, "-1/2".to_string());
}
#[test]
//! is not recommended to use this library directly, but rather the official
//! interface through `std::rand`.
-#![crate_id = "rand#0.11.0-pre"]
+#![crate_id = "rand#0.11.0"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase, globs)]
//! characters in the search text and `m` is the number of instructions in a
//! compiled expression.
-#![crate_id = "regex#0.11.0-pre"]
+#![crate_id = "regex#0.11.0"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![experimental]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
//! This crate provides the `regex!` macro. Its use is documented in the
//! `regex` crate.
-#![crate_id = "regex_macros#0.11.0-pre"]
+#![crate_id = "regex_macros#0.11.0"]
#![crate_type = "dylib"]
#![experimental]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(plugin_registrar, managed_boxes, quote)]
use syntax::codemap;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{ExtCtxt, MacResult, MacExpr, DummyResult};
-use syntax::parse;
use syntax::parse::token;
use syntax::print::pprust;
/// Looks for a single string literal and returns it.
/// Otherwise, logs an error with cx.span_err and returns None.
fn parse(cx: &mut ExtCtxt, tts: &[ast::TokenTree]) -> Option<String> {
- let mut parser = parse::new_parser_from_tts(cx.parse_sess(), cx.cfg(),
- Vec::from_slice(tts));
+ let mut parser = cx.new_parser_from_tts(tts);
let entry = cx.expand_expr(parser.parse_expr());
let regex = match entry.node {
ast::ExprLit(lit) => {
//! necessary. It is an error to include this library when also linking with
//! the system libc library.
-#![crate_id = "rlibc#0.11.0-pre"]
+#![crate_id = "rlibc#0.11.0"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(intrinsics)]
#![no_std]
#![experimental]
-// This library is definining the builtin functions, so it would be a shame for
+// This library defines the builtin functions, so it would be a shame for
// LLVM to optimize these function calls to themselves!
#![no_builtins]
// get all hardware potential via VFP3 (hardware floating point)
// and NEON (SIMD) instructions supported by LLVM.
// Note that without those flags various linking errors might
- // arise as some of intrinsicts are converted into function calls
+ // arise as some of intrinsics are converted into function calls
// and nobody provides implementations those functions
fn target_feature<'a>(sess: &'a Session) -> &'a str {
match sess.targ_cfg.os {
use std::mem;
use std::gc::{Gc, GC};
-pub static VERSION: &'static str = "0.11.0-pre";
+pub static VERSION: &'static str = "0.11.0";
pub fn maybe_inject_crates_ref(sess: &Session, krate: ast::Crate)
-> ast::Crate {
*/
-#![crate_id = "rustc#0.11.0-pre"]
+#![crate_id = "rustc#0.11.0"]
#![experimental]
#![comment = "The Rust compiler"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![allow(deprecated)]
#![feature(macro_rules, globs, struct_variant, managed_boxes, quote)]
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
// Lint for constants that look like binding identifiers (#7526)
match (&p.node, cx.tcx.def_map.borrow().find(&p.id)) {
- (&ast::PatIdent(_, ref path, _), Some(&def::DefStatic(_, false))) => {
- // last identifier alone is right choice for this lint.
- let ident = path.segments.last().unwrap().identifier;
- let s = token::get_ident(ident);
+ (&ast::PatIdent(_, ref path1, _), Some(&def::DefStatic(_, false))) => {
+ let s = token::get_ident(path1.node);
if s.get().chars().any(|c| c.is_lowercase()) {
- cx.span_lint(NON_UPPERCASE_PATTERN_STATICS, path.span,
+ cx.span_lint(NON_UPPERCASE_PATTERN_STATICS, path1.span,
format!("static constant in pattern `{}` should have an uppercase \
name such as `{}`",
s.get(), s.get().chars().map(|c| c.to_uppercase())
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
match &p.node {
- &ast::PatIdent(_, ref path, _) => {
+ &ast::PatIdent(_, ref path1, _) => {
match cx.tcx.def_map.borrow().find(&p.id) {
Some(&def::DefLocal(_, _)) | Some(&def::DefBinding(_, _)) |
Some(&def::DefArg(_, _)) => {
- // last identifier alone is right choice for this lint.
- let ident = path.segments.last().unwrap().identifier;
- let s = token::get_ident(ident);
+ let s = token::get_ident(path1.node);
if s.get().len() > 0 && s.get().char_at(0).is_uppercase() {
- cx.span_lint(UPPERCASE_VARIABLES, path.span,
+ cx.span_lint(UPPERCASE_VARIABLES, path1.span,
"variable names should start with \
a lowercase character");
}
_ => {}
}
- /// Expressions that syntatically contain an "exterior" struct
+ /// Expressions that syntactically contain an "exterior" struct
/// literal i.e. not surrounded by any parens or other
/// delimiters, e.g. `X { y: 1 }`, `X { y: 1 }.method()`, `foo
/// == X { y: 1 }` and `X { y: 1 } == foo` all do, but `(X {
// avoid false warnings in match arms with multiple patterns
let mut mutables = HashMap::new();
for &p in pats.iter() {
- pat_util::pat_bindings(&cx.tcx.def_map, &*p, |mode, id, _, path| {
+ pat_util::pat_bindings(&cx.tcx.def_map, &*p, |mode, id, _, path1| {
+ let ident = path1.node;
match mode {
ast::BindByValue(ast::MutMutable) => {
- if path.segments.len() != 1 {
- cx.sess().span_bug(p.span,
- "mutable binding that doesn't consist \
- of exactly one segment");
- }
- let ident = path.segments.get(0).identifier;
if !token::get_ident(ident).get().starts_with("_") {
mutables.insert_or_update_with(ident.name as uint,
vec!(id), |_, old| { old.push(id); });
for arg in decl.inputs.iter() {
ebml_w.start_tag(tag_method_argument_name);
match arg.pat.node {
- ast::PatIdent(_, ref name, _) => {
- let name = name.segments.last().unwrap().identifier;
- let name = token::get_ident(name);
+ ast::PatIdent(_, ref path1, _) => {
+ let name = token::get_ident(path1.node);
ebml_w.writer.write(name.get().as_bytes());
}
_ => {}
match ty.node {
ast::TyPath(ref path, ref bounds, _) if path.segments
.len() == 1 => {
+ let ident = path.segments.last().unwrap().identifier;
assert!(bounds.is_none());
- encode_impl_type_basename(ebml_w, ast_util::path_to_ident(path));
+ encode_impl_type_basename(ebml_w, ident);
}
_ => {}
}
move_pat: &ast::Pat,
cmt: mc::cmt) {
let pat_span_path_opt = match move_pat.node {
- ast::PatIdent(_, ref path, _) => {
- Some(MoveSpanAndPath::with_span_and_path(move_pat.span,
- (*path).clone()))
+ ast::PatIdent(_, ref path1, _) => {
+ Some(MoveSpanAndPath{span: move_pat.span,
+ ident: path1.node})
},
_ => None,
};
#[deriving(Clone)]
pub struct MoveSpanAndPath {
- span: codemap::Span,
- path: ast::Path
-}
-
-impl MoveSpanAndPath {
- pub fn with_span_and_path(span: codemap::Span,
- path: ast::Path)
- -> MoveSpanAndPath {
- MoveSpanAndPath {
- span: span,
- path: path,
- }
- }
+ pub span: codemap::Span,
+ pub ident: ast::Ident
}
pub struct GroupedMoveErrors {
let mut is_first_note = true;
for move_to in error.move_to_places.iter() {
note_move_destination(bccx, move_to.span,
- &move_to.path, is_first_note);
+ &move_to.ident, is_first_note);
is_first_note = false;
}
}
fn note_move_destination(bccx: &BorrowckCtxt,
move_to_span: codemap::Span,
- pat_ident_path: &ast::Path,
+ pat_ident: &ast::Ident,
is_first_note: bool) {
- let pat_name = pprust::path_to_str(pat_ident_path);
+ let pat_name = pprust::ident_to_str(pat_ident);
if is_first_note {
bccx.span_note(
move_to_span,
}
}
-struct MatchCheckCtxt<'a> {
- tcx: &'a ty::ctxt
+pub struct MatchCheckCtxt<'a> {
+ pub tcx: &'a ty::ctxt
}
#[deriving(Clone, PartialEq)]
-enum Constructor {
+pub enum Constructor {
/// The constructor of all patterns that don't vary by constructor,
/// e.g. struct patterns and fixed-length arrays.
Single,
Slice(uint)
}
-#[deriving(Clone)]
+#[deriving(Clone, PartialEq)]
enum Usefulness {
- Useful(Vec<Gc<Pat>>),
+ Useful,
+ UsefulWithWitness(Vec<Gc<Pat>>),
NotUseful
}
LeaveOutWitness
}
-impl Usefulness {
- fn useful(self) -> Option<Vec<Gc<Pat>>> {
- match self {
- Useful(pats) => Some(pats),
- _ => None
- }
- }
-}
-
impl<'a> Visitor<()> for MatchCheckCtxt<'a> {
fn visit_expr(&mut self, ex: &Expr, _: ()) {
check_expr(self, ex);
let v = vec!(*pat);
match is_useful(cx, &seen, v.as_slice(), LeaveOutWitness) {
NotUseful => cx.tcx.sess.span_err(pat.span, "unreachable pattern"),
- _ => ()
+ Useful => (),
+ UsefulWithWitness(_) => unreachable!()
}
if arm.guard.is_none() {
let Matrix(mut rows) = seen;
fn check_exhaustive(cx: &MatchCheckCtxt, sp: Span, m: &Matrix) {
match is_useful(cx, m, [wild()], ConstructWitness) {
- Useful(pats) => {
+ UsefulWithWitness(pats) => {
let witness = match pats.as_slice() {
[witness] => witness,
[] => wild(),
}
NotUseful => {
// This is good, wildcard pattern isn't reachable
- }
+ },
+ _ => unreachable!()
}
}
// Note: is_useful doesn't work on empty types, as the paper notes.
// So it assumes that v is non-empty.
-fn is_useful(cx: &MatchCheckCtxt, m @ &Matrix(ref rows): &Matrix,
+fn is_useful(cx: &MatchCheckCtxt, matrix @ &Matrix(ref rows): &Matrix,
v: &[Gc<Pat>], witness: WitnessPreference) -> Usefulness {
- debug!("{:}", m);
+ debug!("{:}", matrix);
if rows.len() == 0u {
- return Useful(vec!());
+ return match witness {
+ ConstructWitness => UsefulWithWitness(vec!()),
+ LeaveOutWitness => Useful
+ };
}
if rows.get(0).len() == 0u {
return NotUseful;
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
if constructors.is_empty() {
- match missing_constructor(cx, m, left_ty, max_slice_length) {
+ match missing_constructor(cx, matrix, left_ty, max_slice_length) {
None => {
- all_constructors(cx, left_ty, max_slice_length).move_iter().filter_map(|c| {
- is_useful_specialized(cx, m, v, c.clone(),
- left_ty, witness).useful().map(|pats| {
- Useful(match witness {
- ConstructWitness => {
- let arity = constructor_arity(cx, &c, left_ty);
- let subpats = {
- let pat_slice = pats.as_slice();
- Vec::from_fn(arity, |i| {
- pat_slice.get(i).map(|p| p.clone())
- .unwrap_or_else(|| wild())
- })
- };
- let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
- result.extend(pats.move_iter().skip(arity));
- result
- }
- LeaveOutWitness => vec!()
- })
- })
- }).nth(0).unwrap_or(NotUseful)
+ all_constructors(cx, left_ty, max_slice_length).move_iter().map(|c| {
+ match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
+ UsefulWithWitness(pats) => UsefulWithWitness({
+ let arity = constructor_arity(cx, &c, left_ty);
+ let subpats = {
+ let pat_slice = pats.as_slice();
+ Vec::from_fn(arity, |i| {
+ pat_slice.get(i).map(|p| p.clone())
+ .unwrap_or_else(|| wild())
+ })
+ };
+ let mut result = vec!(construct_witness(cx, &c, subpats, left_ty));
+ result.extend(pats.move_iter().skip(arity));
+ result
+ }),
+ result => result
+ }
+ }).find(|result| result != &NotUseful).unwrap_or(NotUseful)
},
Some(constructor) => {
let matrix = Matrix(rows.iter().filter_map(|r|
default(cx, r.as_slice())).collect());
match is_useful(cx, &matrix, v.tail(), witness) {
- Useful(pats) => Useful(match witness {
- ConstructWitness => {
- let arity = constructor_arity(cx, &constructor, left_ty);
- let wild_pats = Vec::from_elem(arity, wild());
- let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
- (vec!(enum_pat)).append(pats.as_slice())
- }
- LeaveOutWitness => vec!()
- }),
+ UsefulWithWitness(pats) => {
+ let arity = constructor_arity(cx, &constructor, left_ty);
+ let wild_pats = Vec::from_elem(arity, wild());
+ let enum_pat = construct_witness(cx, &constructor, wild_pats, left_ty);
+ UsefulWithWitness(vec!(enum_pat).append(pats.as_slice()))
+ },
result => result
}
}
}
} else {
- constructors.move_iter().filter_map(|c| {
- is_useful_specialized(cx, m, v, c.clone(), left_ty, witness)
- .useful().map(|pats| Useful(pats))
- }).nth(0).unwrap_or(NotUseful)
+ constructors.move_iter().map(|c|
+ is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness)
+ ).find(|result| result != &NotUseful).unwrap_or(NotUseful)
}
}
ctor: Constructor, lty: ty::t, witness: WitnessPreference) -> Usefulness {
let arity = constructor_arity(cx, &ctor, lty);
let matrix = Matrix(m.iter().filter_map(|r| {
- specialize(cx, r.as_slice(), &ctor, arity)
+ specialize(cx, r.as_slice(), &ctor, 0u, arity)
}).collect());
- match specialize(cx, v, &ctor, arity) {
+ match specialize(cx, v, &ctor, 0u, arity) {
Some(v) => is_useful(cx, &matrix, v.as_slice(), witness),
None => NotUseful
}
let const_expr = lookup_const_by_id(cx.tcx, did).unwrap();
vec!(ConstantValue(eval_const_expr(cx.tcx, &*const_expr)))
},
+ Some(&DefStruct(_)) => vec!(Single),
Some(&DefVariant(_, id, _)) => vec!(Variant(id)),
_ => vec!()
},
}
}
-fn is_wild(cx: &MatchCheckCtxt, p: Gc<Pat>) -> bool {
- let pat = raw_pat(p);
- match pat.node {
- PatWild | PatWildMulti => true,
- PatIdent(_, _, _) =>
- match cx.tcx.def_map.borrow().find(&pat.id) {
- Some(&DefVariant(_, _, _)) | Some(&DefStatic(..)) => false,
- _ => true
- },
- PatVec(ref before, Some(_), ref after) =>
- before.is_empty() && after.is_empty(),
- _ => false
- }
-}
-
/// This computes the arity of a constructor. The arity of a constructor
/// is how many subpattern patterns of that constructor should be expanded to.
///
/// For instance, a tuple pattern (_, 42u, Some([])) has the arity of 3.
/// A struct pattern's arity is the number of fields it contains, etc.
-fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
+pub fn constructor_arity(cx: &MatchCheckCtxt, ctor: &Constructor, ty: ty::t) -> uint {
match ty::get(ty).sty {
ty::ty_tup(ref fs) => fs.len(),
ty::ty_box(_) | ty::ty_uniq(_) => 1u,
/// different patterns.
/// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing
/// fields filled with wild patterns.
-fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
- constructor: &Constructor, arity: uint) -> Option<Vec<Gc<Pat>>> {
+pub fn specialize(cx: &MatchCheckCtxt, r: &[Gc<Pat>],
+ constructor: &Constructor, col: uint, arity: uint) -> Option<Vec<Gc<Pat>>> {
let &Pat {
id: pat_id, node: ref node, span: pat_span
- } = &(*raw_pat(r[0]));
+ } = &(*raw_pat(r[col]));
let head: Option<Vec<Gc<Pat>>> = match node {
&PatWild =>
Some(Vec::from_elem(arity, wild())),
None
}
};
- head.map(|head| head.append(r.tail()))
+ head.map(|head| head.append(r.slice_to(col)).append(r.slice_from(col + 1)))
}
fn default(cx: &MatchCheckCtxt, r: &[Gc<Pat>]) -> Option<Vec<Gc<Pat>>> {
- if is_wild(cx, r[0]) {
+ if pat_is_binding_or_wild(&cx.tcx.def_map, &*raw_pat(r[0])) {
Some(Vec::from_slice(r.tail()))
} else {
None
fn is_refutable(cx: &MatchCheckCtxt, pat: Gc<Pat>) -> Option<Gc<Pat>> {
let pats = Matrix(vec!(vec!(pat)));
- is_useful(cx, &pats, [wild()], ConstructWitness)
- .useful()
- .map(|pats| {
+ match is_useful(cx, &pats, [wild()], ConstructWitness) {
+ UsefulWithWitness(pats) => {
assert_eq!(pats.len(), 1);
- pats.get(0).clone()
- })
+ Some(pats.get(0).clone())
+ },
+ NotUseful => None,
+ Useful => unreachable!()
+ }
}
// Legality of move bindings checking
ast::PatStruct(_, ref fields, _) => {
self.handle_field_pattern_match(pat, fields.as_slice());
}
+ ast::PatIdent(_, _, _) => {
+ // it might be the only use of a static:
+ self.lookup_and_handle_definition(&pat.id)
+ }
_ => ()
}
use middle::freevars;
use middle::pat_util;
use middle::ty;
-use middle::typeck::MethodCall;
+use middle::typeck::{MethodCall, MethodObject, MethodOrigin, MethodParam};
+use middle::typeck::{MethodStatic};
use middle::typeck;
-use syntax::ast;
-use syntax::codemap::{Span};
use util::ppaux::Repr;
use std::gc::Gc;
+use syntax::ast;
+use syntax::codemap::Span;
///////////////////////////////////////////////////////////////////////////
// The Delegate trait
WriteAndRead, // x += y
}
+enum OverloadedCallType {
+ FnOverloadedCall,
+ FnMutOverloadedCall,
+ FnOnceOverloadedCall,
+}
+
+impl OverloadedCallType {
+ fn from_trait_id(tcx: &ty::ctxt, trait_id: ast::DefId)
+ -> OverloadedCallType {
+ for &(maybe_function_trait, overloaded_call_type) in [
+ (tcx.lang_items.fn_once_trait(), FnOnceOverloadedCall),
+ (tcx.lang_items.fn_mut_trait(), FnMutOverloadedCall),
+ (tcx.lang_items.fn_trait(), FnOverloadedCall)
+ ].iter() {
+ match maybe_function_trait {
+ Some(function_trait) if function_trait == trait_id => {
+ return overloaded_call_type
+ }
+ _ => continue,
+ }
+ }
+
+ tcx.sess.bug("overloaded call didn't map to known function trait")
+ }
+
+ fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
+ -> OverloadedCallType {
+ let method_descriptor =
+ match tcx.methods.borrow_mut().find(&method_id) {
+ None => {
+ tcx.sess.bug("overloaded call method wasn't in method \
+ map")
+ }
+ Some(ref method_descriptor) => (*method_descriptor).clone(),
+ };
+ let impl_id = match method_descriptor.container {
+ ty::TraitContainer(_) => {
+ tcx.sess.bug("statically resolved overloaded call method \
+ belonged to a trait?!")
+ }
+ ty::ImplContainer(impl_id) => impl_id,
+ };
+ let trait_ref = match ty::impl_trait_ref(tcx, impl_id) {
+ None => {
+ tcx.sess.bug("statically resolved overloaded call impl \
+ didn't implement a trait?!")
+ }
+ Some(ref trait_ref) => (*trait_ref).clone(),
+ };
+ OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
+ }
+
+ fn from_method_origin(tcx: &ty::ctxt, origin: &MethodOrigin)
+ -> OverloadedCallType {
+ match *origin {
+ MethodStatic(def_id) => {
+ OverloadedCallType::from_method_id(tcx, def_id)
+ }
+ MethodParam(ref method_param) => {
+ OverloadedCallType::from_trait_id(tcx, method_param.trait_id)
+ }
+ MethodObject(ref method_object) => {
+ OverloadedCallType::from_trait_id(tcx, method_object.trait_id)
+ }
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// The ExprUseVisitor type
//
}
}
_ => {
- match self.tcx()
- .method_map
- .borrow()
- .find(&MethodCall::expr(call.id)) {
- Some(_) => {
- // FIXME(#14774, pcwalton): Implement this.
+ let overloaded_call_type =
+ match self.tcx()
+ .method_map
+ .borrow()
+ .find(&MethodCall::expr(call.id)) {
+ Some(ref method_callee) => {
+ OverloadedCallType::from_method_origin(
+ self.tcx(),
+ &method_callee.origin)
}
None => {
self.tcx().sess.span_bug(
callee.span,
format!("unexpected callee type {}",
- callee_ty.repr(self.tcx())).as_slice());
+ callee_ty.repr(self.tcx())).as_slice())
+ }
+ };
+ match overloaded_call_type {
+ FnMutOverloadedCall => {
+ self.borrow_expr(callee,
+ ty::ReScope(call.id),
+ ty::MutBorrow,
+ ClosureInvocation);
+ }
+ FnOverloadedCall => {
+ self.borrow_expr(callee,
+ ty::ReScope(call.id),
+ ty::ImmBorrow,
+ ClosureInvocation);
}
+ FnOnceOverloadedCall => self.consume_expr(callee),
}
}
}
use middle::freevars;
use middle::subst;
use middle::ty;
+use middle::typeck::{MethodCall, NoAdjustment};
use middle::typeck;
use util::ppaux::{Repr, ty_to_str};
use util::ppaux::UserString;
use syntax::ast::*;
use syntax::attr;
use syntax::codemap::Span;
-use syntax::print::pprust::{expr_to_str,path_to_str};
+use syntax::print::pprust::{expr_to_str, ident_to_str};
use syntax::{visit};
use syntax::visit::Visitor;
ExprCast(ref source, _) => {
let source_ty = ty::expr_ty(cx.tcx, &**source);
let target_ty = ty::expr_ty(cx.tcx, e);
- check_trait_cast(cx, source_ty, target_ty, source.span);
+ let method_call = MethodCall {
+ expr_id: e.id,
+ adjustment: NoAdjustment,
+ };
+ check_trait_cast(cx,
+ source_ty,
+ target_ty,
+ source.span,
+ method_call);
}
ExprRepeat(ref element, ref count_expr) => {
let count = ty::eval_repeat_count(cx.tcx, &**count_expr);
ty::AutoObject(..) => {
let source_ty = ty::expr_ty(cx.tcx, e);
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
- check_trait_cast(cx, source_ty, target_ty, e.span);
+ let method_call = MethodCall {
+ expr_id: e.id,
+ adjustment: typeck::AutoObject,
+ };
+ check_trait_cast(cx,
+ source_ty,
+ target_ty,
+ e.span,
+ method_call);
}
ty::AutoAddEnv(..) |
ty::AutoDerefRef(..) => {}
}
}
-fn check_trait_cast(cx: &mut Context, source_ty: ty::t, target_ty: ty::t, span: Span) {
+fn check_type_parameter_bounds_in_vtable_result(
+ cx: &mut Context,
+ span: Span,
+ vtable_res: &typeck::vtable_res) {
+ for origins in vtable_res.iter() {
+ for origin in origins.iter() {
+ let (type_param_defs, substs) = match *origin {
+ typeck::vtable_static(def_id, ref tys, _) => {
+ let type_param_defs =
+ ty::lookup_item_type(cx.tcx, def_id).generics
+ .types
+ .clone();
+ (type_param_defs, (*tys).clone())
+ }
+ _ => {
+ // Nothing to do here.
+ continue
+ }
+ };
+ for type_param_def in type_param_defs.iter() {
+ let typ = substs.types.get(type_param_def.space,
+ type_param_def.index);
+ check_typaram_bounds(cx, span, *typ, type_param_def)
+ }
+ }
+ }
+}
+
+fn check_trait_cast(cx: &mut Context,
+ source_ty: ty::t,
+ target_ty: ty::t,
+ span: Span,
+ method_call: MethodCall) {
check_cast_for_escaping_regions(cx, source_ty, target_ty, span);
match ty::get(target_ty).sty {
- ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => match ty::get(ty).sty {
- ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
- check_trait_cast_bounds(cx, span, source_ty, bounds);
+ ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ ty, .. }) => {
+ match ty::get(ty).sty {
+ ty::ty_trait(box ty::TyTrait { bounds, .. }) => {
+ match cx.tcx.vtable_map.borrow().find(&method_call) {
+ None => {
+ cx.tcx.sess.span_bug(span,
+ "trait cast not in vtable \
+ map?!")
+ }
+ Some(vtable_res) => {
+ check_type_parameter_bounds_in_vtable_result(
+ cx,
+ span,
+ vtable_res)
+ }
+ };
+ check_trait_cast_bounds(cx, span, source_ty, bounds);
+ }
+ _ => {}
}
- _ => {}
- },
+ }
_ => {}
}
}
fn check_pat(cx: &mut Context, pat: &Pat) {
let var_name = match pat.node {
PatWild => Some("_".to_string()),
- PatIdent(_, ref path, _) => Some(path_to_str(path).to_string()),
+ PatIdent(_, ref path1, _) => Some(ident_to_str(&path1.node).to_string()),
_ => None
};
OrdTraitLangItem, "ord", ord_trait;
StrEqFnLangItem, "str_eq", str_eq_fn;
- UniqStrEqFnLangItem, "uniq_str_eq", uniq_str_eq_fn;
// A number of failure-related lang items. The `fail_` item corresponds to
// divide-by-zero and various failure cases with `match`. The
for arg in decl.inputs.iter() {
pat_util::pat_bindings(&ir.tcx.def_map,
&*arg.pat,
- |_bm, arg_id, _x, path| {
+ |_bm, arg_id, _x, path1| {
debug!("adding argument {}", arg_id);
- let ident = ast_util::path_to_ident(path);
+ let ident = path1.node;
fn_maps.add_variable(Arg(arg_id, ident));
})
};
}
fn visit_local(ir: &mut IrMaps, local: &Local) {
- pat_util::pat_bindings(&ir.tcx.def_map, &*local.pat, |_, p_id, sp, path| {
+ pat_util::pat_bindings(&ir.tcx.def_map, &*local.pat, |_, p_id, sp, path1| {
debug!("adding local variable {}", p_id);
- let name = ast_util::path_to_ident(path);
+ let name = path1.node;
ir.add_live_node_for_node(p_id, VarDefNode(sp));
ir.add_variable(Local(LocalInfo {
id: p_id,
fn visit_arm(ir: &mut IrMaps, arm: &Arm) {
for pat in arm.pats.iter() {
- pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path| {
+ pat_util::pat_bindings(&ir.tcx.def_map, &**pat, |bm, p_id, sp, path1| {
debug!("adding local variable {} from match with bm {:?}",
p_id, bm);
- let name = ast_util::path_to_ident(path);
+ let name = path1.node;
ir.add_live_node_for_node(p_id, VarDefNode(sp));
ir.add_variable(Local(LocalInfo {
id: p_id,
for arg in decl.inputs.iter() {
pat_util::pat_bindings(&self.ir.tcx.def_map,
&*arg.pat,
- |_bm, p_id, sp, path| {
+ |_bm, p_id, sp, path1| {
let var = self.variable(p_id, sp);
// Ignore unused self.
- let ident = ast_util::path_to_ident(path);
+ let ident = path1.node;
if ident.name != special_idents::self_.name {
self.warn_about_unused(sp, p_id, entry_ln, var);
}
Some(adjustment) => {
match *adjustment {
ty::AutoObject(..) => {
- // Implicity cast a concrete object to trait object.
+ // Implicitly cast a concrete object to trait object.
// Result is an rvalue.
let expr_ty = if_ok!(self.expr_ty_adjusted(expr));
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
use std::collections::HashMap;
use std::gc::{Gc, GC};
use syntax::ast::*;
-use syntax::ast_util::{path_to_ident, walk_pat};
+use syntax::ast_util::{walk_pat};
use syntax::codemap::{Span, DUMMY_SP};
pub type PatIdMap = HashMap<Ident, NodeId>;
// use the NodeId of their namesake in the first pattern.
pub fn pat_id_map(dm: &resolve::DefMap, pat: &Pat) -> PatIdMap {
let mut map = HashMap::new();
- pat_bindings(dm, pat, |_bm, p_id, _s, n| {
- map.insert(path_to_ident(n), p_id);
+ pat_bindings(dm, pat, |_bm, p_id, _s, path1| {
+ map.insert(path1.node, p_id);
});
map
}
/// `match foo() { Some(a) => (), None => () }`
pub fn pat_bindings(dm: &resolve::DefMap,
pat: &Pat,
- it: |BindingMode, NodeId, Span, &Path|) {
+ it: |BindingMode, NodeId, Span, &SpannedIdent|) {
walk_pat(pat, |p| {
match p.node {
PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => {
contains_bindings
}
-pub fn simple_identifier<'a>(pat: &'a Pat) -> Option<&'a Path> {
+pub fn simple_identifier<'a>(pat: &'a Pat) -> Option<&'a Ident> {
match pat.node {
- PatIdent(BindByValue(_), ref path, None) => {
- Some(path)
+ PatIdent(BindByValue(_), ref path1, None) => {
+ Some(&path1.node)
}
_ => {
None
// error messages without (too many) false positives
// (i.e. we could just return here to not check them at
// all, or some worse estimation of whether an impl is
- // publically visible.
+ // publicly visible.
ast::ItemImpl(ref g, ref trait_ref, self_, ref methods) => {
// `impl [... for] Private` is never visible.
let self_contains_private;
use syntax::ast::*;
use syntax::ast;
use syntax::ast_util::{local_def};
-use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method};
+use syntax::ast_util::{walk_pat, trait_method_to_ty_method};
use syntax::ext::mtwt;
use syntax::parse::token::special_idents;
use syntax::parse::token;
-use syntax::print::pprust::path_to_str;
use syntax::codemap::{Span, DUMMY_SP, Pos};
use syntax::owned_slice::OwnedSlice;
use syntax::visit;
// Create the module and add all methods.
match ty.node {
TyPath(ref path, _, _) if path.segments.len() == 1 => {
- let name = path_to_ident(path);
+ let name = path.segments.last().unwrap().identifier;
let parent_opt = parent.module().children.borrow()
.find_copy(&name.name);
// user and one 'x' came from the macro.
fn binding_mode_map(&mut self, pat: &Pat) -> BindingMap {
let mut result = HashMap::new();
- pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path| {
- let name = mtwt::resolve(path_to_ident(path));
+ pat_bindings(&self.def_map, pat, |binding_mode, _id, sp, path1| {
+ let name = mtwt::resolve(path1.node);
result.insert(name,
binding_info {span: sp,
binding_mode: binding_mode});
let pat_id = pattern.id;
walk_pat(pattern, |pattern| {
match pattern.node {
- PatIdent(binding_mode, ref path, _)
- if !path.global && path.segments.len() == 1 => {
+ PatIdent(binding_mode, ref path1, _) => {
// The meaning of pat_ident with no type parameters
// depends on whether an enum variant or unit-like struct
// such a value is simply disallowed (since it's rarely
// what you want).
- let ident = path.segments.get(0).identifier;
+ let ident = path1.node;
let renamed = mtwt::resolve(ident);
match self.resolve_bare_identifier_pattern(ident) {
format!("identifier `{}` is bound \
more than once in the same \
pattern",
- path_to_str(path)).as_slice());
+ token::get_ident(ident)).as_slice());
}
// Else, not bound in the same pattern: do
// nothing.
}
}
-
- // Check the types in the path pattern.
- for ty in path.segments
- .iter()
- .flat_map(|seg| seg.types.iter()) {
- self.resolve_type(&**ty);
- }
- }
-
- PatIdent(binding_mode, ref path, _) => {
- // This must be an enum variant, struct, or constant.
- match self.resolve_path(pat_id, path, ValueNS, false) {
- Some(def @ (DefVariant(..), _)) |
- Some(def @ (DefStruct(..), _)) => {
- self.record_def(pattern.id, def);
- }
- Some(def @ (DefStatic(..), _)) => {
- self.enforce_default_binding_mode(
- pattern,
- binding_mode,
- "a constant");
- self.record_def(pattern.id, def);
- }
- Some(_) => {
- self.resolve_error(
- path.span,
- format!("`{}` is not an enum variant or constant",
- token::get_ident(
- path.segments
- .last()
- .unwrap()
- .identifier)).as_slice())
- }
- None => {
- self.resolve_error(path.span,
- "unresolved enum variant");
- }
- }
-
- // Check the types in the path pattern.
- for ty in path.segments
- .iter()
- .flat_map(|s| s.types.iter()) {
- self.resolve_type(&**ty);
- }
}
PatEnum(ref path, _) => {
in a static method. Maybe a \
`self` argument is missing?");
} else {
- let name = path_to_ident(path).name;
- let mut msg = match self.find_fallback_in_self_type(name) {
+ let last_name = path.segments.last().unwrap().identifier.name;
+ let mut msg = match self.find_fallback_in_self_type(last_name) {
NoSuggestion => {
// limit search to 5 to reduce the number
// of stupid suggestions
{
let qualname = self.analysis.ty_cx.map.path_to_str(item.id);
- // If the variable is immutable, save the initialising expresion.
+ // If the variable is immutable, save the initialising expression.
let value = match mt {
ast::MutMutable => String::from_str("<mutable>"),
ast::MutImmutable => self.span.snippet(expr.span),
let decl_id = ty::trait_method_of_method(&self.analysis.ty_cx, def_id);
// This incantation is required if the method referenced is a trait's
- // defailt implementation.
+ // default implementation.
let def_id = ty::method(&self.analysis.ty_cx, def_id).provided_source
.unwrap_or(def_id);
(Some(def_id), decl_id)
self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
visit::walk_pat(self, p, e);
}
- ast::PatIdent(bm, ref path, ref optional_subpattern) => {
+ ast::PatIdent(bm, ref path1, ref optional_subpattern) => {
let immut = match bm {
// Even if the ref is mut, you can't change the ref, only
// the data pointed at, so showing the initialising expression
}
};
// collect path for either visit_local or visit_arm
- self.collected_paths.push((p.id, path.clone(), immut, recorder::VarRef));
+ let path = ast_util::ident_to_path(path1.span,path1.node);
+ self.collected_paths.push((p.id, path, immut, recorder::VarRef));
match *optional_subpattern {
None => {}
Some(subpattern) => self.visit_pat(&*subpattern, e),
info!("Writing output to {}", disp);
}
- // Create ouput file.
+ // Create output file.
let mut out_name = cratename.clone();
out_name.push_str(".csv");
root_path.push(out_name);
* We store information about the bound variables for each arm as part of the
* per-arm `ArmData` struct. There is a mapping from identifiers to
* `BindingInfo` structs. These structs contain the mode/id/type of the
- * binding, but they also contain up to two LLVM values, called `llmatch` and
- * `llbinding` respectively (the `llbinding`, as will be described shortly, is
- * optional and only present for by-value bindings---therefore it is bundled
- * up as part of the `TransBindingMode` type). Both point at allocas.
+ * binding, but they also contain an LLVM value which points at an alloca
+ * called `llmatch`. For by value bindings that are Copy, we also create
+ * an extra alloca that we copy the matched value to so that any changes
+ * we do to our copy is not reflected in the original and vice-versa.
+ * We don't do this if it's a move since the original value can't be used
+ * and thus allowing us to cheat in not creating an extra alloca.
*
* The `llmatch` binding always stores a pointer into the value being matched
* which points at the data for the binding. If the value being matched has
* up against an identifier, we store the current pointer into the
* corresponding alloca.
*
- * In addition, for each by-value binding (copy or move), we will create a
- * second alloca (`llbinding`) that will hold the final value. In this
- * example, that means that `d` would have this second alloca of type `D` (and
- * hence `llbinding` has type `D*`).
- *
* Once a pattern is completely matched, and assuming that there is no guard
* pattern, we will branch to a block that leads to the body itself. For any
* by-value bindings, this block will first load the ptr from `llmatch` (the
- * one of type `D*`) and copy/move the value into `llbinding` (the one of type
- * `D`). The second alloca then becomes the value of the local variable. For
- * by ref bindings, the value of the local variable is simply the first
- * alloca.
+ * one of type `D*`) and then load a second time to get the actual value (the
+ * one of type `D`). For by ref bindings, the value of the local variable is
+ * simply the first alloca.
*
* So, for the example above, we would generate a setup kind of like this:
*
* | Entry |
* +-------+
* |
- * +-------------------------------------------+
- * | llmatch_c = (addr of first half of tuple) |
- * | llmatch_d = (addr of first half of tuple) |
- * +-------------------------------------------+
+ * +--------------------------------------------+
+ * | llmatch_c = (addr of first half of tuple) |
+ * | llmatch_d = (addr of second half of tuple) |
+ * +--------------------------------------------+
* |
* +--------------------------------------+
- * | *llbinding_d = **llmatch_dlbinding_d |
+ * | *llbinding_d = **llmatch_d |
* +--------------------------------------+
*
* If there is a guard, the situation is slightly different, because we must
* +-------------------------------------------+
* |
* +-------------------------------------------------+
- * | *llbinding_d = **llmatch_dlbinding_d |
+ * | *llbinding_d = **llmatch_d |
* | check condition |
- * | if false { free *llbinding_d, goto next case } |
+ * | if false { goto next case } |
* | if true { goto body } |
* +-------------------------------------------------+
*
* The handling for the cleanups is a bit... sensitive. Basically, the body
* is the one that invokes `add_clean()` for each binding. During the guard
* evaluation, we add temporary cleanups and revoke them after the guard is
- * evaluated (it could fail, after all). Presuming the guard fails, we drop
- * the various values we copied explicitly. Note that guards and moves are
+ * evaluated (it could fail, after all). Note that guards and moves are
* just plain incompatible.
*
* Some relevant helper functions that manage bindings:
* - `create_bindings_map()`
- * - `store_non_ref_bindings()`
* - `insert_lllocals()`
*
*
use lib::llvm::{llvm, ValueRef, BasicBlockRef};
use middle::const_eval;
use middle::def;
-use middle::lang_items::{UniqStrEqFnLangItem, StrEqFnLangItem};
+use middle::check_match;
+use middle::lang_items::StrEqFnLangItem;
use middle::pat_util::*;
use middle::resolve::DefMap;
use middle::trans::adt;
use middle::trans::common::*;
use middle::trans::consts;
use middle::trans::controlflow;
-use middle::trans::datum;
use middle::trans::datum::*;
use middle::trans::expr::Dest;
use middle::trans::expr;
-use middle::trans::glue;
use middle::trans::tvec;
use middle::trans::type_of;
use middle::trans::debuginfo;
use util::common::indenter;
use util::ppaux::{Repr, vec_map_to_str};
+use std;
use std::collections::HashMap;
use std::cell::Cell;
use std::rc::Rc;
-use std::gc::{Gc, GC};
+use std::gc::{Gc};
use syntax::ast;
use syntax::ast::Ident;
-use syntax::ast_util::path_to_ident;
-use syntax::ast_util;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax::codemap::Span;
use syntax::parse::token::InternedString;
-// An option identifying a literal: either a unit-like struct or an
-// expression.
+// An option identifying a literal: either an expression or a DefId of a static expression.
enum Lit {
- UnitLikeStructLit(ast::NodeId), // the node ID of the pattern
ExprLit(Gc<ast::Expr>),
ConstLit(ast::DefId), // the def ID of the constant
}
// range)
enum Opt {
lit(Lit),
- var(ty::Disr, Rc<adt::Repr>),
+ var(ty::Disr, Rc<adt::Repr>, ast::DefId),
range(Gc<ast::Expr>, Gc<ast::Expr>),
vec_len(/* length */ uint, VecLenOpt, /*range of matches*/(uint, uint))
}
fn lit_to_expr(tcx: &ty::ctxt, a: &Lit) -> Gc<ast::Expr> {
match *a {
ExprLit(existing_a_expr) => existing_a_expr,
- ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap(),
- UnitLikeStructLit(_) => fail!("lit_to_expr: unexpected struct lit"),
+ ConstLit(a_const) => const_eval::lookup_const_by_id(tcx, a_const).unwrap()
}
}
fn opt_eq(tcx: &ty::ctxt, a: &Opt, b: &Opt) -> bool {
match (a, b) {
- (&lit(UnitLikeStructLit(a)), &lit(UnitLikeStructLit(b))) => a == b,
(&lit(a), &lit(b)) => {
let a_expr = lit_to_expr(tcx, &a);
let b_expr = lit_to_expr(tcx, &b);
_ => fail!("compare_list_exprs: type mismatch"),
}
}
- (&var(a, _), &var(b, _)) => a == b,
+ (&var(a, _, _), &var(b, _, _)) => a == b,
(&vec_len(a1, a2, _), &vec_len(b1, b2, _)) =>
a1 == b1 && a2 == b2,
_ => false
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
return single_result(Result::new(bcx, lit_datum.val));
}
- lit(UnitLikeStructLit(pat_id)) => {
- let struct_ty = ty::node_id_to_type(bcx.tcx(), pat_id);
- let datum = datum::rvalue_scratch_datum(bcx, struct_ty, "");
- return single_result(Result::new(bcx, datum.val));
- }
lit(l @ ConstLit(ref def_id)) => {
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_to_expr(bcx.tcx(), &l).id);
let (llval, _) = consts::get_const_val(bcx.ccx(), *def_id);
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
return single_result(Result::new(bcx, lit_datum.val));
}
- var(disr_val, ref repr) => {
+ var(disr_val, ref repr, _) => {
return adt::trans_case(bcx, &**repr, disr_val);
}
range(ref l1, ref l2) => {
let def = ccx.tcx.def_map.borrow().get_copy(&pat_id);
match def {
def::DefVariant(enum_id, var_id, _) => {
- let variants = ty::enum_variants(ccx.tcx(), enum_id);
- for v in (*variants).iter() {
- if var_id == v.id {
- return var(v.disr_val,
- adt::represent_node(bcx, pat_id))
- }
- }
- unreachable!();
- }
- def::DefFn(..) |
- def::DefStruct(_) => {
- return lit(UnitLikeStructLit(pat_id));
+ let variant = ty::enum_variant_with_id(ccx.tcx(), enum_id, var_id);
+ var(variant.disr_val, adt::represent_node(bcx, pat_id), var_id)
}
_ => {
ccx.sess().bug("non-variant or struct in variant_opt()");
}
#[deriving(Clone)]
-enum TransBindingMode {
- TrByValue(/*llbinding:*/ ValueRef),
+pub enum TransBindingMode {
+ TrByCopy(/* llbinding */ ValueRef),
+ TrByMove,
TrByRef,
}
* - `id` is the node id of the binding
* - `ty` is the Rust type of the binding */
#[deriving(Clone)]
-struct BindingInfo {
- llmatch: ValueRef,
- trmode: TransBindingMode,
- id: ast::NodeId,
- span: Span,
- ty: ty::t,
+pub struct BindingInfo {
+ pub llmatch: ValueRef,
+ pub trmode: TransBindingMode,
+ pub id: ast::NodeId,
+ pub span: Span,
+ pub ty: ty::t,
}
type BindingsMap = HashMap<Ident, BindingInfo>;
m.iter().map(|br| {
match br.pats.get(col).node {
- ast::PatIdent(_, ref path, Some(inner)) => {
+ ast::PatIdent(_, ref path1, Some(inner)) => {
let pats = Vec::from_slice(br.pats.slice(0u, col))
.append((vec!(inner))
.append(br.pats.slice(col + 1u, br.pats.len())).as_slice());
let mut bound_ptrs = br.bound_ptrs.clone();
- bound_ptrs.push((path_to_ident(path), val));
+ bound_ptrs.push((path1.node, val));
Match {
pats: pats,
data: &*br.data,
}).collect()
}
-fn assert_is_binding_or_wild(bcx: &Block, p: Gc<ast::Pat>) {
- if !pat_is_binding_or_wild(&bcx.tcx().def_map, &*p) {
- bcx.sess().span_bug(
- p.span,
- format!("expected an identifier pattern but found p: {}",
- p.repr(bcx.tcx())).as_slice());
- }
-}
-
-type enter_pat<'a> = |Gc<ast::Pat>|: 'a -> Option<Vec<Gc<ast::Pat>>>;
+type enter_pats<'a> = |&[Gc<ast::Pat>]|: 'a -> Option<Vec<Gc<ast::Pat>>>;
fn enter_match<'a, 'b>(
bcx: &'b Block<'b>,
m: &'a [Match<'a, 'b>],
col: uint,
val: ValueRef,
- e: enter_pat)
+ e: enter_pats)
-> Vec<Match<'a, 'b>> {
debug!("enter_match(bcx={}, m={}, col={}, val={})",
bcx.to_str(),
let _indenter = indenter();
m.iter().filter_map(|br| {
- e(*br.pats.get(col)).map(|sub| {
- let pats = sub.append(br.pats.slice(0u, col))
- .append(br.pats.slice(col + 1u, br.pats.len()));
-
+ e(br.pats.as_slice()).map(|pats| {
let this = *br.pats.get(col);
let mut bound_ptrs = br.bound_ptrs.clone();
match this.node {
- ast::PatIdent(_, ref path, None) => {
+ ast::PatIdent(_, ref path1, None) => {
if pat_is_binding(dm, &*this) {
- bound_ptrs.push((path_to_ident(path), val));
+ bound_ptrs.push((path1.node, val));
}
}
_ => {}
let _indenter = indenter();
// Collect all of the matches that can match against anything.
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatWild | ast::PatWildMulti => Some(Vec::new()),
- ast::PatIdent(_, _, None) if pat_is_binding(dm, &*p) => Some(Vec::new()),
- _ => None
+ enter_match(bcx, dm, m, col, val, |pats| {
+ if pat_is_binding_or_wild(dm, pats[col]) {
+ Some(Vec::from_slice(pats.slice_to(col)).append(pats.slice_from(col + 1)))
+ } else {
+ None
}
})
}
// <nmatsakis> so all patterns must either be records (resp. tuples) or
// wildcards
+/// The above is now outdated in that enter_match() now takes a function that
+/// takes the complete row of patterns rather than just the first one.
+/// Also, most of the enter_() family functions have been unified with
+/// the check_match specialization step.
fn enter_opt<'a, 'b>(
bcx: &'b Block<'b>,
+ _: ast::NodeId,
+ dm: &DefMap,
m: &'a [Match<'a, 'b>],
opt: &Opt,
col: uint,
bcx.val_to_str(val));
let _indenter = indenter();
- let tcx = bcx.tcx();
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- let mut i = 0;
- enter_match(bcx, &tcx.def_map, m, col, val, |p| {
- let answer = match p.node {
- ast::PatEnum(..) |
- ast::PatIdent(_, _, None) if pat_is_const(&tcx.def_map, &*p) => {
- let const_def = tcx.def_map.borrow().get_copy(&p.id);
- let const_def_id = const_def.def_id();
- if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) {
- Some(Vec::new())
- } else {
- None
- }
- }
- ast::PatEnum(_, ref subpats) => {
- if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
- // FIXME: Must we clone?
- match *subpats {
- None => Some(Vec::from_elem(variant_size, dummy)),
- Some(ref subpats) => {
- Some((*subpats).iter().map(|x| *x).collect())
- }
- }
- } else {
- None
- }
- }
- ast::PatIdent(_, _, None)
- if pat_is_variant_or_struct(&tcx.def_map, &*p) => {
- if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
- Some(Vec::new())
- } else {
- None
- }
- }
- ast::PatLit(l) => {
- if opt_eq(tcx, &lit(ExprLit(l)), opt) { Some(Vec::new()) }
- else { None }
- }
- ast::PatRange(l1, l2) => {
- if opt_eq(tcx, &range(l1, l2), opt) { Some(Vec::new()) }
- else { None }
- }
- ast::PatStruct(_, ref field_pats, _) => {
- if opt_eq(tcx, &variant_opt(bcx, p.id), opt) {
- // Look up the struct variant ID.
- let struct_id;
- match tcx.def_map.borrow().get_copy(&p.id) {
- def::DefVariant(_, found_struct_id, _) => {
- struct_id = found_struct_id;
- }
- _ => {
- tcx.sess.span_bug(p.span, "expected enum variant def");
- }
- }
+ let ctor = match opt {
+ &lit(x) => check_match::ConstantValue(const_eval::eval_const_expr(
+ bcx.tcx(), lit_to_expr(bcx.tcx(), &x))),
+ &range(ref lo, ref hi) => check_match::ConstantRange(
+ const_eval::eval_const_expr(bcx.tcx(), &**lo),
+ const_eval::eval_const_expr(bcx.tcx(), &**hi)
+ ),
+ &vec_len(len, _, _) => check_match::Slice(len),
+ &var(_, _, def_id) => check_match::Variant(def_id)
+ };
- // Reorder the patterns into the same order they were
- // specified in the struct definition. Also fill in
- // unspecified fields with dummy.
- let mut reordered_patterns = Vec::new();
- let r = ty::lookup_struct_fields(tcx, struct_id);
- for field in r.iter() {
- match field_pats.iter().find(|p| p.ident.name
- == field.name) {
- None => reordered_patterns.push(dummy),
- Some(fp) => reordered_patterns.push(fp.pat)
- }
- }
- Some(reordered_patterns)
- } else {
- None
- }
- }
+ let mut i = 0;
+ let tcx = bcx.tcx();
+ let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx() };
+ enter_match(bcx, dm, m, col, val, |pats| {
+ let span = pats[col].span;
+ let specialized = match pats[col].node {
ast::PatVec(ref before, slice, ref after) => {
let (lo, hi) = match *opt {
vec_len(_, _, (lo, hi)) => (lo, hi),
- _ => tcx.sess.span_bug(p.span,
+ _ => tcx.sess.span_bug(span,
"vec pattern but not vec opt")
};
- match slice {
+ let elems = match slice {
Some(slice) if i >= lo && i <= hi => {
let n = before.len() + after.len();
let this_opt = vec_len(n, vec_len_ge(before.len()),
}
}
_ => None
- }
+ };
+ elems.map(|head| head.append(pats.slice_to(col)).append(pats.slice_from(col + 1)))
}
_ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(variant_size, dummy))
+ check_match::specialize(&mcx, pats.as_slice(), &ctor, col, variant_size)
}
};
i += 1;
- answer
- })
-}
-
-fn enter_rec_or_struct<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- fields: &[ast::Ident],
- val: ValueRef)
- -> Vec<Match<'a, 'b>> {
- debug!("enter_rec_or_struct(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatStruct(_, ref fpats, _) => {
- let mut pats = Vec::new();
- for fname in fields.iter() {
- match fpats.iter().find(|p| p.ident.name == fname.name) {
- None => pats.push(dummy),
- Some(pat) => pats.push(pat.pat)
- }
- }
- Some(pats)
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(fields.len(), dummy))
- }
- }
- })
-}
-
-fn enter_tup<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef,
- n_elts: uint)
- -> Vec<Match<'a, 'b>> {
- debug!("enter_tup(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatTup(ref elts) => {
- let mut new_elts = Vec::new();
- for elt in elts.iter() {
- new_elts.push((*elt).clone())
- }
- Some(new_elts)
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(n_elts, dummy))
- }
- }
- })
-}
-
-fn enter_tuple_struct<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef,
- n_elts: uint)
- -> Vec<Match<'a, 'b>> {
- debug!("enter_tuple_struct(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatEnum(_, Some(ref elts)) => {
- Some(elts.iter().map(|x| (*x)).collect())
- }
- ast::PatEnum(_, None) => {
- Some(Vec::from_elem(n_elts, dummy))
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(Vec::from_elem(n_elts, dummy))
- }
- }
- })
-}
-
-fn enter_uniq<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef)
- -> Vec<Match<'a, 'b>> {
- debug!("enter_uniq(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat {id: 0, node: ast::PatWild, span: DUMMY_SP};
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatBox(sub) => {
- Some(vec!(sub))
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(vec!(dummy))
- }
- }
- })
-}
-
-fn enter_region<'a, 'b>(
- bcx: &'b Block<'b>,
- dm: &DefMap,
- m: &'a [Match<'a, 'b>],
- col: uint,
- val: ValueRef)
- -> Vec<Match<'a, 'b>> {
- debug!("enter_region(bcx={}, m={}, col={}, val={})",
- bcx.to_str(),
- m.repr(bcx.tcx()),
- col,
- bcx.val_to_str(val));
- let _indenter = indenter();
-
- let dummy = box(GC) ast::Pat { id: 0, node: ast::PatWild, span: DUMMY_SP };
- enter_match(bcx, dm, m, col, val, |p| {
- match p.node {
- ast::PatRegion(sub) => {
- Some(vec!(sub))
- }
- _ => {
- assert_is_binding_or_wild(bcx, p);
- Some(vec!(dummy))
- }
- }
+ specialized
})
}
add_to_set(ccx.tcx(), &mut found, lit(ExprLit(l)));
}
ast::PatIdent(..) => {
- // This is one of: an enum variant, a unit-like struct, or a
- // variable binding.
+ // This is either an enum variant or a variable binding.
let opt_def = ccx.tcx.def_map.borrow().find_copy(&cur.id);
match opt_def {
Some(def::DefVariant(..)) => {
add_to_set(ccx.tcx(), &mut found,
variant_opt(bcx, cur.id));
}
- Some(def::DefStruct(..)) => {
- add_to_set(ccx.tcx(), &mut found,
- lit(UnitLikeStructLit(cur.id)));
- }
Some(def::DefStatic(const_did, false)) => {
add_to_set(ccx.tcx(), &mut found,
lit(ConstLit(const_did)));
ExtractedBlock { vals: elems, bcx: bcx }
}
-/// Checks every pattern in `m` at `col` column.
-/// If there are a struct pattern among them function
-/// returns list of all fields that are matched in these patterns.
-/// Function returns None if there is no struct pattern.
-/// Function doesn't collect fields from struct-like enum variants.
-/// Function can return empty list if there is only wildcard struct pattern.
-fn collect_record_or_struct_fields<'a>(
- bcx: &'a Block<'a>,
- m: &[Match],
- col: uint)
- -> Option<Vec<ast::Ident> > {
- let mut fields: Vec<ast::Ident> = Vec::new();
- let mut found = false;
- for br in m.iter() {
- match br.pats.get(col).node {
- ast::PatStruct(_, ref fs, _) => {
- match ty::get(node_id_type(bcx, br.pats.get(col).id)).sty {
- ty::ty_struct(..) => {
- extend(&mut fields, fs.as_slice());
- found = true;
- }
- _ => ()
- }
- }
- _ => ()
- }
- }
- if found {
- return Some(fields);
- } else {
- return None;
- }
-
- fn extend(idents: &mut Vec<ast::Ident> , field_pats: &[ast::FieldPat]) {
- for field_pat in field_pats.iter() {
- let field_ident = field_pat.ident;
- if !idents.iter().any(|x| x.name == field_ident.name) {
- idents.push(field_ident);
- }
- }
- }
-}
-
// Macro for deciding whether any of the remaining matches fit a given kind of
// pattern. Note that, because the macro is well-typed, either ALL of the
// matches should fit that sort of pattern or NONE (however, some of the
any_pat!(m, ast::PatRegion(_))
}
-fn any_tup_pat(m: &[Match], col: uint) -> bool {
- any_pat!(m, ast::PatTup(_))
-}
-
-fn any_tuple_struct_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
+fn any_irrefutable_adt_pat(bcx: &Block, m: &[Match], col: uint) -> bool {
m.iter().any(|br| {
let pat = *br.pats.get(col);
match pat.node {
- ast::PatEnum(_, _) => {
+ ast::PatTup(_) => true,
+ ast::PatEnum(..) | ast::PatIdent(_, _, None) | ast::PatStruct(..) =>
match bcx.tcx().def_map.borrow().find(&pat.id) {
Some(&def::DefFn(..)) |
Some(&def::DefStruct(..)) => true,
_ => false
- }
- }
+ },
_ => false
}
})
}
#[deriving(PartialEq)]
-pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len, }
+pub enum branch_kind { no_branch, single, switch, compare, compare_vec_len }
// Compiles a comparison between two things.
fn compare_values<'a>(
}
match ty::get(rhs_t).sty {
- ty::ty_uniq(t) => match ty::get(t).sty {
- ty::ty_str => {
- let scratch_lhs = alloca(cx, val_ty(lhs), "__lhs");
- Store(cx, lhs, scratch_lhs);
- let scratch_rhs = alloca(cx, val_ty(rhs), "__rhs");
- Store(cx, rhs, scratch_rhs);
- let did = langcall(cx,
- None,
- format!("comparison of `{}`",
- cx.ty_to_str(rhs_t)).as_slice(),
- UniqStrEqFnLangItem);
- callee::trans_lang_call(cx, did, [scratch_lhs, scratch_rhs], None)
- }
- _ => cx.sess().bug("only strings supported in compare_values"),
- },
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
ty::ty_str => compare_str(cx, lhs, rhs, rhs_t),
ty::ty_vec(mt, _) => match ty::get(mt.ty).sty {
},
_ => cx.sess().bug("only byte strings supported in compare_values"),
},
- _ => cx.sess().bug("on string and byte strings supported in compare_values"),
+ _ => cx.sess().bug("only string and byte strings supported in compare_values"),
},
_ => cx.sess().bug("only scalars, byte strings, and strings supported in compare_values"),
}
}
-fn store_non_ref_bindings<'a>(
- bcx: &'a Block<'a>,
- bindings_map: &BindingsMap,
- opt_cleanup_scope: Option<cleanup::ScopeId>)
- -> &'a Block<'a>
-{
- /*!
- * For each copy/move binding, copy the value from the value being
- * matched into its final home. This code executes once one of
- * the patterns for a given arm has completely matched. It adds
- * cleanups to the `opt_cleanup_scope`, if one is provided.
- */
-
- let fcx = bcx.fcx;
- let mut bcx = bcx;
- for (_, &binding_info) in bindings_map.iter() {
- match binding_info.trmode {
- TrByValue(lldest) => {
- let llval = Load(bcx, binding_info.llmatch); // get a T*
- let datum = Datum::new(llval, binding_info.ty, Lvalue);
- bcx = datum.store_to(bcx, lldest);
-
- match opt_cleanup_scope {
- None => {}
- Some(s) => {
- fcx.schedule_drop_mem(s, lldest, binding_info.ty);
- }
- }
- }
- TrByRef => {}
- }
- }
- return bcx;
-}
-
-fn insert_lllocals<'a>(bcx: &'a Block<'a>,
- bindings_map: &BindingsMap,
- cleanup_scope: cleanup::ScopeId)
+fn insert_lllocals<'a>(mut bcx: &'a Block<'a>,
+ bindings_map: &BindingsMap)
-> &'a Block<'a> {
/*!
* For each binding in `data.bindings_map`, adds an appropriate entry into
- * the `fcx.lllocals` map, scheduling cleanup in `cleanup_scope`.
+ * the `fcx.lllocals` map
*/
- let fcx = bcx.fcx;
-
for (&ident, &binding_info) in bindings_map.iter() {
let llval = match binding_info.trmode {
- // By value bindings: use the stack slot that we
- // copied/moved the value into
- TrByValue(lldest) => lldest,
+ // By value mut binding for a copy type: load from the ptr
+ // into the matched value and copy to our alloca
+ TrByCopy(llbinding) => {
+ let llval = Load(bcx, binding_info.llmatch);
+ let datum = Datum::new(llval, binding_info.ty, Lvalue);
+ bcx = datum.store_to(bcx, llbinding);
+
+ llbinding
+ },
+
+ // By value move bindings: load from the ptr into the matched value
+ TrByMove => Load(bcx, binding_info.llmatch),
// By ref binding: use the ptr into the matched value
TrByRef => binding_info.llmatch
};
let datum = Datum::new(llval, binding_info.ty, Lvalue);
- fcx.schedule_drop_mem(cleanup_scope, llval, binding_info.ty);
debug!("binding {:?} to {}",
binding_info.id,
if bcx.sess().opts.debuginfo == FullDebugInfo {
debuginfo::create_match_binding_metadata(bcx,
ident,
- binding_info.id,
- binding_info.span,
- datum);
+ binding_info);
}
}
bcx
vec_map_to_str(vals, |v| bcx.val_to_str(*v)));
let _indenter = indenter();
- // Lest the guard itself should fail, introduce a temporary cleanup
- // scope for any non-ref bindings we create.
- let temp_scope = bcx.fcx.push_custom_cleanup_scope();
-
- let mut bcx = bcx;
- bcx = store_non_ref_bindings(bcx, &data.bindings_map,
- Some(cleanup::CustomScope(temp_scope)));
- bcx = insert_lllocals(bcx, &data.bindings_map,
- cleanup::CustomScope(temp_scope));
+ let mut bcx = insert_lllocals(bcx, &data.bindings_map);
let val = unpack_datum!(bcx, expr::trans(bcx, guard_expr));
let val = val.to_llbool(bcx);
- // Cancel cleanups now that the guard successfully executed. If
- // the guard was false, we will drop the values explicitly
- // below. Otherwise, we'll add lvalue cleanups at the end.
- bcx.fcx.pop_custom_cleanup_scope(temp_scope);
-
return with_cond(bcx, Not(bcx, val), |bcx| {
- // Guard does not match: free the values we copied,
- // and remove all bindings from the lllocals table
- let bcx = drop_bindings(bcx, data);
+ // Guard does not match: remove all bindings from the lllocals table
+ for (_, &binding_info) in data.bindings_map.iter() {
+ bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
+ }
match chk {
// If the default arm is the only one left, move on to the next
// condition explicitly rather than (possibly) falling back to
};
bcx
});
-
- fn drop_bindings<'a>(bcx: &'a Block<'a>, data: &ArmData)
- -> &'a Block<'a> {
- let mut bcx = bcx;
- for (_, &binding_info) in data.bindings_map.iter() {
- match binding_info.trmode {
- TrByValue(llval) => {
- bcx = glue::drop_ty(bcx, llval, binding_info.ty);
- }
- TrByRef => {}
- }
- bcx.fcx.lllocals.borrow_mut().remove(&binding_info.id);
- }
- return bcx;
- }
}
fn compile_submatch<'a, 'b>(
let vals_left = Vec::from_slice(vals.slice(0u, col)).append(vals.slice(col + 1u, vals.len()));
let ccx = bcx.fcx.ccx;
- let mut pat_id = 0;
- for br in m.iter() {
- // Find a real id (we're adding placeholder wildcard patterns, but
- // each column is guaranteed to have at least one real pattern)
- if pat_id == 0 {
- pat_id = br.pats.get(col).id;
- }
- }
- match collect_record_or_struct_fields(bcx, m, col) {
- Some(ref rec_fields) => {
- let pat_ty = node_id_type(bcx, pat_id);
- let pat_repr = adt::represent_type(bcx.ccx(), pat_ty);
- expr::with_field_tys(tcx, pat_ty, Some(pat_id), |discr, field_tys| {
- let rec_vals = rec_fields.iter().map(|field_name| {
- let ix = ty::field_idx_strict(tcx, field_name.name, field_tys);
- adt::trans_field_ptr(bcx, &*pat_repr, val, discr, ix)
- }).collect::<Vec<_>>();
- compile_submatch(
- bcx,
- enter_rec_or_struct(bcx,
- dm,
- m,
- col,
- rec_fields.as_slice(),
- val).as_slice(),
- rec_vals.append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- });
- return;
- }
- None => {}
- }
+ // Find a real id (we're adding placeholder wildcard patterns, but
+ // each column is guaranteed to have at least one real pattern)
+ let pat_id = m.iter().map(|br| br.pats.get(col).id).find(|&id| id != 0).unwrap_or(0);
- if any_tup_pat(m, col) {
- let tup_ty = node_id_type(bcx, pat_id);
- let tup_repr = adt::represent_type(bcx.ccx(), tup_ty);
- let n_tup_elts = match ty::get(tup_ty).sty {
- ty::ty_tup(ref elts) => elts.len(),
- _ => ccx.sess().bug("non-tuple type in tuple pattern")
- };
- let tup_vals = Vec::from_fn(n_tup_elts, |i| {
- adt::trans_field_ptr(bcx, &*tup_repr, val, 0, i)
- });
- compile_submatch(bcx,
- enter_tup(bcx,
- dm,
- m,
- col,
- val,
- n_tup_elts).as_slice(),
- tup_vals.append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
- }
-
- if any_tuple_struct_pat(bcx, m, col) {
- let struct_ty = node_id_type(bcx, pat_id);
- let struct_element_count;
- match ty::get(struct_ty).sty {
- ty::ty_struct(struct_id, _) => {
- struct_element_count =
- ty::lookup_struct_fields(tcx, struct_id).len();
- }
- _ => {
- ccx.sess().bug("non-struct type in tuple struct pattern");
- }
- }
-
- let struct_repr = adt::represent_type(bcx.ccx(), struct_ty);
- let llstructvals = Vec::from_fn(struct_element_count, |i| {
- adt::trans_field_ptr(bcx, &*struct_repr, val, 0, i)
- });
- compile_submatch(bcx,
- enter_tuple_struct(bcx, dm, m, col, val,
- struct_element_count).as_slice(),
- llstructvals.append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
- }
+ let left_ty = if pat_id == 0 {
+ ty::mk_nil()
+ } else {
+ node_id_type(bcx, pat_id)
+ };
- if any_uniq_pat(m, col) {
- let llbox = Load(bcx, val);
- compile_submatch(bcx,
- enter_uniq(bcx, dm, m, col, val).as_slice(),
- (vec!(llbox)).append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
- }
+ let mcx = check_match::MatchCheckCtxt { tcx: bcx.tcx() };
+ let adt_vals = if any_irrefutable_adt_pat(bcx, m, col) {
+ let repr = adt::represent_type(bcx.ccx(), left_ty);
+ let arg_count = adt::num_args(&*repr, 0);
+ let field_vals: Vec<ValueRef> = std::iter::range(0, arg_count).map(|ix|
+ adt::trans_field_ptr(bcx, &*repr, val, 0, ix)
+ ).collect();
+ Some(field_vals)
+ } else if any_uniq_pat(m, col) || any_region_pat(m, col) {
+ Some(vec!(Load(bcx, val)))
+ } else {
+ None
+ };
- if any_region_pat(m, col) {
- let loaded_val = Load(bcx, val);
- compile_submatch(bcx,
- enter_region(bcx, dm, m, col, val).as_slice(),
- (vec!(loaded_val)).append(vals_left.as_slice()).as_slice(),
- chk, has_genuine_default);
- return;
+ match adt_vals {
+ Some(field_vals) => {
+ let pats = enter_match(bcx, dm, m, col, val, |pats|
+ check_match::specialize(&mcx, pats, &check_match::Single, col, field_vals.len())
+ );
+ let vals = field_vals.append(vals_left.as_slice());
+ compile_submatch(bcx, pats.as_slice(), vals.as_slice(), chk, has_genuine_default);
+ return;
+ }
+ _ => ()
}
// Decide what kind of branch we need
debug!("test_val={}", bcx.val_to_str(test_val));
if opts.len() > 0u {
match *opts.get(0) {
- var(_, ref repr) => {
+ var(_, ref repr, _) => {
let (the_kind, val_opt) = adt::trans_switch(bcx, &**repr, val);
kind = the_kind;
for &tval in val_opt.iter() { test_val = tval; }
}
lit(_) => {
- let pty = node_id_type(bcx, pat_id);
- test_val = load_if_immediate(bcx, val, pty);
- kind = if ty::type_is_integral(pty) { switch }
+ test_val = load_if_immediate(bcx, val, left_ty);
+ kind = if ty::type_is_integral(left_ty) { switch }
else { compare };
}
range(_, _) => {
kind = compare;
},
vec_len(..) => {
- let vec_ty = node_id_type(bcx, pat_id);
- let (_, len) = tvec::get_base_and_len(bcx, val, vec_ty);
+ let (_, len) = tvec::get_base_and_len(bcx, val, left_ty);
test_val = len;
kind = compare_vec_len;
}
}
}
}
- compare => {
- let t = node_id_type(bcx, pat_id);
+ compare | compare_vec_len => {
+ let t = if kind == compare {
+ left_ty
+ } else {
+ ty::mk_uint() // vector length
+ };
let Result {bcx: after_cx, val: matches} = {
match trans_opt(bcx, opt) {
single_result(Result {bcx, val}) => {
compare_values(bcx, test_val, val, t)
}
lower_bound(Result {bcx, val}) => {
- compare_scalar_types(
- bcx, test_val, val,
- t, ast::BiGe)
+ compare_scalar_types(bcx, test_val, val, t, ast::BiGe)
}
range_result(Result {val: vbegin, ..},
Result {bcx, val: vend}) => {
// the default.
let guarded = m[i].data.arm.guard.is_some();
let multi_pats = m[i].pats.len() > 1;
- if i+1 < len && (guarded || multi_pats) {
- branch_chk = Some(JumpToBasicBlock(bcx.llbb));
- }
- CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
- }
- compare_vec_len => {
- let Result {bcx: after_cx, val: matches} = {
- match trans_opt(bcx, opt) {
- single_result(
- Result {bcx, val}) => {
- let value = compare_scalar_values(
- bcx, test_val, val,
- signed_int, ast::BiEq);
- Result::new(bcx, value)
- }
- lower_bound(
- Result {bcx, val: val}) => {
- let value = compare_scalar_values(
- bcx, test_val, val,
- signed_int, ast::BiGe);
- Result::new(bcx, value)
- }
- range_result(
- Result {val: vbegin, ..},
- Result {bcx, val: vend}) => {
- let llge =
- compare_scalar_values(
- bcx, test_val,
- vbegin, signed_int, ast::BiGe);
- let llle =
- compare_scalar_values(
- bcx, test_val, vend,
- signed_int, ast::BiLe);
- Result::new(bcx, And(bcx, llge, llle))
- }
- }
- };
- bcx = fcx.new_temp_block("compare_vec_len_next");
-
- // If none of these subcases match, move on to the
- // next condition if there is any.
- if i+1 < len {
+ if i + 1 < len && (guarded || multi_pats || kind == compare_vec_len) {
branch_chk = Some(JumpToBasicBlock(bcx.llbb));
}
CondBr(after_cx, matches, opt_cx.llbb, bcx.llbb);
let mut size = 0u;
let mut unpacked = Vec::new();
match *opt {
- var(disr_val, ref repr) => {
+ var(disr_val, ref repr, _) => {
let ExtractedBlock {vals: argvals, bcx: new_bcx} =
extract_variant_args(opt_cx, &**repr, disr_val, val);
size = argvals.len();
}
lit(_) | range(_, _) => ()
}
- let opt_ms = enter_opt(opt_cx, m, opt, col, size, val);
+ let opt_ms = enter_opt(opt_cx, pat_id, dm, m, opt, col, size, val);
let opt_vals = unpacked.append(vals_left.as_slice());
match branch_chk {
let ccx = bcx.ccx();
let tcx = bcx.tcx();
let mut bindings_map = HashMap::new();
- pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path| {
- let ident = path_to_ident(path);
+ pat_bindings(&tcx.def_map, &*pat, |bm, p_id, span, path1| {
+ let ident = path1.node;
let variable_ty = node_id_type(bcx, p_id);
let llvariable_ty = type_of::type_of(ccx, variable_ty);
+ let tcx = bcx.tcx();
let llmatch;
let trmode;
match bm {
+ ast::BindByValue(_)
+ if !ty::type_moves_by_default(tcx, variable_ty) => {
+ llmatch = alloca(bcx,
+ llvariable_ty.ptr_to(),
+ "__llmatch");
+ trmode = TrByCopy(alloca(bcx,
+ llvariable_ty,
+ bcx.ident(ident).as_slice()));
+ }
ast::BindByValue(_) => {
// in this case, the final type of the variable will be T,
// but during matching we need to store a *T as explained
// above
- llmatch = alloca(bcx, llvariable_ty.ptr_to(), "__llmatch");
- trmode = TrByValue(alloca(bcx,
- llvariable_ty,
- bcx.ident(ident).as_slice()));
+ llmatch = alloca(bcx,
+ llvariable_ty.ptr_to(),
+ bcx.ident(ident).as_slice());
+ trmode = TrByMove;
}
ast::BindByRef(_) => {
llmatch = alloca(bcx,
for arm_data in arm_datas.iter() {
let mut bcx = arm_data.bodycx;
- // If this arm has a guard, then the various by-value bindings have
- // already been copied into their homes. If not, we do it here. This
- // is just to reduce code space. See extensive comment at the start
- // of the file for more details.
- if arm_data.arm.guard.is_none() {
- bcx = store_non_ref_bindings(bcx, &arm_data.bindings_map, None);
- }
-
- // insert bindings into the lllocals map and add cleanups
- let cleanup_scope = fcx.push_custom_cleanup_scope();
- bcx = insert_lllocals(bcx, &arm_data.bindings_map,
- cleanup::CustomScope(cleanup_scope));
+ // insert bindings into the lllocals map
+ bcx = insert_lllocals(bcx, &arm_data.bindings_map);
bcx = expr::trans_into(bcx, &*arm_data.arm.body, dest);
- bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cleanup_scope);
arm_cxs.push(bcx);
}
// In such cases, the more general path is unsafe, because
// it assumes it is matching against a valid value.
match simple_identifier(&*pat) {
- Some(path) => {
+ Some(ident) => {
let var_scope = cleanup::var_scope(tcx, local.id);
return mk_binding_alloca(
- bcx, pat.id, path, BindLocal, var_scope, (),
+ bcx, pat.id, ident, BindLocal, var_scope, (),
|(), bcx, v, _| expr::trans_into(bcx, &*init_expr,
expr::SaveIn(v)));
}
// create dummy memory for the variables if we have no
// value to store into them immediately
let tcx = bcx.tcx();
- pat_bindings(&tcx.def_map, &*pat, |_, p_id, _, path| {
+ pat_bindings(&tcx.def_map, &*pat, |_, p_id, _, path1| {
let scope = cleanup::var_scope(tcx, p_id);
bcx = mk_binding_alloca(
- bcx, p_id, path, BindLocal, scope, (),
+ bcx, p_id, &path1.node, BindLocal, scope, (),
|(), bcx, llval, ty| { zero_mem(bcx, llval, ty); bcx });
});
bcx
let _icx = push_ctxt("match::store_arg");
match simple_identifier(&*pat) {
- Some(path) => {
+ Some(ident) => {
// Generate nicer LLVM for the common case of fn a pattern
// like `x: T`
let arg_ty = node_id_type(bcx, pat.id);
bcx
} else {
mk_binding_alloca(
- bcx, pat.id, path, BindArgument, arg_scope, arg,
+ bcx, pat.id, ident, BindArgument, arg_scope, arg,
|arg, bcx, llval, _| arg.store_to(bcx, llval))
}
}
fn mk_binding_alloca<'a,A>(bcx: &'a Block<'a>,
p_id: ast::NodeId,
- path: &ast::Path,
+ ident: &ast::Ident,
binding_mode: IrrefutablePatternBindingMode,
cleanup_scope: cleanup::ScopeId,
arg: A,
populate: |A, &'a Block<'a>, ValueRef, ty::t| -> &'a Block<'a>)
-> &'a Block<'a> {
let var_ty = node_id_type(bcx, p_id);
- let ident = ast_util::path_to_ident(path);
// Allocate memory on stack for the binding.
- let llval = alloc_ty(bcx, var_ty, bcx.ident(ident).as_slice());
+ let llval = alloc_ty(bcx, var_ty, bcx.ident(*ident).as_slice());
// Subtle: be sure that we *populate* the memory *before*
// we schedule the cleanup.
let tcx = bcx.tcx();
let ccx = bcx.ccx();
match pat.node {
- ast::PatIdent(pat_binding_mode, ref path, inner) => {
+ ast::PatIdent(pat_binding_mode, ref path1, inner) => {
if pat_is_binding(&tcx.def_map, &*pat) {
// Allocate the stack slot where the value of this
// binding will live and place it into the appropriate
// map.
bcx = mk_binding_alloca(
- bcx, pat.id, path, binding_mode, cleanup_scope, (),
+ bcx, pat.id, &path1.node, binding_mode, cleanup_scope, (),
|(), bcx, llval, ty| {
match pat_binding_mode {
ast::BindByValue(_) => {
let function_type =
ty::mk_bare_fn(tcx, method.fty.clone()).subst(tcx, &substs);
- let function_name = tcx.map.with_path(method_id.node, |path| {
+ let function_name = ty::with_path(tcx, method_id, |path| {
link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim")
});
let llfn = decl_internal_rust_fn(ccx,
use middle::subst;
use middle::trans::adt;
use middle::trans::common::*;
-use middle::trans::datum::{Datum, Lvalue};
use middle::trans::machine;
+use middle::trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
use middle::trans::type_of;
use middle::trans::type_::Type;
use middle::trans;
static DW_ATE_unsigned: c_uint = 0x07;
static DW_ATE_unsigned_char: c_uint = 0x08;
+static UNKNOWN_LINE_NUMBER: c_uint = 0;
+static UNKNOWN_COLUMN_NUMBER: c_uint = 0;
+
+// ptr::null() doesn't work :(
+static UNKNOWN_FILE_METADATA: DIFile = (0 as DIFile);
+static UNKNOWN_SCOPE_METADATA: DIScope = (0 as DIScope);
+
//=-----------------------------------------------------------------------------
// Public Interface of debuginfo module
//=-----------------------------------------------------------------------------
unique_type_id.push_char('{');
match ty::get(type_).sty {
- ty::ty_nil |
- ty::ty_bot |
- ty::ty_bool |
- ty::ty_char |
- ty::ty_str |
- ty::ty_int(_) |
- ty::ty_uint(_) |
+ ty::ty_nil |
+ ty::ty_bot |
+ ty::ty_bool |
+ ty::ty_char |
+ ty::ty_str |
+ ty::ty_int(_) |
+ ty::ty_uint(_) |
ty::ty_float(_) => {
- unique_type_id.push_str(ppaux::ty_to_str(cx.tcx(), type_).as_slice());
+ push_debuginfo_type_name(cx, type_, false, &mut unique_type_id);
},
ty::ty_enum(def_id, ref substs) => {
unique_type_id.push_str("enum ");
element_type: ty::t)
-> UniqueTypeId {
let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
- let heap_vec_box_type_id = format!("$$HEAP_VEC_BOX<{}>$$",
+ let heap_vec_box_type_id = format!("{{HEAP_VEC_BOX<{}>}}",
self.get_unique_type_id_as_string(element_type_id)
.as_slice());
let interner_key = self.unique_id_interner.intern(Rc::new(heap_vec_box_type_id));
element_type: ty::t)
-> UniqueTypeId {
let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
- let gc_box_type_id = format!("$$GC_BOX<{}>$$",
+ let gc_box_type_id = format!("{{GC_BOX<{}>}}",
self.get_unique_type_id_as_string(element_type_id)
.as_slice());
let interner_key = self.unique_id_interner.intern(Rc::new(gc_box_type_id));
}
}
+// Returns from the enclosing function if the type metadata with the given
+// unique id can be found in the type map
+macro_rules! return_if_metadata_created_in_meantime(
+ ($cx: expr, $unique_type_id: expr) => (
+ match debug_context($cx).type_map
+ .borrow()
+ .find_metadata_for_unique_id($unique_type_id) {
+ Some(metadata) => return MetadataCreationResult::new(metadata, true),
+ None => { /* proceed normally */ }
+ };
+ )
+)
+
/// A context object for maintaining all state needed by the debuginfo module.
pub struct CrateDebugContext {
let cx = bcx.ccx();
let def_map = &cx.tcx.def_map;
- pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, path_ref| {
- let var_ident = ast_util::path_to_ident(path_ref);
+ pat_util::pat_bindings(def_map, &*local.pat, |_, node_id, span, path1| {
+ let var_ident = path1.node;
let datum = match bcx.fcx.lllocals.borrow().find_copy(&node_id) {
Some(datum) => datum,
}
Some(ast_map::NodeLocal(pat)) | Some(ast_map::NodeArg(pat)) => {
match pat.node {
- ast::PatIdent(_, ref path, _) => {
- ast_util::path_to_ident(path)
+ ast::PatIdent(_, ref path1, _) => {
+ path1.node
}
_ => {
cx.sess()
/// Adds the created metadata nodes directly to the crate's IR.
pub fn create_match_binding_metadata(bcx: &Block,
variable_ident: ast::Ident,
- node_id: ast::NodeId,
- span: Span,
- datum: Datum<Lvalue>) {
+ binding: BindingInfo) {
if fn_should_be_ignored(bcx.fcx) {
return;
}
- let scope_metadata = scope_metadata(bcx.fcx, node_id, span);
+ let scope_metadata = scope_metadata(bcx.fcx, binding.id, binding.span);
+ let aops = unsafe {
+ [llvm::LLVMDIBuilderCreateOpDeref(bcx.ccx().int_type.to_ref())]
+ };
+ // Regardless of the actual type (`T`) we're always passed the stack slot (alloca)
+ // for the binding. For ByRef bindings that's a `T*` but for ByMove bindings we
+ // actually have `T**`. So to get the actual variable we need to dereference once
+ // more. For ByCopy we just use the stack slot we created for the binding.
+ let var_type = match binding.trmode {
+ TrByCopy(llbinding) => DirectVariable {
+ alloca: llbinding
+ },
+ TrByMove => IndirectVariable {
+ alloca: binding.llmatch,
+ address_operations: aops
+ },
+ TrByRef => DirectVariable {
+ alloca: binding.llmatch
+ }
+ };
declare_local(bcx,
variable_ident,
- datum.ty,
+ binding.ty,
scope_metadata,
- DirectVariable { alloca: datum.val },
+ var_type,
LocalVariable,
- span);
+ binding.span);
}
/// Creates debug information for the given function argument.
let def_map = &cx.tcx.def_map;
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata;
- pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, path_ref| {
+ pat_util::pat_bindings(def_map, &*arg.pat, |_, node_id, span, path1| {
let llarg = match bcx.fcx.llargs.borrow().find_copy(&node_id) {
Some(v) => v,
None => {
Referenced variable location is not an alloca!");
}
- let argument_ident = ast_util::path_to_ident(path_ref);
-
let argument_index = {
let counter = &fcx.debug_context.get_ref(cx, span).argument_counter;
let argument_index = counter.get();
};
declare_local(bcx,
- argument_ident,
+ path1.node,
llarg.ty,
scope_metadata,
DirectVariable { alloca: llarg.val },
if has_self_type {
let actual_self_type = self_type.unwrap();
// Add self type name to <...> clause of function name
- let actual_self_type_name = ppaux::ty_to_str(cx.tcx(), actual_self_type);
- name_to_append_suffix_to.push_str(
- actual_self_type_name.as_slice());
+ let actual_self_type_name = compute_debuginfo_type_name(
+ cx,
+ actual_self_type,
+ true);
+
+ name_to_append_suffix_to.push_str(actual_self_type_name.as_slice());
if generics.is_type_parameterized() {
name_to_append_suffix_to.push_str(",");
for (index, &ast::TyParam{ ident: ident, .. }) in generics.ty_params.iter().enumerate() {
let actual_type = *actual_types.get(index);
// Add actual type name to <...> clause of function name
- let actual_type_name = ppaux::ty_to_str(cx.tcx(), actual_type);
+ let actual_type_name = compute_debuginfo_type_name(cx,
+ actual_type,
+ true);
name_to_append_suffix_to.push_str(actual_type_name.as_slice());
if index != generics.ty_params.len() - 1 {
-> DIType {
let pointer_llvm_type = type_of::type_of(cx, pointer_type);
let (pointer_size, pointer_align) = size_and_align_of(cx, pointer_llvm_type);
- let name = ppaux::ty_to_str(cx.tcx(), pointer_type);
+ let name = compute_debuginfo_type_name(cx, pointer_type, false);
let ptr_metadata = name.as_slice().with_c_str(|name| {
unsafe {
llvm::LLVMDIBuilderCreatePointerType(
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
- file_metadata: DIFile,
member_description_factory: MemberDescriptionFactory,
},
FinalMetadata(DICompositeType)
unique_type_id: UniqueTypeId,
metadata_stub: DICompositeType,
llvm_type: Type,
- file_metadata: DIFile,
member_description_factory: MemberDescriptionFactory)
-> RecursiveTypeDescription {
unique_type_id: unique_type_id,
metadata_stub: metadata_stub,
llvm_type: llvm_type,
- file_metadata: file_metadata,
member_description_factory: member_description_factory,
}
}
unique_type_id,
metadata_stub,
llvm_type,
- file_metadata,
- ref member_description_factory
+ ref member_description_factory,
+ ..
} => {
// Make sure that we have a forward declaration of the type in
// the TypeMap so that recursive references are possible. This
set_members_of_composite_type(cx,
metadata_stub,
llvm_type,
- member_descriptions.as_slice(),
- file_metadata,
- codemap::DUMMY_SP);
+ member_descriptions.as_slice());
return MetadataCreationResult::new(metadata_stub, true);
}
}
}
}
+
fn prepare_struct_metadata(cx: &CrateContext,
struct_type: ty::t,
def_id: ast::DefId,
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
- let struct_name = ppaux::ty_to_str(cx.tcx(), struct_type);
+ let struct_name = compute_debuginfo_type_name(cx, struct_type, false);
let struct_llvm_type = type_of::type_of(cx, struct_type);
- let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id);
-
- let file_name = span_start(cx, definition_span).file.name.clone();
- let file_metadata = file_metadata(cx, file_name.as_slice());
+ let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
let struct_metadata_stub = create_struct_stub(cx,
struct_llvm_type,
struct_name.as_slice(),
unique_type_id,
- containing_scope,
- file_metadata,
- definition_span);
+ containing_scope);
let fields = ty::struct_fields(cx.tcx(), def_id, substs);
unique_type_id,
struct_metadata_stub,
struct_llvm_type,
- file_metadata,
StructMDF(StructMemberDescriptionFactory {
fields: fields,
is_simd: ty::type_is_simd(cx.tcx(), struct_type),
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
- let tuple_name = ppaux::ty_to_str(cx.tcx(), tuple_type);
+ let tuple_name = compute_debuginfo_type_name(cx, tuple_type, false);
let tuple_llvm_type = type_of::type_of(cx, tuple_type);
- let loc = span_start(cx, span);
- let file_metadata = file_metadata(cx, loc.file.name.as_slice());
-
create_and_register_recursive_type_forward_declaration(
cx,
tuple_type,
tuple_llvm_type,
tuple_name.as_slice(),
unique_type_id,
- file_metadata,
- file_metadata,
- span),
+ UNKNOWN_SCOPE_METADATA),
tuple_llvm_type,
- file_metadata,
TupleMDF(TupleMemberDescriptionFactory {
component_types: Vec::from_slice(component_types),
span: span,
&**self.variants.get(i),
discriminant_info,
self.containing_scope,
- self.file_metadata,
self.span);
let member_descriptions = member_desc_factory
set_members_of_composite_type(cx,
variant_type_metadata,
variant_llvm_type,
- member_descriptions.as_slice(),
- self.file_metadata,
- codemap::DUMMY_SP);
+ member_descriptions.as_slice());
MemberDescription {
name: "".to_string(),
llvm_type: variant_llvm_type,
&**self.variants.get(0),
NoDiscriminant,
self.containing_scope,
- self.file_metadata,
self.span);
let member_descriptions =
set_members_of_composite_type(cx,
variant_type_metadata,
variant_llvm_type,
- member_descriptions.as_slice(),
- self.file_metadata,
- codemap::DUMMY_SP);
+ member_descriptions.as_slice());
vec![
MemberDescription {
name: "".to_string(),
&**self.variants.get(nndiscr as uint),
OptimizedDiscriminant(ptrfield),
self.containing_scope,
- self.file_metadata,
self.span);
let variant_member_descriptions =
set_members_of_composite_type(cx,
variant_type_metadata,
variant_llvm_type,
- variant_member_descriptions.as_slice(),
- self.file_metadata,
- codemap::DUMMY_SP);
+ variant_member_descriptions.as_slice());
// Encode the information about the null variant in the union
// member's name.
variant_info: &ty::VariantInfo,
discriminant_info: EnumDiscriminantInfo,
containing_scope: DIScope,
- file_metadata: DIFile,
span: Span)
-> (DICompositeType, Type, MemberDescriptionFactory) {
let variant_llvm_type =
struct_def.packed);
// Could do some consistency checks here: size, align, field count, discr type
- // Find the source code location of the variant's definition
- let variant_definition_span = if variant_info.id.krate == ast::LOCAL_CRATE {
- cx.tcx.map.span(variant_info.id.node)
- } else {
- // For definitions from other crates we have no location information available.
- codemap::DUMMY_SP
- };
-
let variant_name = token::get_ident(variant_info.name);
let variant_name = variant_name.get();
let unique_type_id = debug_context(cx).type_map
variant_llvm_type,
variant_name,
unique_type_id,
- containing_scope,
- file_metadata,
- variant_definition_span);
+ containing_scope);
// Get the argument names from the enum variant info
let mut arg_names: Vec<_> = match variant_info.arg_names {
unique_type_id: UniqueTypeId,
span: Span)
-> RecursiveTypeDescription {
- let enum_name = ppaux::ty_to_str(cx.tcx(), enum_type);
+ let enum_name = compute_debuginfo_type_name(cx, enum_type, false);
let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, enum_def_id);
let loc = span_start(cx, definition_span);
DIB(cx),
containing_scope,
name,
- file_metadata,
- loc.line as c_uint,
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
bytes_to_bits(discriminant_size),
bytes_to_bits(discriminant_align),
create_DIArray(DIB(cx), enumerators_metadata.as_slice()),
DIB(cx),
containing_scope,
enum_name,
- file_metadata,
- loc.line as c_uint,
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
bytes_to_bits(enum_type_size),
bytes_to_bits(enum_type_align),
0, // Flags
unique_type_id,
enum_metadata,
enum_llvm_type,
- file_metadata,
EnumMDF(EnumMemberDescriptionFactory {
enum_type: enum_type,
type_rep: type_rep.clone(),
composite_type_unique_id: UniqueTypeId,
member_descriptions: &[MemberDescription],
containing_scope: DIScope,
- file_metadata: DIFile,
- definition_span: Span)
+
+ // Ignore source location information as long as it
+ // can't be reconstructed for non-local crates.
+ _file_metadata: DIFile,
+ _definition_span: Span)
-> DICompositeType {
// Create the (empty) struct metadata node ...
let composite_type_metadata = create_struct_stub(cx,
composite_llvm_type,
composite_type_name,
composite_type_unique_id,
- containing_scope,
- file_metadata,
- definition_span);
+ containing_scope);
// ... and immediately create and add the member descriptions.
set_members_of_composite_type(cx,
composite_type_metadata,
composite_llvm_type,
- member_descriptions,
- file_metadata,
- definition_span);
+ member_descriptions);
return composite_type_metadata;
}
fn set_members_of_composite_type(cx: &CrateContext,
composite_type_metadata: DICompositeType,
composite_llvm_type: Type,
- member_descriptions: &[MemberDescription],
- file_metadata: DIFile,
- definition_span: Span) {
+ member_descriptions: &[MemberDescription]) {
// In some rare cases LLVM metadata uniquing would lead to an existing type
// description being used instead of a new one created in create_struct_stub.
// This would cause a hard to trace assertion in DICompositeType::SetTypeArray().
}
}
- let loc = span_start(cx, definition_span);
-
let member_metadata: Vec<DIDescriptor> = member_descriptions
.iter()
.enumerate()
DIB(cx),
composite_type_metadata,
member_name,
- file_metadata,
- loc.line as c_uint,
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
bytes_to_bits(member_size),
bytes_to_bits(member_align),
bytes_to_bits(member_offset),
struct_llvm_type: Type,
struct_type_name: &str,
unique_type_id: UniqueTypeId,
- containing_scope: DIScope,
- file_metadata: DIFile,
- definition_span: Span)
+ containing_scope: DIScope)
-> DICompositeType {
- let loc = span_start(cx, definition_span);
let (struct_size, struct_align) = size_and_align_of(cx, struct_llvm_type);
let unique_type_id_str = debug_context(cx).type_map
DIB(cx),
containing_scope,
name,
- file_metadata,
- loc.line as c_uint,
+ UNKNOWN_FILE_METADATA,
+ UNKNOWN_LINE_NUMBER,
bytes_to_bits(struct_size),
bytes_to_bits(struct_align),
0,
-> MetadataCreationResult {
let content_type_metadata = type_metadata(cx, content_type, codemap::DUMMY_SP);
- match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
- Some(metadata) => return MetadataCreationResult::new(metadata, true),
- None => { /* proceed */ }
- };
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
- let content_type_name = ppaux::ty_to_str(cx.tcx(), content_type);
+ let content_type_name = compute_debuginfo_type_name(cx, content_type, true);
let content_type_name = content_type_name.as_slice();
let content_llvm_type = type_of::type_of(cx, content_type);
let nil_pointer_type_metadata = type_metadata(cx,
nil_pointer_type,
codemap::DUMMY_SP);
-
let member_descriptions = [
MemberDescription {
name: "refcnt".to_string(),
}
];
- let loc = span_start(cx, codemap::DUMMY_SP);
- let file_metadata = file_metadata(cx, loc.file.name.as_slice());
-
let gc_box_unique_id = debug_context(cx).type_map
.borrow_mut()
.get_unique_type_id_of_gc_box(cx, content_type);
box_type_name.as_slice(),
gc_box_unique_id,
member_descriptions,
- file_metadata,
- file_metadata,
+ UNKNOWN_SCOPE_METADATA,
+ UNKNOWN_FILE_METADATA,
codemap::DUMMY_SP);
let gc_pointer_metadata = pointer_type_metadata(cx,
-> MetadataCreationResult {
let element_type_metadata = type_metadata(cx, element_type, span);
- match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
- Some(metadata) => return MetadataCreationResult::new(metadata, true),
- None => { /* proceed */ }
- };
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
let element_llvm_type = type_of::type_of(cx, element_type);
let (element_type_size, element_type_align) = size_and_align_of(cx, element_llvm_type);
let element_llvm_type = type_of::type_of(cx, element_type);
let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
- match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
- Some(metadata) => return MetadataCreationResult::new(metadata, true),
- None => { /* proceed */ }
- };
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
let vecbox_llvm_type = Type::vec(cx, &element_llvm_type);
- let vec_pointer_type_name = ppaux::ty_to_str(cx.tcx(), vec_pointer_type);
+ let vec_pointer_type_name = compute_debuginfo_type_name(cx,
+ vec_pointer_type,
+ true);
let vec_pointer_type_name = vec_pointer_type_name.as_slice();
let member_llvm_types = vecbox_llvm_type.field_types();
vec_pointer_type_name,
vec_box_unique_id,
member_descriptions,
- file_metadata,
+ UNKNOWN_SCOPE_METADATA,
file_metadata,
span);
let element_type_metadata = type_metadata(cx, data_ptr_type, span);
- match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
- Some(metadata) => return MetadataCreationResult::new(metadata, true),
- None => { /* proceed */ }
- };
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
let slice_llvm_type = type_of::type_of(cx, vec_type);
- let slice_type_name = ppaux::ty_to_str(cx.tcx(), vec_type);
+ let slice_type_name = compute_debuginfo_type_name(cx, vec_type, true);
let member_llvm_types = slice_llvm_type.field_types();
assert!(slice_layout_is_correct(cx,
slice_type_name.as_slice(),
unique_type_id,
member_descriptions,
- file_metadata,
+ UNKNOWN_SCOPE_METADATA,
file_metadata,
span);
return MetadataCreationResult::new(metadata, false);
signature: &ty::FnSig,
span: Span)
-> MetadataCreationResult {
- let loc = span_start(cx, span);
- let file_metadata = file_metadata(cx, loc.file.name.as_slice());
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs.len() + 1);
// return type
signature_metadata.push(type_metadata(cx, argument_type, span));
}
- match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
- Some(metadata) => return MetadataCreationResult::new(metadata, true),
- None => { /* proceed */ }
- };
+ return_if_metadata_created_in_meantime!(cx, unique_type_id);
return MetadataCreationResult::new(
unsafe {
llvm::LLVMDIBuilderCreateSubroutineType(
DIB(cx),
- file_metadata,
+ UNKNOWN_FILE_METADATA,
create_DIArray(DIB(cx), signature_metadata.as_slice()))
},
false);
}
-fn trait_metadata(cx: &CrateContext,
- def_id: ast::DefId,
- trait_type: ty::t,
- substs: &subst::Substs,
- trait_store: ty::TraitStore,
- _: &ty::BuiltinBounds,
- unique_type_id: UniqueTypeId)
- -> DIType {
+fn trait_pointer_metadata(cx: &CrateContext,
+ // trait_pointer_type must be the type of the fat
+ // pointer to the concrete trait object
+ trait_pointer_type: ty::t,
+ unique_type_id: UniqueTypeId)
+ -> DIType {
// The implementation provided here is a stub. It makes sure that the trait
// type is assigned the correct name, size, namespace, and source location.
// But it does not describe the trait's methods.
- let last = ty::with_path(cx.tcx(), def_id, |mut path| path.last().unwrap());
- let ident_string = token::get_name(last.name());
- let mut name = ppaux::trait_store_to_str(cx.tcx(), trait_store);
- name.push_str(ident_string.get());
- // Add type and region parameters
- let trait_def = ty::lookup_trait_def(cx.tcx(), def_id);
- let name = ppaux::parameterized(cx.tcx(), name.as_slice(),
- substs, &trait_def.generics);
+ let trait_object_type = match ty::get(trait_pointer_type).sty {
+ ty::ty_uniq(pointee_type) => pointee_type,
+ ty::ty_rptr(_, ty::mt { ty, .. }) => ty,
+ _ => {
+ let pp_type_name = ppaux::ty_to_str(cx.tcx(), trait_pointer_type);
+ cx.sess().bug(format!("debuginfo: Unexpected trait-pointer type in \
+ trait_pointer_metadata(): {}",
+ pp_type_name.as_slice()).as_slice());
+ }
+ };
+
+ let def_id = match ty::get(trait_object_type).sty {
+ ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id,
+ _ => {
+ let pp_type_name = ppaux::ty_to_str(cx.tcx(), trait_object_type);
+ cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \
+ trait_pointer_metadata(): {}",
+ pp_type_name.as_slice()).as_slice());
+ }
+ };
- let (containing_scope, definition_span) = get_namespace_and_span_for_item(cx, def_id);
+ let trait_pointer_type_name =
+ compute_debuginfo_type_name(cx, trait_pointer_type, false);
- let file_name = span_start(cx, definition_span).file.name.clone();
- let file_metadata = file_metadata(cx, file_name.as_slice());
+ let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
- let trait_llvm_type = type_of::type_of(cx, trait_type);
+ let trait_pointer_llvm_type = type_of::type_of(cx, trait_pointer_type);
composite_type_metadata(cx,
- trait_llvm_type,
- name.as_slice(),
+ trait_pointer_llvm_type,
+ trait_pointer_type_name.as_slice(),
unique_type_id,
[],
containing_scope,
- file_metadata,
- definition_span)
+ UNKNOWN_FILE_METADATA,
+ codemap::DUMMY_SP)
}
fn type_metadata(cx: &CrateContext,
debug!("type_metadata: {:?}", ty::get(t));
- macro_rules! return_if_created_in_meantime(
- () => (
- match debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id) {
- Some(metadata) => return metadata,
- None => { /* proceed normally */ }
- };
- )
- )
-
let sty = &ty::get(t).sty;
let MetadataCreationResult { metadata, already_stored_in_typemap } = match *sty {
ty::ty_nil |
let i8_t = ty::mk_i8();
heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span)
}
- ty::ty_trait(box ty::TyTrait {
- def_id,
- ref substs,
- ref bounds
- }) => {
+ ty::ty_trait(..) => {
MetadataCreationResult::new(
- trait_metadata(cx, def_id, t, substs, ty::UniqTraitStore,
- bounds, unique_type_id),
- false)
+ trait_pointer_metadata(cx, t, unique_type_id),
+ false)
}
_ => {
- let pointee_metadata = type_metadata(cx, pointee_type, usage_site_span);
- return_if_created_in_meantime!();
+ let pointee_metadata = type_metadata(cx,
+ pointee_type,
+ usage_site_span);
+ match debug_context(cx).type_map
+ .borrow()
+ .find_metadata_for_unique_id(unique_type_id) {
+ Some(metadata) => return metadata,
+ None => { /* proceed normally */ }
+ };
+
MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata),
false)
}
vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
}
ty::ty_str => {
- vec_slice_metadata(cx, t, ty::mk_i8(), unique_type_id, usage_site_span)
+ vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span)
}
- ty::ty_trait(box ty::TyTrait {
- def_id,
- ref substs,
- ref bounds
- }) => {
+ ty::ty_trait(..) => {
MetadataCreationResult::new(
- trait_metadata(cx, def_id, t, substs,
- ty::RegionTraitStore(ty::ReStatic, mt.mutbl),
- bounds, unique_type_id),
- false)
+ trait_pointer_metadata(cx, t, unique_type_id),
+ false)
}
_ => {
let pointee = type_metadata(cx, mt.ty, usage_site_span);
- return_if_created_in_meantime!();
+
+ match debug_context(cx).type_map
+ .borrow()
+ .find_metadata_for_unique_id(unique_type_id) {
+ Some(metadata) => return metadata,
+ None => { /* proceed normally */ }
+ };
+
MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee), false)
}
}
match debug_location {
KnownLocation { scope, line, .. } => {
- let col = 0u; // Always set the column to zero like Clang and GCC
+ // Always set the column to zero like Clang and GCC
+ let col = UNKNOWN_COLUMN_NUMBER;
debug!("setting debug location to {} {}", line, col);
let elements = [C_i32(cx, line as i32), C_i32(cx, col as i32),
scope, ptr::mut_null()];
// Push argument identifiers onto the stack so arguments integrate nicely
// with variable shadowing.
for &arg_pat in arg_pats.iter() {
- pat_util::pat_bindings(def_map, &*arg_pat, |_, _, _, path_ref| {
- let ident = ast_util::path_to_ident(path_ref);
+ pat_util::pat_bindings(def_map, &*arg_pat, |_, _, _, path1| {
scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
- ident: Some(ident) });
+ ident: Some(path1.node) });
})
}
// ast_util::walk_pat() here because we have to visit *all* nodes in
// order to put them into the scope map. The above functions don't do that.
match pat.node {
- ast::PatIdent(_, ref path_ref, ref sub_pat_opt) => {
+ ast::PatIdent(_, ref path1, ref sub_pat_opt) => {
// Check if this is a binding. If so we need to put it on the
// scope stack and maybe introduce an artificial scope
if pat_util::pat_is_binding(def_map, &*pat) {
- let ident = ast_util::path_to_ident(path_ref);
+ let ident = path1.node;
// LLVM does not properly generate 'DW_AT_start_scope' fields
// for variable DIEs. For this reason we have to introduce
}
+//=-----------------------------------------------------------------------------
+// Type Names for Debug Info
+//=-----------------------------------------------------------------------------
+
+// Compute the name of the type as it should be stored in debuginfo. Does not do
+// any caching, i.e. calling the function twice with the same type will also do
+// the work twice. The `qualified` parameter only affects the first level of the
+// type name, further levels (i.e. type parameters) are always fully qualified.
+fn compute_debuginfo_type_name(cx: &CrateContext,
+ t: ty::t,
+ qualified: bool)
+ -> String {
+ let mut result = String::with_capacity(64);
+ push_debuginfo_type_name(cx, t, qualified, &mut result);
+ result
+}
+
+// Pushes the name of the type as it should be stored in debuginfo on the
+// `output` String. See also compute_debuginfo_type_name().
+fn push_debuginfo_type_name(cx: &CrateContext,
+ t: ty::t,
+ qualified: bool,
+ output:&mut String) {
+ match ty::get(t).sty {
+ ty::ty_nil => output.push_str("()"),
+ ty::ty_bot => output.push_str("!"),
+ ty::ty_bool => output.push_str("bool"),
+ ty::ty_char => output.push_str("char"),
+ ty::ty_str => output.push_str("str"),
+ ty::ty_int(ast::TyI) => output.push_str("int"),
+ ty::ty_int(ast::TyI8) => output.push_str("i8"),
+ ty::ty_int(ast::TyI16) => output.push_str("i16"),
+ ty::ty_int(ast::TyI32) => output.push_str("i32"),
+ ty::ty_int(ast::TyI64) => output.push_str("i64"),
+ ty::ty_uint(ast::TyU) => output.push_str("uint"),
+ ty::ty_uint(ast::TyU8) => output.push_str("u8"),
+ ty::ty_uint(ast::TyU16) => output.push_str("u16"),
+ ty::ty_uint(ast::TyU32) => output.push_str("u32"),
+ ty::ty_uint(ast::TyU64) => output.push_str("u64"),
+ ty::ty_float(ast::TyF32) => output.push_str("f32"),
+ ty::ty_float(ast::TyF64) => output.push_str("f64"),
+ ty::ty_struct(def_id, ref substs) |
+ ty::ty_enum(def_id, ref substs) => {
+ push_item_name(cx, def_id, qualified, output);
+ push_type_params(cx, substs, output);
+ },
+ ty::ty_tup(ref component_types) => {
+ output.push_char('(');
+ for &component_type in component_types.iter() {
+ push_debuginfo_type_name(cx, component_type, true, output);
+ output.push_str(", ");
+ }
+ output.pop_char();
+ output.pop_char();
+ output.push_char(')');
+ },
+ ty::ty_uniq(inner_type) => {
+ output.push_str("Box<");
+ push_debuginfo_type_name(cx, inner_type, true, output);
+ output.push_char('>');
+ },
+ ty::ty_box(inner_type) => {
+ output.push_char('@');
+ push_debuginfo_type_name(cx, inner_type, true, output);
+ },
+ ty::ty_ptr(ty::mt { ty: inner_type, mutbl } ) => {
+ output.push_char('*');
+ match mutbl {
+ ast::MutImmutable => output.push_str("const "),
+ ast::MutMutable => output.push_str("mut "),
+ }
+
+ push_debuginfo_type_name(cx, inner_type, true, output);
+ },
+ ty::ty_rptr(_, ty::mt { ty: inner_type, mutbl }) => {
+ output.push_char('&');
+ if mutbl == ast::MutMutable {
+ output.push_str("mut ");
+ }
+
+ push_debuginfo_type_name(cx, inner_type, true, output);
+ },
+ ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => {
+ output.push_char('[');
+ push_debuginfo_type_name(cx, inner_type, true, output);
+
+ match optional_length {
+ Some(len) => {
+ output.push_str(format!(", ..{}", len).as_slice());
+ }
+ None => { /* nothing to do */ }
+ };
+
+ output.push_char(']');
+ },
+ ty::ty_trait(ref trait_data) => {
+ push_item_name(cx, trait_data.def_id, false, output);
+ push_type_params(cx, &trait_data.substs, output);
+ },
+ ty::ty_bare_fn(ty::BareFnTy{ fn_style, abi, ref sig } ) => {
+ if fn_style == ast::UnsafeFn {
+ output.push_str("unsafe ");
+ }
+
+ if abi != ::syntax::abi::Rust {
+ output.push_str("extern \"");
+ output.push_str(abi.name());
+ output.push_str("\" ");
+ }
+
+ output.push_str("fn(");
+
+ if sig.inputs.len() > 0 {
+ for ¶meter_type in sig.inputs.iter() {
+ push_debuginfo_type_name(cx, parameter_type, true, output);
+ output.push_str(", ");
+ }
+ output.pop_char();
+ output.pop_char();
+ }
+
+ if sig.variadic {
+ if sig.inputs.len() > 0 {
+ output.push_str(", ...");
+ } else {
+ output.push_str("...");
+ }
+ }
+
+ output.push_char(')');
+
+ if !ty::type_is_nil(sig.output) {
+ output.push_str(" -> ");
+ push_debuginfo_type_name(cx, sig.output, true, output);
+ }
+ },
+ ty::ty_closure(box ty::ClosureTy { fn_style,
+ onceness,
+ store,
+ ref sig,
+ .. // omitting bounds ...
+ }) => {
+ if fn_style == ast::UnsafeFn {
+ output.push_str("unsafe ");
+ }
+
+ if onceness == ast::Once {
+ output.push_str("once ");
+ }
+
+ let param_list_closing_char;
+ match store {
+ ty::UniqTraitStore => {
+ output.push_str("proc(");
+ param_list_closing_char = ')';
+ }
+ ty::RegionTraitStore(_, ast::MutMutable) => {
+ output.push_str("&mut|");
+ param_list_closing_char = '|';
+ }
+ ty::RegionTraitStore(_, ast::MutImmutable) => {
+ output.push_str("&|");
+ param_list_closing_char = '|';
+ }
+ };
+
+ if sig.inputs.len() > 0 {
+ for ¶meter_type in sig.inputs.iter() {
+ push_debuginfo_type_name(cx, parameter_type, true, output);
+ output.push_str(", ");
+ }
+ output.pop_char();
+ output.pop_char();
+ }
+
+ if sig.variadic {
+ if sig.inputs.len() > 0 {
+ output.push_str(", ...");
+ } else {
+ output.push_str("...");
+ }
+ }
+
+ output.push_char(param_list_closing_char);
+
+ if !ty::type_is_nil(sig.output) {
+ output.push_str(" -> ");
+ push_debuginfo_type_name(cx, sig.output, true, output);
+ }
+ },
+ ty::ty_err |
+ ty::ty_infer(_) |
+ ty::ty_param(_) => {
+ cx.sess().bug(format!("debuginfo: Trying to create type name for \
+ unexpected type: {}", ppaux::ty_to_str(cx.tcx(), t)).as_slice());
+ }
+ }
+
+ fn push_item_name(cx: &CrateContext,
+ def_id: ast::DefId,
+ qualified: bool,
+ output: &mut String) {
+ ty::with_path(cx.tcx(), def_id, |mut path| {
+ if qualified {
+ if def_id.krate == ast::LOCAL_CRATE {
+ output.push_str(crate_root_namespace(cx));
+ output.push_str("::");
+ }
+
+ let mut path_element_count = 0u;
+ for path_element in path {
+ let name = token::get_name(path_element.name());
+ output.push_str(name.get());
+ output.push_str("::");
+ path_element_count += 1;
+ }
+
+ if path_element_count == 0 {
+ cx.sess().bug("debuginfo: Encountered empty item path!");
+ }
+
+ output.pop_char();
+ output.pop_char();
+ } else {
+ let name = token::get_name(path.last()
+ .expect("debuginfo: Empty item path?")
+ .name());
+ output.push_str(name.get());
+ }
+ });
+ }
+
+ // Pushes the type parameters in the given `Substs` to the output string.
+ // This ignores region parameters, since they can't reliably be
+ // reconstructed for items from non-local crates. For local crates, this
+ // would be possible but with inlining and LTO we have to use the least
+ // common denominator - otherwise we would run into conflicts.
+ fn push_type_params(cx: &CrateContext,
+ substs: &subst::Substs,
+ output: &mut String) {
+ if substs.types.is_empty() {
+ return;
+ }
+
+ output.push_char('<');
+
+ for &type_parameter in substs.types.iter() {
+ push_debuginfo_type_name(cx, type_parameter, true, output);
+ output.push_str(", ");
+ }
+
+ output.pop_char();
+ output.pop_char();
+
+ output.push_char('>');
+ }
+}
+
+
//=-----------------------------------------------------------------------------
// Namespace Handling
//=-----------------------------------------------------------------------------
}
}
+fn crate_root_namespace<'a>(cx: &'a CrateContext) -> &'a str {
+ cx.link_meta.crateid.name.as_slice()
+}
+
fn namespace_for_item(cx: &CrateContext, def_id: ast::DefId) -> Rc<NamespaceTreeNode> {
ty::with_path(cx.tcx(), def_id, |path| {
// prepend crate name if not already present
let krate = if def_id.krate == ast::LOCAL_CRATE {
- let crate_namespace_ident = token::str_to_ident(cx.link_meta
- .crateid
- .name
- .as_slice());
+ let crate_namespace_ident = token::str_to_ident(crate_root_namespace(cx));
Some(ast_map::PathMod(crate_namespace_ident.name))
} else {
None
match cx.map.find(id) {
Some(ast_map::NodeLocal(pat)) => {
match pat.node {
- ast::PatIdent(_, ref path, _) => {
- token::get_ident(ast_util::path_to_ident(path))
+ ast::PatIdent(_, ref path1, _) => {
+ token::get_ident(path1.node)
}
_ => {
cx.sess.bug(
demand::suptype(fcx, pat.span, expected, const_pty.ty);
fcx.write_ty(pat.id, const_pty.ty);
}
- ast::PatIdent(bm, ref name, sub) if pat_is_binding(&tcx.def_map, pat) => {
+ ast::PatIdent(bm, ref path1, sub) if pat_is_binding(&tcx.def_map, pat) => {
let typ = fcx.local_ty(pat.span, pat.id);
match bm {
}
}
- let canon_id = *pcx.map.get(&ast_util::path_to_ident(name));
+ let canon_id = *pcx.map.get(&path1.node);
if canon_id != pat.id {
let ct = fcx.local_ty(pat.span, canon_id);
demand::eqtype(fcx, pat.span, ct, typ);
_ => ()
}
}
- ast::PatIdent(_, ref path, _) => {
- check_pat_variant(pcx, pat, path, &Some(Vec::new()), expected);
+ // it's not a binding, it's an enum in disguise:
+ ast::PatIdent(_, ref path1, _) => {
+ let path = ast_util::ident_to_path(path1.span,path1.node);
+ check_pat_variant(pcx, pat, &path, &Some(Vec::new()), expected);
}
ast::PatEnum(ref path, ref subpats) => {
check_pat_variant(pcx, pat, path, subpats, expected);
// Add pattern bindings.
fn visit_pat(&mut self, p: &ast::Pat, _: ()) {
match p.node {
- ast::PatIdent(_, ref path, _)
+ ast::PatIdent(_, ref path1, _)
if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) => {
self.assign(p.id, None);
debug!("Pattern binding {} is assigned to {}",
- token::get_ident(path.segments.get(0).identifier),
+ token::get_ident(path1.node),
self.fcx.infcx().ty_to_str(
self.fcx.inh.locals.borrow().get_copy(&p.id)));
}
let it = trait_m.generics.types.get_vec(subst::FnSpace).iter()
.zip(impl_m.generics.types.get_vec(subst::FnSpace).iter());
- for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
- // Check that the impl does not require any builtin-bounds
- // that the trait does not guarantee:
- let extra_bounds =
- impl_param_def.bounds.builtin_bounds -
- trait_param_def.bounds.builtin_bounds;
- if !extra_bounds.is_empty() {
- tcx.sess.span_err(
- impl_m_span,
- format!("in method `{}`, \
- type parameter {} requires `{}`, \
- which is not required by \
- the corresponding type parameter \
- in the trait declaration",
- token::get_ident(trait_m.ident),
- i,
- extra_bounds.user_string(tcx)).as_slice());
- return;
- }
-
- // 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.
- if impl_param_def.bounds.trait_bounds.len() !=
- trait_param_def.bounds.trait_bounds.len()
- {
- let found = impl_param_def.bounds.trait_bounds.len();
- let expected = trait_param_def.bounds.trait_bounds.len();
- tcx.sess.span_err(
- impl_m_span,
- format!("in method `{}`, type parameter {} has {} trait \
- bound{}, but the corresponding type parameter in \
- the trait declaration has {} trait bound{}",
- token::get_ident(trait_m.ident),
- i,
- found,
- if found == 1 {""} else {"s"},
- expected,
- if expected == 1 {""} else {"s"}).as_slice());
- return;
- }
- }
-
// This code is best explained by example. Consider a trait:
//
// trait Trait<T> {
let trait_fty = ty::mk_bare_fn(tcx, trait_m.fty.clone());
let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs);
+ // Check bounds.
+ for (i, (trait_param_def, impl_param_def)) in it.enumerate() {
+ // Check that the impl does not require any builtin-bounds
+ // that the trait does not guarantee:
+ let extra_bounds =
+ impl_param_def.bounds.builtin_bounds -
+ trait_param_def.bounds.builtin_bounds;
+ if !extra_bounds.is_empty() {
+ tcx.sess.span_err(
+ impl_m_span,
+ format!("in method `{}`, \
+ type parameter {} requires `{}`, \
+ which is not required by \
+ the corresponding type parameter \
+ in the trait declaration",
+ token::get_ident(trait_m.ident),
+ i,
+ extra_bounds.user_string(tcx)).as_slice());
+ return;
+ }
+
+ // Check that the trait bounds of the trait imply the bounds of its
+ // implementation.
+ //
+ // FIXME(pcwalton): We could be laxer here regarding sub- and super-
+ // traits, but I doubt that'll be wanted often, so meh.
+ for impl_trait_bound in impl_param_def.bounds.trait_bounds.iter() {
+ let impl_trait_bound =
+ impl_trait_bound.subst(tcx, &impl_to_skol_substs);
+
+ let mut ok = false;
+ for trait_bound in trait_param_def.bounds.trait_bounds.iter() {
+ let trait_bound =
+ trait_bound.subst(tcx, &trait_to_skol_substs);
+ let infcx = infer::new_infer_ctxt(tcx);
+ match infer::mk_sub_trait_refs(&infcx,
+ true,
+ infer::Misc(impl_m_span),
+ trait_bound,
+ impl_trait_bound.clone()) {
+ Ok(_) => {
+ ok = true;
+ break
+ }
+ Err(_) => continue,
+ }
+ }
+
+ if !ok {
+ tcx.sess.span_err(impl_m_span,
+ format!("in method `{}`, type parameter {} \
+ requires bound `{}`, which is not \
+ required by the corresponding \
+ type parameter in the trait \
+ declaration",
+ token::get_ident(trait_m.ident),
+ i,
+ ppaux::trait_ref_to_str(
+ tcx,
+ &*impl_trait_bound)).as_slice())
+ }
+ }
+ }
+
// Check the impl method type IM is a subtype of the trait method
// type TM. To see why this makes sense, think of a vtable. The
// expected type of the function pointers in the vtable is the
// Resolve any sub bounds. Note that there still may be free
// type variables in substs. This might still be OK: the
// process of looking up bounds might constrain some of them.
+ //
+ // This does not check built-in traits because those are handled
+ // later in the kind checking pass.
let im_generics =
ty::lookup_item_type(tcx, impl_did).generics;
let subres = lookup_vtables(vcx,
}
}
- (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if a_p.idx == b_p.idx => {
+ (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if
+ a_p.idx == b_p.idx && a_p.space == b_p.space => {
Ok(a)
}
/**
* At any time, users may snapshot a unification table. The changes
- * made during the snapshot may either be *commited* or *rolled back*.
+ * made during the snapshot may either be *committed* or *rolled back*.
*/
pub struct Snapshot<K> {
// Ensure that this snapshot is keyed to the table type.
/**
* Starts a new snapshot. Each snapshot must be either
- * rolled back or commited in a "LIFO" (stack) order.
+ * rolled back or committed in a "LIFO" (stack) order.
*/
pub fn snapshot(&mut self) -> Snapshot<K> {
let length = self.undo_log.len();
match self.undo_log.pop().unwrap() {
OpenSnapshot => {
// This indicates a failure to obey the stack discipline.
- tcx.sess.bug("Cannot rollback an uncommited snapshot");
+ tcx.sess.bug("Cannot rollback an uncommitted snapshot");
}
CommittedSnapshot => {
// This occurs when there are nested snapshots and
- // the inner is commited but outer is rolled back.
+ // the inner is committed but outer is rolled back.
}
NewVar(i) => {
#[deriving(Clone)]
pub enum vtable_origin {
/*
- Statically known vtable. def_id gives the class or impl item
+ Statically known vtable. def_id gives the impl item
from whence comes the vtable, and tys are the type substs.
- vtable_res is the vtable itself
+ vtable_res is the vtable itself.
*/
vtable_static(ast::DefId, subst::Substs, vtable_res),
F32, F64,
Char,
Bool,
- Nil,
+ Unit,
Str,
Slice,
PrimitiveTuple,
"u32" => Some(U32),
"u64" => Some(U64),
"bool" => Some(Bool),
- "nil" => Some(Nil),
+ "unit" => Some(Unit),
"char" => Some(Char),
"str" => Some(Str),
"f32" => Some(F32),
Str => "str",
Bool => "bool",
Char => "char",
- Nil => "()",
+ Unit => "()",
Slice => "slice",
PrimitiveTuple => "tuple",
}
pub fn to_url_str(&self) -> &'static str {
match *self {
- Nil => "nil",
+ Unit => "unit",
other => other.to_str(),
}
}
fn clean(&self) -> Type {
use syntax::ast::*;
match self.node {
- TyNil => Primitive(Nil),
+ TyNil => Primitive(Unit),
TyPtr(ref m) => RawPointer(m.mutbl.clean(), box m.ty.clean()),
TyRptr(ref l, ref m) =>
BorrowedRef {lifetime: l.clean(), mutability: m.mutbl.clean(),
fn clean(&self) -> Type {
match ty::get(*self).sty {
ty::ty_bot => Bottom,
- ty::ty_nil => Primitive(Nil),
+ ty::ty_nil => Primitive(Unit),
ty::ty_bool => Primitive(Bool),
ty::ty_char => Primitive(Char),
ty::ty_int(ast::TyI) => Primitive(Int),
}
fn path_to_str(p: &ast::Path) -> String {
- use syntax::parse::token;
-
let mut s = String::new();
let mut first = true;
for i in p.segments.iter().map(|x| token::get_ident(x.identifier)) {
impl Clean<Vec<Item>> for ast::ViewItem {
fn clean(&self) -> Vec<Item> {
- // We consider inlining the documentation of `pub use` statments, but we
+ // We consider inlining the documentation of `pub use` statements, but we
// forcefully don't inline if this is not public or if the
// #[doc(no_inline)] attribute is present.
let denied = self.vis != ast::Public || self.attrs.iter().any(|a| {
match p.node {
PatWild => "_".to_string(),
PatWildMulti => "..".to_string(),
- PatIdent(_, ref p, _) => path_to_str(p),
+ PatIdent(_, ref p, _) => token::get_ident(p.node).get().to_string(),
PatEnum(ref p, _) => path_to_str(p),
PatStruct(..) => fail!("tried to get argument name from pat_struct, \
which is not allowed in function arguments"),
},
args = decl.decl.inputs,
arrow = match decl.decl.output {
- clean::Primitive(clean::Nil) => "".to_string(),
+ clean::Primitive(clean::Unit) => "".to_string(),
_ => format!(" -> {}", decl.decl.output),
},
bounds = {
m.collect::<Vec<String>>().connect(" + "))
},
arrow = match decl.decl.output {
- clean::Primitive(clean::Nil) => "".to_string(),
+ clean::Primitive(clean::Unit) => "".to_string(),
_ => format!(" -> {}", decl.decl.output)
})
}
write!(f, "({args}){arrow}",
args = self.inputs,
arrow = match self.output {
- clean::Primitive(clean::Nil) => "".to_string(),
+ clean::Primitive(clean::Unit) => "".to_string(),
_ => format!(" -> {}", self.output),
})
}
write!(f, "({args}){arrow}",
args = args,
arrow = match d.output {
- clean::Primitive(clean::Nil) => "".to_string(),
+ clean::Primitive(clean::Unit) => "".to_string(),
_ => format!(" -> {}", d.output),
})
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![crate_id = "rustdoc#0.11.0-pre"]
+#![crate_id = "rustdoc#0.11.0"]
#![experimental]
#![desc = "rustdoc, the Rust documentation extractor"]
#![license = "MIT/ASL2"]
// (without forcing an additional & around &str). So we are instead
// temporarily adding an instance for ~str and String, so that we can
// take ToCStr as owned. When DST lands, the string instances should
-// be revisted, and arguments bound by ToCStr should be passed by
+// be revisited, and arguments bound by ToCStr should be passed by
// reference.
impl<'a> ToCStr for &'a str {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![crate_id = "rustrt#0.11.0-pre"]
+#![crate_id = "rustrt#0.11.0"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(macro_rules, phase, globs, thread_local, managed_boxes, asm)]
#![feature(linkage, lang_items, unsafe_destructor)]
extern "C" {
// iOS on armv7 uses SjLj exceptions and requires to link
- // agains corresponding routine (..._SjLj_...)
+ // against corresponding routine (..._SjLj_...)
#[cfg(not(target_os = "ios", target_arch = "arm"))]
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception)
-> _Unwind_Reason_Code;
/// This function can be used as an emulated "try/catch" to interoperate
/// with the rust runtime at the outermost boundary. It is not possible to
/// use this function in a nested fashion (a try/catch inside of another
- /// try/catch). Invoking this funciton is quite cheap.
+ /// try/catch). Invoking this function is quite cheap.
///
/// If the closure `f` succeeds, then the returned task can be used again
/// for another invocation of `run`. If the closure `f` fails then `self`
// 1. If TLD destruction fails, heap destruction will be attempted.
// There is a test for this at fail-during-tld-destroy.rs. Sadly the
// other way can't be tested due to point 2 above. Note that we must
- // immortalize the heap first becuase if any deallocations are
+ // immortalize the heap first because if any deallocations are
// attempted while TLD is being dropped it will attempt to free the
// allocation from the wrong heap (because the current one has been
// replaced).
// EINVAL means |stack_size| is either too small or not a
// multiple of the system page size. Because it's definitely
// >= PTHREAD_STACK_MIN, it must be an alignment issue.
- // Round up to the neareast page and try again.
+ // Round up to the nearest page and try again.
let page_size = libc::sysconf(libc::_SC_PAGESIZE) as uint;
let stack_size = (stack_size + page_size - 1) &
(-(page_size as int - 1) as uint - 1);
*/
-#![crate_id = "rustuv#0.11.0-pre"]
+#![crate_id = "rustuv#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
+#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "http://www.rust-lang.org/favicon.ico",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
+ html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, unsafe_destructor)]
#![deny(unused_result, unused_must_use)]
impl Drop for ForbidUnwind {
fn drop(&mut self) {
assert!(self.failing_before == task::failing(),
- "didnt want an unwind during: {}", self.msg);
+ "didn't want an unwind during: {}", self.msg);
}
}
// immediately as part of the call to alloc_cb. What this means is that
// we must be ready for this to happen (by setting the data in the uv
// handle). In theory this otherwise doesn't need to happen until after
- // the read is succesfully started.
+ // the read is successfully started.
unsafe { uvll::set_data_for_uv_handle(self.handle, &mut rcx) }
// Send off the read request, but don't block until we're sure that the
fn sleep(&mut self, msecs: u64) {
// As with all of the below functions, we must be extra careful when
// destroying the previous action. If the previous action was a channel,
- // destroying it could invoke a context switch. For these situtations,
+ // destroying it could invoke a context switch. For these situations,
// we must temporarily un-home ourselves, then destroy the action, and
// then re-home again.
let missile = self.fire_homing_missile();
//! An example version number with all five components is
//! `0.8.1-rc.3.0+20130922.linux`.
-#![crate_id = "semver#0.11.0-pre"]
+#![crate_id = "semver#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
use std::char;
use std::cmp;
Core encoding and decoding interfaces.
*/
-#![crate_id = "serialize#0.11.0-pre"]
+#![crate_id = "serialize#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, managed_boxes, default_type_params, phase)]
// colon after v4
let none: Option<IpAddr> = FromStr::from_str("::127.0.0.1:");
assert_eq!(None, none);
- // not enought groups
+ // not enough groups
let none: Option<IpAddr> = FromStr::from_str("1.2.3.4.5:127.0.0.1");
assert_eq!(None, none);
// too many groups
/// Sets the broadcast flag on or off
#[experimental]
- pub fn set_broadast(&mut self, broadcast: bool) -> IoResult<()> {
+ pub fn set_broadcast(&mut self, broadcast: bool) -> IoResult<()> {
if broadcast {
self.obj.hear_broadcasts()
} else {
}.map_err(IoError::from_rtio_error)
}
+ /// Sets the broadcast flag on or off
+ #[deprecated="renamed to `set_broadcast`"]
+ pub fn set_broadast(&mut self, broadcast: bool) -> IoResult<()> {
+ self.set_broadcast(broadcast)
+ }
+
/// Sets the read/write timeout for this socket.
///
/// For more information, see `TcpStream::set_timeout`
//! all the standard macros, such as `assert!`, `fail!`, `println!`,
//! and `format!`, also available to all Rust code.
-#![crate_id = "std#0.11.0-pre"]
+#![crate_id = "std#0.11.0"]
#![unstable]
#![comment = "The Rust standard library"]
#![license = "MIT/ASL2"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, globs, managed_boxes, linkage)]
pub use core::raw;
pub use core::simd;
pub use core::tuple;
+// FIXME #15320: primitive documentation needs top-level modules, this
+// should be `std::tuple::unit`.
+pub use core::unit;
#[cfg(not(test))] pub use core::ty;
pub use core::result;
pub use core::option;
use ptr::RawPtr;
use ptr;
use result::{Err, Ok, Result};
-use slice::{Vector, ImmutableVector, MutableVector};
+use slice::{Vector, ImmutableVector, MutableVector, ImmutableEqVector};
use str::{Str, StrSlice, StrAllocating};
use str;
use string::String;
/// None => println!("{} is not defined in the environment.", key)
/// }
/// ```
-pub fn setenv(n: &str, v: &str) {
+pub fn setenv<T: BytesContainer>(n: &str, v: T) {
#[cfg(unix)]
- fn _setenv(n: &str, v: &str) {
+ fn _setenv(n: &str, v: &[u8]) {
unsafe {
with_env_lock(|| {
n.with_c_str(|nbuf| {
}
#[cfg(windows)]
- fn _setenv(n: &str, v: &str) {
+ fn _setenv(n: &str, v: &[u8]) {
let n: Vec<u16> = n.utf16_units().collect();
let n = n.append_one(0);
- let v: Vec<u16> = v.utf16_units().collect();
+ let v: Vec<u16> = str::from_utf8(v).unwrap().utf16_units().collect();
let v = v.append_one(0);
+
unsafe {
with_env_lock(|| {
libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr());
})
}
}
- _setenv(n, v)
+
+ _setenv(n, v.container_as_bytes())
}
/// Remove a variable from the environment entirely.
_unsetenv(n);
}
-#[cfg(unix)]
-/// Parse a string or vector according to the platform's conventions
-/// for the `PATH` environment variable and return a Vec<Path>.
-/// Drops empty paths.
+/// Parses input according to platform conventions for the `PATH`
+/// environment variable.
///
/// # Example
/// ```rust
/// use std::os;
///
/// let key = "PATH";
-/// match os::getenv(key) {
+/// match os::getenv_as_bytes(key) {
/// Some(paths) => {
/// for path in os::split_paths(paths).iter() {
/// println!("'{}'", path.display());
/// }
/// }
-/// None => println!("{} is not defined in the environnement.", key)
+/// None => println!("{} is not defined in the environment.", key)
/// }
/// ```
pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
- unparsed.container_as_bytes()
- .split(|b| *b == ':' as u8)
- .filter(|s| s.len() > 0)
- .map(Path::new)
- .collect()
-}
+ #[cfg(unix)]
+ fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
+ unparsed.container_as_bytes()
+ .split(|b| *b == b':')
+ .map(Path::new)
+ .collect()
+ }
-#[cfg(windows)]
-/// Parse a string or vector according to the platform's conventions
-/// for the `PATH` environment variable. Drops empty paths.
-pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
- // On Windows, the PATH environment variable is semicolon separated. Double
- // quotes are used as a way of introducing literal semicolons (since
- // c:\some;dir is a valid Windows path). Double quotes are not themselves
- // permitted in path names, so there is no way to escape a double quote.
- // Quoted regions can appear in arbitrary locations, so
- //
- // c:\foo;c:\som"e;di"r;c:\bar
- //
- // Should parse as [c:\foo, c:\some;dir, c:\bar].
- //
- // (The above is based on testing; there is no clear reference available
- // for the grammar.)
-
- let mut parsed = Vec::new();
- let mut in_progress = Vec::new();
- let mut in_quote = false;
-
- for b in unparsed.container_as_bytes().iter() {
- match *b as char {
- ';' if !in_quote => {
- // ignore zero-length path strings
- if in_progress.len() > 0 {
+ #[cfg(windows)]
+ fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
+ // On Windows, the PATH environment variable is semicolon separated. Double
+ // quotes are used as a way of introducing literal semicolons (since
+ // c:\some;dir is a valid Windows path). Double quotes are not themselves
+ // permitted in path names, so there is no way to escape a double quote.
+ // Quoted regions can appear in arbitrary locations, so
+ //
+ // c:\foo;c:\som"e;di"r;c:\bar
+ //
+ // Should parse as [c:\foo, c:\some;dir, c:\bar].
+ //
+ // (The above is based on testing; there is no clear reference available
+ // for the grammar.)
+
+ let mut parsed = Vec::new();
+ let mut in_progress = Vec::new();
+ let mut in_quote = false;
+
+ for b in unparsed.container_as_bytes().iter() {
+ match *b {
+ b';' if !in_quote => {
parsed.push(Path::new(in_progress.as_slice()));
+ in_progress.truncate(0)
+ }
+ b'"' => {
+ in_quote = !in_quote;
+ }
+ _ => {
+ in_progress.push(*b);
}
- in_progress.truncate(0)
- }
- '\"' => {
- in_quote = !in_quote;
}
- _ => {
- in_progress.push(*b);
+ }
+ parsed.push(Path::new(in_progress));
+ parsed
+ }
+
+ _split_paths(unparsed)
+}
+
+/// Joins a collection of `Path`s appropriately for the `PATH`
+/// environment variable.
+///
+/// Returns a `Vec<u8>` on success, since `Path`s are not utf-8
+/// encoded on all platforms.
+///
+/// Returns an `Err` (containing an error message) if one of the input
+/// `Path`s contains an invalid character for constructing the `PATH`
+/// variable (a double quote on Windows or a colon on Unix).
+///
+/// # Example
+///
+/// ```rust
+/// use std::os;
+/// use std::path::Path;
+///
+/// let key = "PATH";
+/// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
+/// paths.push(Path::new("/home/xyz/bin"));
+/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
+/// ```
+pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+ #[cfg(windows)]
+ fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+ let mut joined = Vec::new();
+ let sep = b';';
+
+ for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+ if i > 0 { joined.push(sep) }
+ if path.contains(&b'"') {
+ return Err("path segment contains `\"`");
+ } else if path.contains(&sep) {
+ joined.push(b'"');
+ joined.push_all(path);
+ joined.push(b'"');
+ } else {
+ joined.push_all(path);
}
}
+
+ Ok(joined)
}
- if in_progress.len() > 0 {
- parsed.push(Path::new(in_progress));
+ #[cfg(unix)]
+ fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
+ let mut joined = Vec::new();
+ let sep = b':';
+
+ for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
+ if i > 0 { joined.push(sep) }
+ if path.contains(&sep) { return Err("path segment contains separator `:`") }
+ joined.push_all(path);
+ }
+
+ Ok(joined)
}
- parsed
+ _join_paths(paths)
}
/// A low-level OS in-memory pipe.
use c_str::ToCStr;
use option;
use os::{env, getcwd, getenv, make_absolute};
- use os::{split_paths, setenv, unsetenv};
+ use os::{split_paths, join_paths, setenv, unsetenv};
use os;
use rand::Rng;
use rand;
parsed.iter().map(|s| Path::new(*s)).collect()
}
- assert!(check_parse("", []));
- assert!(check_parse(r#""""#, []));
- assert!(check_parse(";;", []));
+ assert!(check_parse("", [""]));
+ assert!(check_parse(r#""""#, [""]));
+ assert!(check_parse(";;", ["", "", ""]));
assert!(check_parse(r"c:\", [r"c:\"]));
- assert!(check_parse(r"c:\;", [r"c:\"]));
+ assert!(check_parse(r"c:\;", [r"c:\", ""]));
assert!(check_parse(r"c:\;c:\Program Files\",
[r"c:\", r"c:\Program Files\"]));
assert!(check_parse(r#"c:\;c:\"foo"\"#, [r"c:\", r"c:\foo\"]));
parsed.iter().map(|s| Path::new(*s)).collect()
}
- assert!(check_parse("", []));
- assert!(check_parse("::", []));
+ assert!(check_parse("", [""]));
+ assert!(check_parse("::", ["", "", ""]));
assert!(check_parse("/", ["/"]));
- assert!(check_parse("/:", ["/"]));
+ assert!(check_parse("/:", ["/", ""]));
assert!(check_parse("/:/usr/local", ["/", "/usr/local"]));
}
+ #[test]
+ #[cfg(unix)]
+ fn join_paths_unix() {
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ join_paths(input).unwrap().as_slice() == output.as_bytes()
+ }
+
+ assert!(test_eq([], ""));
+ assert!(test_eq(["/bin", "/usr/bin", "/usr/local/bin"],
+ "/bin:/usr/bin:/usr/local/bin"));
+ assert!(test_eq(["", "/bin", "", "", "/usr/bin", ""],
+ ":/bin:::/usr/bin:"));
+ assert!(join_paths(["/te:st"]).is_err());
+ }
+
+ #[test]
+ #[cfg(windows)]
+ fn join_paths_windows() {
+ fn test_eq(input: &[&str], output: &str) -> bool {
+ join_paths(input).unwrap().as_slice() == output.as_bytes()
+ }
+
+ assert!(test_eq([], ""));
+ assert!(test_eq([r"c:\windows", r"c:\"],
+ r"c:\windows;c:\"));
+ assert!(test_eq(["", r"c:\windows", "", "", r"c:\", ""],
+ r";c:\windows;;;c:\;"));
+ assert!(test_eq([r"c:\te;st", r"c:\"],
+ r#""c:\te;st";c:\"#));
+ assert!(join_paths([r#"c:\te"st"#]).is_err());
+ }
+
// More recursive_mkdir tests are in extra::tempfile
}
}
// while it doesn't requires lock for work as everything is
- // local, it still displays much nicier backtraces when a
+ // local, it still displays much nicer backtraces when a
// couple of tasks fail simultaneously
static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
let _g = unsafe { LOCK.lock() };
}
// We woke ourselves up from select. Assert that the task should be
- // trashed and returne that we don't have any data.
+ // trashed and returned that we don't have any data.
n => {
let t = unsafe { BlockedTask::cast_from_uint(n) };
t.trash();
// This function should be used after newly created Packet
// was wrapped with an Arc
- // In other case mutex data will be duplicated while clonning
+ // In other case mutex data will be duplicated while cloning
// and that could cause problems on platforms where it is
// represented by opaque data structure
pub fn postinit_lock(&mut self) {
// See Port::drop for what's going on
if self.port_dropped.load(atomics::SeqCst) { return Err(t) }
- // Note that the multiple sender case is a little tricker
+ // Note that the multiple sender case is a little trickier
// semantically than the single sender case. The logic for
// incrementing is "add and if disconnected store disconnected".
// This could end up leading some senders to believe that there
//! use this crate specifically. Instead, its functionality is reexported
//! through `std::sync`.
-#![crate_id = "sync#0.11.0-pre"]
+#![crate_id = "sync#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase, globs, macro_rules, unsafe_destructor)]
None => {}
}
- // After we've failed the fast path, then we delegate to the differnet
+ // After we've failed the fast path, then we delegate to the different
// locking protocols for green/native tasks. This will select two tasks
// to continue further (one native, one green).
let t: Box<Task> = Local::take();
// In the nullary enum case, the parser can't determine
// which it is. The resolver determines this, and
// records this pattern's NodeId in an auxiliary
- // set (of "pat_idents that refer to nullary enums")
- PatIdent(BindingMode, Path, Option<Gc<Pat>>),
+ // set (of "PatIdents that refer to nullary enums")
+ PatIdent(BindingMode, SpannedIdent, Option<Gc<Pat>>),
PatEnum(Path, Option<Vec<Gc<Pat>>>), /* "none" means a * pattern where
* we don't bind the fields to names */
PatStruct(Path, Vec<FieldPat>, bool),
impl Arg {
pub fn new_self(span: Span, mutability: Mutability) -> Arg {
- let path = ast_util::ident_to_path(span, special_idents::self_);
+ let path = Spanned{span:span,node:special_idents::self_};
Arg {
// HACK(eddyb) fake type for the self argument.
ty: P(Ty {
}).collect::<Vec<String>>().connect("::")
}
-// totally scary function: ignores all but the last element, should have
-// a different name
-pub fn path_to_ident(path: &Path) -> Ident {
- path.segments.last().unwrap().identifier
-}
-
pub fn local_def(id: NodeId) -> DefId {
ast::DefId { krate: LOCAL_CRATE, node: id }
}
})
}
+// convert a span and an identifier to the corresponding
+// 1-segment path
pub fn ident_to_path(s: Span, identifier: Ident) -> Path {
ast::Path {
span: s,
pub fn ident_to_pat(id: NodeId, s: Span, i: Ident) -> Gc<Pat> {
box(GC) ast::Pat { id: id,
- node: PatIdent(BindByValue(MutImmutable), ident_to_path(s, i), None),
+ node: PatIdent(BindByValue(MutImmutable), codemap::Spanned{span:s, node:i}, None),
span: s }
}
use codemap::Span;
use ext::base;
use ext::base::*;
-use parse;
use parse::token::InternedString;
use parse::token;
pub fn expand_asm(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult> {
- let mut p = parse::new_parser_from_tts(cx.parse_sess(),
- cx.cfg(),
- tts.iter()
- .map(|x| (*x).clone())
- .collect());
-
+ let mut p = cx.new_parser_from_tts(tts);
let mut asm = InternedString::new("");
let mut asm_str_style = None;
let mut outputs = Vec::new();
use ext;
use ext::expand;
use parse;
+use parse::parser;
use parse::token;
use parse::token::{InternedString, intern, str_to_ident};
use util::small_vector::SmallVector;
}
}
+ pub fn new_parser_from_tts(&self, tts: &[ast::TokenTree])
+ -> parser::Parser<'a> {
+ parse::tts_to_parser(self.parse_sess, Vec::from_slice(tts), self.cfg())
+ }
+
pub fn codemap(&self) -> &'a CodeMap { &self.parse_sess.span_diagnostic.cm }
pub fn parse_sess(&self) -> &'a parse::ParseSess { self.parse_sess }
pub fn cfg(&self) -> ast::CrateConfig { self.cfg.clone() }
}
/// Emit `msg` attached to `sp`, and stop compilation immediately.
///
- /// `span_err` should be strongly prefered where-ever possible:
+ /// `span_err` should be strongly preferred where-ever possible:
/// this should *only* be used when
/// - continuing has a high risk of flow-on errors (e.g. errors in
/// declaring a macro would cause all uses of that macro to
pub fn get_exprs_from_tts(cx: &mut ExtCtxt,
sp: Span,
tts: &[ast::TokenTree]) -> Option<Vec<Gc<ast::Expr>>> {
- let mut p = parse::new_parser_from_tts(cx.parse_sess(),
- cx.cfg(),
- tts.iter()
- .map(|x| (*x).clone())
- .collect());
+ let mut p = cx.new_parser_from_tts(tts);
let mut es = Vec::new();
while p.token != token::EOF {
es.push(cx.expand_expr(p.parse_expr()));
span: Span,
ident: ast::Ident,
bm: ast::BindingMode) -> Gc<ast::Pat> {
- let path = self.path_ident(span, ident);
- let pat = ast::PatIdent(bm, path, None);
+ let pat = ast::PatIdent(bm, Spanned{span: span, node: ident}, None);
self.pat(span, pat)
}
fn pat_enum(&self, span: Span, path: ast::Path, subpats: Vec<Gc<ast::Pat>> ) -> Gc<ast::Pat> {
use parse::attr::ParserAttr;
use parse::token::InternedString;
use parse::token;
-use parse;
pub fn expand_cfg(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
-> Box<base::MacResult> {
- let mut p = parse::new_parser_from_tts(cx.parse_sess(),
- cx.cfg(),
- tts.iter()
- .map(|x| (*x).clone())
- .collect());
-
+ let mut p = cx.new_parser_from_tts(tts);
let mut cfgs = Vec::new();
// parse `cfg!(meta_item, meta_item(x,y), meta_item="foo", ...)`
while p.token != token::EOF {
generic `deriving`");
}
- // `ref` inside let matches is buggy. Causes havoc wih rusc.
+ // `ref` inside let matches is buggy. Causes havoc with rusc.
// let (variant_index, ref self_vec) = matches_so_far[0];
let (variant, self_vec) = match matches_so_far.get(0) {
&(_, v, ref s) => (v, s)
fn create_subpatterns(&self,
cx: &mut ExtCtxt,
- field_paths: Vec<ast::Path> ,
+ field_paths: Vec<ast::SpannedIdent> ,
mutbl: ast::Mutability)
-> Vec<Gc<ast::Pat>> {
field_paths.iter().map(|path| {
cx.span_bug(sp, "a struct with named and unnamed fields in `deriving`");
}
};
- let path =
- cx.path_ident(sp,
- cx.ident_of(format!("{}_{}",
- prefix,
- i).as_slice()));
- paths.push(path.clone());
+ let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
+ paths.push(codemap::Spanned{span: sp, node: ident});
let val = cx.expr(
- sp, ast::ExprParen(
- cx.expr_deref(sp, cx.expr_path(path))));
+ sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(cx.path_ident(sp,ident)))));
ident_expr.push((sp, opt_id, val));
}
let mut ident_expr = Vec::new();
for (i, va) in variant_args.iter().enumerate() {
let sp = self.set_expn_info(cx, va.ty.span);
- let path =
- cx.path_ident(sp,
- cx.ident_of(format!("{}_{}",
- prefix,
- i).as_slice()));
-
- paths.push(path.clone());
- let val = cx.expr(
- sp, ast::ExprParen(cx.expr_deref(sp, cx.expr_path(path))));
+ let ident = cx.ident_of(format!("{}_{}", prefix, i).as_slice());
+ let path1 = codemap::Spanned{span: sp, node: ident};
+ paths.push(path1);
+ let expr_path = cx.expr_path(cx.path_ident(sp, ident));
+ let val = cx.expr(sp, ast::ExprParen(cx.expr_deref(sp, expr_path)));
ident_expr.push((sp, None, val));
}
// we found a pat_ident!
ast::Pat {
id: _,
- node: ast::PatIdent(_, ref path, ref inner),
+ node: ast::PatIdent(_, ref path1, ref inner),
span: _
} => {
- match path {
- // a path of length one:
- &ast::Path {
- global: false,
- span: _,
- segments: ref segments
- } if segments.len() == 1 => {
- self.ident_accumulator.push(segments.get(0)
- .identifier)
- }
- // I believe these must be enums...
- _ => ()
- }
+ self.ident_accumulator.push(path1.node);
// visit optional subpattern of pat_ident:
for subpat in inner.iter() {
self.visit_pat(&**subpat, ())
}
// create a really evil test case where a $x appears inside a binding of $x
- // but *shouldnt* bind because it was inserted by a different macro....
+ // but *shouldn't* bind because it was inserted by a different macro....
// can't write this test case until we have macro-generating macros.
// FIXME #9383 : lambda var hygiene
use ext::build::AstBuilder;
use parse::token::InternedString;
use parse::token;
-use rsparse = parse;
use parse = fmt_macros;
use std::collections::HashMap;
let mut names = HashMap::<String, Gc<ast::Expr>>::new();
let mut order = Vec::new();
- let mut p = rsparse::new_parser_from_tts(ecx.parse_sess(),
- ecx.cfg(),
- tts.iter()
- .map(|x| (*x).clone())
- .collect());
+ let mut p = ecx.new_parser_from_tts(tts);
// Parse the leading function expression (maybe a block, maybe a path)
let invocation = if allow_method {
let e = p.parse_expr();
use ext::build::AstBuilder;
use parse::token::*;
use parse::token;
-use parse;
use std::gc::Gc;
// it has to do with transition away from supporting old-style macros, so
// try removing it when enough of them are gone.
- let mut p = parse::new_parser_from_tts(cx.parse_sess(),
- cx.cfg(),
- tts.iter()
- .map(|x| (*x).clone())
- .collect());
+ let mut p = cx.new_parser_from_tts(tts);
p.quote_depth += 1u;
let cx_expr = p.parse_expr();
let node = match p.node {
PatWild => PatWild,
PatWildMulti => PatWildMulti,
- PatIdent(binding_mode, ref pth, ref sub) => {
+ PatIdent(binding_mode, ref pth1, ref sub) => {
PatIdent(binding_mode,
- folder.fold_path(pth),
+ Spanned{span: folder.new_span(pth1.span),
+ node: folder.fold_ident(pth1.node)},
sub.map(|x| folder.fold_pat(x)))
}
PatLit(e) => PatLit(folder.fold_expr(e)),
*/
-#![crate_id = "syntax#0.11.0-pre"]
+#![crate_id = "syntax#0.11.0"]
#![experimental]
#![license = "MIT/ASL2"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(macro_rules, globs, managed_boxes, default_type_params, phase)]
#![feature(quote, unsafe_destructor)]
#[test] fn parse_ident_pat () {
let sess = new_parse_sess();
let mut parser = string_to_parser(&sess, "b".to_string());
- assert!(parser.parse_pat() ==
- box(GC) ast::Pat{id: ast::DUMMY_NODE_ID,
- node: ast::PatIdent(
- ast::BindByValue(ast::MutImmutable),
- ast::Path {
- span:sp(0,1),
- global:false,
- segments: vec!(
- ast::PathSegment {
- identifier: str_to_ident("b"),
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
- }
- ),
- },
- None /* no idea */),
- span: sp(0,1)});
+ assert!(parser.parse_pat()
+ == box(GC) ast::Pat{
+ id: ast::DUMMY_NODE_ID,
+ node: ast::PatIdent(ast::BindByValue(ast::MutImmutable),
+ Spanned{ span:sp(0, 1),
+ node: str_to_ident("b")
+ },
+ None),
+ span: sp(0,1)});
parser_done(parser);
}
id: ast::DUMMY_NODE_ID,
node: ast::PatIdent(
ast::BindByValue(ast::MutImmutable),
- ast::Path {
- span:sp(6,7),
- global:false,
- segments: vec!(
- ast::PathSegment {
- identifier:
- str_to_ident("b"),
- lifetimes: Vec::new(),
- types: OwnedSlice::empty(),
- }
- ),
- },
- None // no idea
- ),
- span: sp(6,7)
- },
- id: ast::DUMMY_NODE_ID
- }),
+ Spanned{
+ span: sp(6,7),
+ node: str_to_ident("b")},
+ None
+ ),
+ span: sp(6,7)
+ },
+ id: ast::DUMMY_NODE_ID
+ }),
output: ast::P(ast::Ty{id: ast::DUMMY_NODE_ID,
node: ast::TyNil,
span:sp(15,15)}), // not sure
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
use ast::Visibility;
use ast;
-use ast_util::{as_prec, lit_is_str, operator_prec};
+use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
use ast_util;
use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
use codemap;
self.bump();
self.parse_pat()
} else {
- let fieldpath = ast_util::ident_to_path(self.last_span,
- fieldname);
+ let fieldpath = codemap::Spanned{span:self.last_span, node: fieldname};
box(GC) ast::Pat {
id: ast::DUMMY_NODE_ID,
node: PatIdent(bind_type, fieldpath, None),
}
_ => {}
}
+ // at this point, token != _, ~, &, &&, (, [
if (!is_ident_or_path(&self.token) && self.token != token::MOD_SEP)
|| self.is_keyword(keywords::True)
let end = self.parse_expr_res(RESTRICT_NO_BAR_OP);
pat = PatRange(start, end);
} else if is_plain_ident(&self.token) && !can_be_enum_or_struct {
- let name = self.parse_path(NoTypesAllowed).path;
+ let id = self.parse_ident();
+ let id_span = self.last_span;
+ let pth1 = codemap::Spanned{span:id_span, node: id};
if self.eat(&token::NOT) {
// macro invocation
let ket = token::close_delimiter_for(&self.token)
seq_sep_none(),
|p| p.parse_token_tree());
- let mac = MacInvocTT(name, tts, EMPTY_CTXT);
+ let mac = MacInvocTT(ident_to_path(id_span,id), tts, EMPTY_CTXT);
pat = ast::PatMac(codemap::Spanned {node: mac, span: self.span});
} else {
let sub = if self.eat(&token::AT) {
// or just foo
None
};
- pat = PatIdent(BindByValue(MutImmutable), name, sub);
+ pat = PatIdent(BindByValue(MutImmutable), pth1, sub);
}
} else {
// parse an enum pat
// or an identifier pattern, resolve
// will sort it out:
pat = PatIdent(BindByValue(MutImmutable),
- enum_path,
- None);
+ codemap::Spanned{
+ span: enum_path.span,
+ node: enum_path.segments.get(0)
+ .identifier},
+ None);
} else {
pat = PatEnum(enum_path, Some(args));
}
"expected identifier, found path");
}
// why a path here, and not just an identifier?
- let name = self.parse_path(NoTypesAllowed).path;
+ let name = codemap::Spanned{span: self.last_span, node: self.parse_ident()};
let sub = if self.eat(&token::AT) {
Some(self.parse_pat())
} else {
None => {
// we only expect an ident if we didn't parse one
// above.
- let ident_str = if id == token::special_idents::invalid {
+ let ident_str = if id.name == token::special_idents::invalid.name {
"identifier, "
} else {
""
);
let hi = self.span.hi;
- if id == token::special_idents::invalid {
+ if id.name == token::special_idents::invalid.name {
return box(GC) spanned(lo, hi, StmtMac(
spanned(lo, hi, MacInvocTT(pth, tts, EMPTY_CTXT)), false));
} else {
to_str(|s| s.print_path(p, false))
}
+pub fn ident_to_str(id: &ast::Ident) -> String {
+ to_str(|s| s.print_ident(*id))
+}
+
pub fn fun_to_str(decl: &ast::FnDecl, fn_style: ast::FnStyle, name: ast::Ident,
opt_explicit_self: Option<ast::ExplicitSelf_>,
generics: &ast::Generics) -> String {
match pat.node {
ast::PatWild => try!(word(&mut self.s, "_")),
ast::PatWildMulti => try!(word(&mut self.s, "..")),
- ast::PatIdent(binding_mode, ref path, sub) => {
+ ast::PatIdent(binding_mode, ref path1, sub) => {
match binding_mode {
ast::BindByRef(mutbl) => {
try!(self.word_nbsp("ref"));
try!(self.word_nbsp("mut"));
}
}
- try!(self.print_path(path, true));
+ try!(self.print_ident(path1.node));
match sub {
Some(ref p) => {
try!(word(&mut self.s, "@"));
ast::TyInfer => try!(self.print_pat(&*input.pat)),
_ => {
match input.pat.node {
- ast::PatIdent(_, ref path, _) if
- path.segments.len() == 1 &&
- path.segments.get(0).identifier.name ==
+ ast::PatIdent(_, ref path1, _) if
+ path1.node.name ==
parse::token::special_idents::invalid.name => {
// Do nothing.
}
PatRegion(ref subpattern) => {
visitor.visit_pat(&**subpattern, env)
}
- PatIdent(_, ref path, ref optional_subpattern) => {
- visitor.visit_path(path, pattern.id, env.clone());
+ PatIdent(_, ref pth1, ref optional_subpattern) => {
+ visitor.visit_ident(pth1.span, pth1.node, env.clone());
match *optional_subpattern {
None => {}
Some(ref subpattern) => visitor.visit_pat(&**subpattern, env),
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo
-#![crate_id = "term#0.11.0-pre"]
+#![crate_id = "term#0.11.0"]
#![experimental]
#![comment = "Simple ANSI color library"]
#![license = "MIT/ASL2"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(macro_rules, phase)]
// running tests while providing a base that other test frameworks may
// build off of.
-#![crate_id = "test#0.11.0-pre"]
+#![crate_id = "test#0.11.0"]
#![experimental]
#![comment = "Rust internal test library only used by rustc"]
#![license = "MIT/ASL2"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/")]
+ html_root_url = "http://doc.rust-lang.org/0.11.0/")]
#![feature(asm, macro_rules, phase)]
//! Simple time handling.
-#![crate_id = "time#0.11.0-pre"]
+#![crate_id = "time#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(phase)]
}
/**
- * Return a string of the current time in the form
- * "Thu Jan 1 00:00:00 1970".
+ * Returns a time string formatted according to the `asctime` format in ISO
+ * C, in the local timezone.
+ *
+ * Example: "Thu Jan 1 00:00:00 1970"
+ */
+ pub fn ctime(&self) -> String {
+ self.to_local().asctime()
+ }
+
+ /**
+ * Returns a time string formatted according to the `asctime` format in ISO
+ * C.
+ *
+ * Example: "Thu Jan 1 00:00:00 1970"
*/
- pub fn ctime(&self) -> String { self.strftime("%c") }
+ pub fn asctime(&self) -> String {
+ self.strftime("%c")
+ }
/// Formats the time according to the format string.
pub fn strftime(&self, format: &str) -> String {
* Returns a time string formatted according to RFC 822.
*
* local: "Thu, 22 Mar 2012 07:53:18 PST"
- * utc: "Thu, 22 Mar 2012 14:53:18 UTC"
+ * utc: "Thu, 22 Mar 2012 14:53:18 GMT"
*/
pub fn rfc822(&self) -> String {
if self.tm_gmtoff == 0_i32 {
}
/**
- * Returns a time string formatted according to ISO 8601.
+ * Returns a time string formatted according to RFC 3999. RFC 3999 is
+ * compatible with ISO 8601.
*
* local: "2012-02-22T07:53:18-07:00"
* utc: "2012-02-22T14:53:18Z"
assert_eq!(strptime("360", "%Y-%m-%d"), Err("Invalid year".to_string()))
}
+ fn test_asctime() {
+ set_time_zone();
+
+ let time = Timespec::new(1234567890, 54321);
+ let utc = at_utc(time);
+ let local = at(time);
+
+ debug!("test_ctime: {:?} {:?}", utc.asctime(), local.asctime());
+
+ assert_eq!(utc.asctime(), "Fri Feb 13 23:31:30 2009".to_string());
+ assert_eq!(local.asctime(), "Fri Feb 13 15:31:30 2009".to_string());
+ }
+
fn test_ctime() {
set_time_zone();
debug!("test_ctime: {:?} {:?}", utc.ctime(), local.ctime());
- assert_eq!(utc.ctime(), "Fri Feb 13 23:31:30 2009".to_string());
+ assert_eq!(utc.ctime(), "Fri Feb 13 15:31:30 2009".to_string());
assert_eq!(local.ctime(), "Fri Feb 13 15:31:30 2009".to_string());
}
assert_eq!(local.strftime("%z"), "-0800".to_string());
assert_eq!(local.strftime("%%"), "%".to_string());
+ assert_eq!(local.asctime(), "Fri Feb 13 15:31:30 2009".to_string());
assert_eq!(local.ctime(), "Fri Feb 13 15:31:30 2009".to_string());
assert_eq!(local.rfc822z(), "Fri, 13 Feb 2009 15:31:30 -0800".to_string());
assert_eq!(local.rfc3339(), "2009-02-13T15:31:30-08:00".to_string());
- assert_eq!(utc.ctime(), "Fri Feb 13 23:31:30 2009".to_string());
+ assert_eq!(utc.asctime(), "Fri Feb 13 23:31:30 2009".to_string());
+ assert_eq!(utc.ctime(), "Fri Feb 13 15:31:30 2009".to_string());
assert_eq!(utc.rfc822(), "Fri, 13 Feb 2009 23:31:30 GMT".to_string());
assert_eq!(utc.rfc822z(), "Fri, 13 Feb 2009 23:31:30 -0000".to_string());
assert_eq!(utc.rfc3339(), "2009-02-13T23:31:30Z".to_string());
test_to_timespec();
test_conversions();
test_strptime();
+ test_asctime();
test_ctime();
test_strftime();
test_timespec_eq_ord();
//! Types/fns concerning URLs (see RFC 3986)
-#![crate_id = "url#0.11.0-pre"]
+#![crate_id = "url#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(default_type_params)]
*/
-#![crate_id = "uuid#0.11.0-pre"]
+#![crate_id = "uuid#0.11.0"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
- html_root_url = "http://doc.rust-lang.org/",
+ html_root_url = "http://doc.rust-lang.org/0.11.0/",
html_playground_url = "http://play.rust-lang.org/")]
#![feature(default_type_params)]
// no-prefer-dynamic
-#![crate_id = "url#0.11.0-pre"]
+#![crate_id = "url#0.11.0"]
#![crate_type = "dylib"]
// no-prefer-dynamic
-#![crate_id = "url#0.11.0-pre"]
+#![crate_id = "url#0.11.0"]
#![crate_type = "rlib"]
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(overloaded_calls)]
+
+use std::ops::{Fn, FnMut, FnOnce};
+
+struct SFn {
+ x: int,
+ y: int,
+}
+
+impl Fn<(int,),int> for SFn {
+ fn call(&self, (z,): (int,)) -> int {
+ self.x * self.y * z
+ }
+}
+
+struct SFnMut {
+ x: int,
+ y: int,
+}
+
+impl FnMut<(int,),int> for SFnMut {
+ fn call_mut(&mut self, (z,): (int,)) -> int {
+ self.x * self.y * z
+ }
+}
+
+struct SFnOnce {
+ x: String,
+}
+
+impl FnOnce<(String,),uint> for SFnOnce {
+ fn call_once(self, (z,): (String,)) -> uint {
+ self.x.len() + z.len()
+ }
+}
+
+fn f() {
+ let mut s = SFn {
+ x: 1,
+ y: 2,
+ };
+ let sp = &mut s;
+ s(3); //~ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+ //~^ ERROR cannot borrow `s` as immutable because it is also borrowed as mutable
+}
+
+fn g() {
+ let s = SFnMut {
+ x: 1,
+ y: 2,
+ };
+ s(3); //~ ERROR cannot borrow immutable local variable `s` as mutable
+}
+
+fn h() {
+ let s = SFnOnce {
+ x: "hello".to_string(),
+ };
+ s(" world".to_string());
+ s(" world".to_string()); //~ ERROR use of moved value: `s`
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// We only want to assert that this doesn't ICE, we don't particularly care
+// about whether it nor it fails to compile.
+
+// error-pattern:
+
+#![feature(macro_rules)]
+
+macro_rules! foo{
+ () => {{
+ macro_rules! bar{() => (())}
+ 1
+ }}
+}
+
+pub fn main() {
+ foo!();
+
+ assert!({one! two()});
+
+ // regardless of whether nested macro_rules works, the following should at
+ // least throw a conventional error.
+ assert!({one! two});
+}
+
--- /dev/null
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #14061: tests the interaction between generic implementation
+// parameter bounds and trait objects.
+
+struct S<T>;
+
+trait Gettable<T> {}
+
+impl<T: Send + Copy> Gettable<T> for S<T> {}
+
+fn f<T>(val: T) {
+ let t: S<T> = S;
+ let a = &t as &Gettable<T>;
+ //~^ ERROR instantiating a type parameter with an incompatible type `T`
+ let a: &Gettable<T> = &t;
+ //~^ ERROR instantiating a type parameter with an incompatible type `T`
+}
+
+fn main() {
+ let t: S<&int> = S;
+ let a = &t as &Gettable<&int>;
+ //~^ ERROR instantiating a type parameter with an incompatible type `&int`
+ let t: Box<S<String>> = box S;
+ let a = t as Box<Gettable<String>>;
+ //~^ ERROR instantiating a type parameter with an incompatible type
+ let t: Box<S<String>> = box S;
+ let a: Box<Gettable<String>> = t;
+ //~^ ERROR instantiating a type parameter with an incompatible type
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// Make sure rustc checks the type parameter bounds in implementations of traits,
+// see #2687
+
+trait A {}
+
+trait B: A {}
+
+trait C: A {}
+
+trait Foo {
+ fn test_error1_fn<T: Eq>(&self);
+ fn test_error2_fn<T: Eq + Ord>(&self);
+ fn test_error3_fn<T: Eq + Ord>(&self);
+ fn test3_fn<T: Eq + Ord>(&self);
+ fn test4_fn<T: Eq + Ord>(&self);
+ fn test_error5_fn<T: A>(&self);
+ fn test6_fn<T: A + Eq>(&self);
+ fn test_error7_fn<T: A>(&self);
+ fn test_error8_fn<T: B>(&self);
+}
+
+impl Foo for int {
+ // invalid bound for T, was defined as Eq in trait
+ fn test_error1_fn<T: Ord>(&self) {}
+ //~^ ERROR in method `test_error1_fn`, type parameter 0 requires bound `core::cmp::Ord`
+
+ // invalid bound for T, was defined as Eq + Ord in trait
+ fn test_error2_fn<T: Eq + B>(&self) {}
+ //~^ ERROR in method `test_error2_fn`, type parameter 0 requires bound `B`
+
+ // invalid bound for T, was defined as Eq + Ord in trait
+ fn test_error3_fn<T: B + Eq>(&self) {}
+ //~^ ERROR in method `test_error3_fn`, type parameter 0 requires bound `B`
+
+ // multiple bounds, same order as in trait
+ fn test3_fn<T: Ord + Eq>(&self) {}
+
+ // multiple bounds, different order as in trait
+ fn test4_fn<T: Eq + Ord>(&self) {}
+
+ // parameters in impls must be equal or more general than in the defining trait
+ fn test_error5_fn<T: B>(&self) {}
+ //~^ ERROR in method `test_error5_fn`, type parameter 0 requires bound `B`
+
+ // bound `std::cmp::Eq` not enforced by this implementation, but this is OK
+ fn test6_fn<T: A>(&self) {}
+
+ fn test_error7_fn<T: A + Eq>(&self) {}
+ //~^ ERROR in method `test_error7_fn`, type parameter 0 requires bound `core::cmp::Eq`
+
+ fn test_error8_fn<T: C>(&self) {}
+ //~^ ERROR in method `test_error8_fn`, type parameter 0 requires bound `C`
+}
+
+
+trait Getter<T> { }
+
+trait Trait {
+ fn method<G:Getter<int>>();
+}
+
+impl Trait for uint {
+ fn method<G: Getter<uint>>() {}
+ //~^ ERROR in method `method`, type parameter 0 requires bound `Getter<uint>`
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Issue #5886: a complex instance of issue #2687.
+
+trait Iterator<A> {
+ fn next(&mut self) -> Option<A>;
+}
+
+trait IteratorUtil<A> {
+ fn zip<B, U: Iterator<U>>(self, other: U) -> ZipIterator<Self, U>;
+}
+
+impl<A, T: Iterator<A>> IteratorUtil<A> for T {
+ fn zip<B, U: Iterator<B>>(self, other: U) -> ZipIterator<T, U> {
+ //~^ ERROR in method `zip`, type parameter 1 requires bound `Iterator<B>`
+ ZipIterator{a: self, b: other}
+ }
+}
+
+struct ZipIterator<T, U> {
+ a: T, b: U
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::num::Num;
+
+trait BrokenAdd: Num {
+ fn broken_add<T>(&self, rhs: T) -> Self {
+ *self + rhs //~ ERROR mismatched types
+ }
+}
+
+impl<T: Num> BrokenAdd for T {}
+
+pub fn main() {
+ let foo: u8 = 0u8;
+ let x: u8 = foo.broken_add("hello darkness my old friend".to_string());
+ println!("{}", x);
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Tr<T> {
+ fn op(T) -> Self;
+}
+
+// these compile as if Self: Tr<U>, even tho only Self: Tr<Self or T>
+trait A: Tr<Self> {
+ fn test<U>(u: U) -> Self {
+ Tr::op(u) //~ ERROR expected Tr<U>, but found Tr<Self>
+ }
+}
+trait B<T>: Tr<T> {
+ fn test<U>(u: U) -> Self {
+ Tr::op(u) //~ ERROR expected Tr<U>, but found Tr<T>
+ }
+}
+
+impl<T> Tr<T> for T {
+ fn op(t: T) -> T { t }
+}
+impl<T> A for T {}
+
+fn main() {
+ std::io::println(A::test((&7306634593706211700, 8)));
+}
+
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+trait Tr {
+ fn test<X>(u: X) -> Self {
+ u //~ ERROR mismatched types
+ }
+}
+
+fn main() {}
+
--- /dev/null
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+// ignore-lldb
+// ignore-android: FIXME(#10381)
+
+// compile-flags:-g
+// gdb-command:rbreak zzz
+// gdb-command:run
+// gdb-command:finish
+
+
+// STRUCTS
+// gdb-command:whatis simple_struct
+// gdb-check:type = struct Struct1
+
+// gdb-command:whatis generic_struct1
+// gdb-check:type = struct GenericStruct<type-names::Mod1::Struct2, type-names::Mod1::Mod2::Struct3>
+
+// gdb-command:whatis generic_struct2
+// gdb-check:type = struct GenericStruct<type-names::Struct1, extern "fastcall" fn(int) -> uint>
+
+// gdb-command:whatis mod_struct
+// gdb-check:type = struct Struct2
+
+
+// ENUMS
+// gdb-command:whatis simple_enum_1
+// gdb-check:type = union Enum1
+
+// gdb-command:whatis simple_enum_2
+// gdb-check:type = union Enum1
+
+// gdb-command:whatis simple_enum_3
+// gdb-check:type = union Enum2
+
+// gdb-command:whatis generic_enum_1
+// gdb-check:type = union Enum3<type-names::Mod1::Struct2>
+
+// gdb-command:whatis generic_enum_2
+// gdb-check:type = union Enum3<type-names::Struct1>
+
+
+// TUPLES
+// gdb-command:whatis tuple1
+// gdb-check:type = struct (u32, type-names::Struct1, type-names::Mod1::Mod2::Enum3<type-names::Mod1::Struct2>)
+
+// gdb-command:whatis tuple2
+// gdb-check:type = struct ((type-names::Struct1, type-names::Mod1::Mod2::Struct3), type-names::Mod1::Enum2, char)
+
+
+// BOX
+// gdb-command:whatis box1
+// gdb-check:type = struct (Box<f32>, i32)
+
+// gdb-command:whatis box2
+// gdb-check:type = struct (Box<type-names::Mod1::Mod2::Enum3<f32>>, i32)
+
+
+// REFERENCES
+// gdb-command:whatis ref1
+// gdb-check:type = struct (&type-names::Struct1, i32)
+
+// gdb-command:whatis ref2
+// gdb-check:type = struct (&type-names::GenericStruct<char, type-names::Struct1>, i32)
+
+// gdb-command:whatis mut_ref1
+// gdb-check:type = struct (&mut type-names::Struct1, i32)
+
+// gdb-command:whatis mut_ref2
+// gdb-check:type = struct (&mut type-names::GenericStruct<type-names::Mod1::Enum2, f64>, i32)
+
+
+// RAW POINTERS
+// gdb-command:whatis mut_ptr1
+// gdb-check:type = struct (*mut type-names::Struct1, int)
+
+// gdb-command:whatis mut_ptr2
+// gdb-check:type = struct (*mut int, int)
+
+// gdb-command:whatis mut_ptr3
+// gdb-check:type = struct (*mut type-names::Mod1::Mod2::Enum3<type-names::Struct1>, int)
+
+// gdb-command:whatis const_ptr1
+// gdb-check:type = struct (*const type-names::Struct1, int)
+
+// gdb-command:whatis const_ptr2
+// gdb-check:type = struct (*const int, int)
+
+// gdb-command:whatis const_ptr3
+// gdb-check:type = struct (*const type-names::Mod1::Mod2::Enum3<type-names::Struct1>, int)
+
+
+// VECTORS
+// gdb-command:whatis fixed_size_vec1
+// gdb-check:type = struct ([type-names::Struct1, ..3], i16)
+
+// gdb-command:whatis fixed_size_vec2
+// gdb-check:type = struct ([uint, ..3], i16)
+
+// gdb-command:whatis slice1
+// gdb-check:type = struct &[uint]
+
+// gdb-command:whatis slice2
+// gdb-check:type = struct &[type-names::Mod1::Enum2]
+
+
+// TRAITS
+// gdb-command:whatis box_trait
+// gdb-check:type = struct Box<Trait1>
+
+// gdb-command:whatis ref_trait
+// gdb-check:type = struct &Trait1
+
+// gdb-command:whatis mut_ref_trait
+// gdb-check:type = struct &mut Trait1
+
+// gdb-command:whatis generic_box_trait
+// gdb-check:type = struct Box<Trait2<i32, type-names::Mod1::Struct2>>
+
+// gdb-command:whatis generic_ref_trait
+// gdb-check:type = struct &Trait2<type-names::Struct1, type-names::Struct1>
+
+// gdb-command:whatis generic_mut_ref_trait
+// gdb-check:type = struct &mut Trait2<type-names::Mod1::Mod2::Struct3, type-names::GenericStruct<uint, int>>
+
+
+// BARE FUNCTIONS
+// gdb-command:whatis rust_fn
+// gdb-check:type = struct (fn(core::option::Option<int>, core::option::Option<&type-names::Mod1::Struct2>), uint)
+
+// gdb-command:whatis extern_c_fn
+// gdb-check:type = struct (extern "C" fn(int), uint)
+
+// gdb-command:whatis unsafe_fn
+// gdb-check:type = struct (unsafe fn(core::result::Result<char, f64>), uint)
+
+// gdb-command:whatis extern_stdcall_fn
+// gdb-check:type = struct (extern "stdcall" fn(), uint)
+
+// gdb-command:whatis rust_fn_with_return_value
+// gdb-check:type = struct (fn(f64) -> uint, uint)
+
+// gdb-command:whatis extern_c_fn_with_return_value
+// gdb-check:type = struct (extern "C" fn() -> type-names::Struct1, uint)
+
+// gdb-command:whatis unsafe_fn_with_return_value
+// gdb-check:type = struct (unsafe fn(type-names::GenericStruct<u16, u8>) -> type-names::Mod1::Struct2, uint)
+
+// gdb-command:whatis extern_stdcall_fn_with_return_value
+// gdb-check:type = struct (extern "stdcall" fn(Box<int>) -> uint, uint)
+
+// gdb-command:whatis generic_function_int
+// gdb-check:type = struct (fn(int) -> int, uint)
+
+// gdb-command:whatis generic_function_struct3
+// gdb-check:type = struct (fn(type-names::Mod1::Mod2::Struct3) -> type-names::Mod1::Mod2::Struct3, uint)
+
+// gdb-command:whatis variadic_function
+// gdb-check:type = struct (unsafe extern "C" fn(*const u8, ...) -> int, uint)
+
+
+// CLOSURES
+// gdb-command:whatis some_proc
+// gdb-check:type = struct (once proc(int, u8) -> (int, u8), uint)
+
+// gdb-command:whatis stack_closure1
+// gdb-check:type = struct (&mut|int|, uint)
+
+// gdb-command:whatis stack_closure2
+// gdb-check:type = struct (&mut|i8, f32| -> f32, uint)
+
+use std::ptr;
+
+struct Struct1;
+struct GenericStruct<T1, T2>;
+
+enum Enum1 {
+ Variant1_1,
+ Variant1_2(int)
+}
+
+mod Mod1 {
+ pub struct Struct2;
+
+ pub enum Enum2 {
+ Variant2_1,
+ Variant2_2(super::Struct1)
+ }
+
+ pub mod Mod2 {
+ pub struct Struct3;
+
+ pub enum Enum3<T> {
+ Variant3_1,
+ Variant3_2(T),
+ }
+ }
+}
+
+trait Trait1 { }
+trait Trait2<T1, T2> { }
+
+impl Trait1 for int {}
+impl<T1, T2> Trait2<T1, T2> for int {}
+
+fn rust_fn(_: Option<int>, _: Option<&Mod1::Struct2>) {}
+extern "C" fn extern_c_fn(_: int) {}
+unsafe fn unsafe_fn(_: Result<char, f64>) {}
+extern "stdcall" fn extern_stdcall_fn() {}
+
+fn rust_fn_with_return_value(_: f64) -> uint { 4 }
+extern "C" fn extern_c_fn_with_return_value() -> Struct1 { Struct1 }
+unsafe fn unsafe_fn_with_return_value(_: GenericStruct<u16, u8>) -> Mod1::Struct2 { Mod1::Struct2 }
+extern "stdcall" fn extern_stdcall_fn_with_return_value(_: Box<int>) -> uint { 0 }
+
+fn generic_function<T>(x: T) -> T { x }
+
+extern {
+ fn printf(_:*const u8, ...) -> int;
+}
+
+// In many of the cases below, the type that is actually under test is wrapped
+// in a tuple, e.g. Box<T>, references, raw pointers, fixed-size vectors, ...
+// This is because GDB will not print the type name from DWARF debuginfo for
+// some kinds of types (pointers, arrays, functions, ...)
+// Since tuples are structs as far as GDB is concerned, their name will be
+// printed correctly, so the tests below just construct a tuple type that will
+// then *contain* the type name that we want to see.
+fn main() {
+
+ // Structs
+ let simple_struct = Struct1;
+ let generic_struct1: GenericStruct<Mod1::Struct2, Mod1::Mod2::Struct3> = GenericStruct;
+ let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(int) -> uint> = GenericStruct;
+ let mod_struct = Mod1::Struct2;
+
+ // Enums
+ let simple_enum_1 = Variant1_1;
+ let simple_enum_2 = Variant1_2(0);
+ let simple_enum_3 = Mod1::Variant2_2(Struct1);
+
+ let generic_enum_1: Mod1::Mod2::Enum3<Mod1::Struct2> = Mod1::Mod2::Variant3_1;
+ let generic_enum_2 = Mod1::Mod2::Variant3_2(Struct1);
+
+ // Tuples
+ let tuple1 = (8u32, Struct1, Mod1::Mod2::Variant3_2(Mod1::Struct2));
+ let tuple2 = ((Struct1, Mod1::Mod2::Struct3), Mod1::Variant2_1, 'x');
+
+ // Box
+ let box1 = (box 1f32, 0i32);
+ let box2 = (box Mod1::Mod2::Variant3_2(1f32), 0i32);
+
+ // References
+ let ref1 = (&Struct1, 0i32);
+ let ref2 = (&GenericStruct::<char, Struct1>, 0i32);
+
+ let mut mut_struct1 = Struct1;
+ let mut mut_generic_struct = GenericStruct::<Mod1::Enum2, f64>;
+ let mut_ref1 = (&mut mut_struct1, 0i32);
+ let mut_ref2 = (&mut mut_generic_struct, 0i32);
+
+ // Raw Pointers
+ let mut_ptr1: (*mut Struct1, int) = (ptr::mut_null(), 0);
+ let mut_ptr2: (*mut int, int) = (ptr::mut_null(), 0);
+ let mut_ptr3: (*mut Mod1::Mod2::Enum3<Struct1>, int) = (ptr::mut_null(), 0);
+
+ let const_ptr1: (*const Struct1, int) = (ptr::null(), 0);
+ let const_ptr2: (*const int, int) = (ptr::null(), 0);
+ let const_ptr3: (*const Mod1::Mod2::Enum3<Struct1>, int) = (ptr::null(), 0);
+
+ // Vectors
+ let fixed_size_vec1 = ([Struct1, Struct1, Struct1], 0i16);
+ let fixed_size_vec2 = ([0u, 1u, 2u], 0i16);
+
+ let vec1 = vec![0u, 2u, 3u];
+ let slice1 = vec1.as_slice();
+ let vec2 = vec![Mod1::Variant2_2(Struct1)];
+ let slice2 = vec2.as_slice();
+
+ // Trait Objects
+ let box_trait = (box 0i) as Box<Trait1>;
+ let ref_trait = &0i as &Trait1;
+ let mut mut_int1 = 0i;
+ let mut_ref_trait = (&mut mut_int1) as &mut Trait1;
+
+ let generic_box_trait = (box 0i) as Box<Trait2<i32, Mod1::Struct2>>;
+ let generic_ref_trait = (&0i) as &Trait2<Struct1, Struct1>;
+
+ let mut generic_mut_ref_trait_impl = 0i;
+ let generic_mut_ref_trait = (&mut generic_mut_ref_trait_impl) as
+ &mut Trait2<Mod1::Mod2::Struct3, GenericStruct<uint, int>>;
+
+ // Bare Functions
+ let rust_fn = (rust_fn, 0u);
+ let extern_c_fn = (extern_c_fn, 0u);
+ let unsafe_fn = (unsafe_fn, 0u);
+ let extern_stdcall_fn = (extern_stdcall_fn, 0u);
+
+ let rust_fn_with_return_value = (rust_fn_with_return_value, 0u);
+ let extern_c_fn_with_return_value = (extern_c_fn_with_return_value, 0u);
+ let unsafe_fn_with_return_value = (unsafe_fn_with_return_value, 0u);
+ let extern_stdcall_fn_with_return_value = (extern_stdcall_fn_with_return_value, 0u);
+
+ let generic_function_int = (generic_function::<int>, 0u);
+ let generic_function_struct3 = (generic_function::<Mod1::Mod2::Struct3>, 0u);
+
+ let variadic_function = (printf, 0u);
+
+ // Closures
+ // I (mw) am a bit unclear about the current state of closures, their
+ // various forms (boxed, unboxed, proc, capture-by-ref, by-val, once) and
+ // how that maps to rustc's internal representation of these forms.
+ // Once closures have reached their 1.0 form, the tests below should
+ // probably be expanded.
+ let some_proc = (proc(a:int, b:u8) (a, b), 0u);
+
+ let stack_closure1 = (|x:int| {}, 0u);
+ let stack_closure2 = (|x:i8, y: f32| { (x as f32) + y }, 0u);
+
+ zzz();
+}
+
+#[inline(never)]
+fn zzz() { () }
-include ../tools.mk
all:
- [ `$(RUSTC) --crate-id crate.rs` = "foo#0.11.0-pre" ]
+ [ `$(RUSTC) --crate-id crate.rs` = "foo#0.11.0" ]
[ `$(RUSTC) --crate-name crate.rs` = "foo" ]
[ `$(RUSTC) --crate-file-name crate.rs` = "foo" ]
[ `$(RUSTC) --crate-file-name --crate-type=lib --test crate.rs` = "foo" ]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![crate_id = "foo#0.11.0-pre"]
+#![crate_id = "foo#0.11.0"]
// Querying about the crate metadata should *not* parse the entire crate, it
// only needs the crate attributes (which are guaranteed to be at the top) be
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S;
+
+fn main() {
+ match Some(&S) {
+ Some(&S) => {},
+ _x => unreachable!()
+ }
+ match Some(&S) {
+ Some(&S) => {},
+ None => unreachable!()
+ }
+}
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Tests that type parameter bounds on an implementation need not match the
+// trait exactly, as long as the implementation doesn't demand *more* bounds
+// than the trait.
+
+trait A {
+ fn foo<T: Eq + Ord>(&self);
+}
+
+impl A for int {
+ fn foo<T: Ord + Ord>(&self) {}
+}
+
+fn main() {}
+
+
#![no_std]
extern crate std;
extern crate zed = "std";
-extern crate bar = "std#0.11.0-pre";
+extern crate bar = "std#0.11.0";
use std::str;