mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
auto merge of #21213 : alexcrichton/rust/rollup, r=alexcrichton
This commit is contained in:
commit
b565501ad8
@ -581,7 +581,7 @@ Robert Knight <robertknight@gmail.com>
|
||||
Robert Millar <robert.millar@cantab.net>
|
||||
Robin Gloster <robin@loc-com.de>
|
||||
Robin Stocker <robin@nibor.org>
|
||||
Rohit Joshi <rohit.joshi@capitalone.com>
|
||||
Rohit Joshi <rohit.c.joshi@gmail.com>
|
||||
Roland Tanglao <roland@rolandtanglao.com>
|
||||
Rolf Timmermans <rolftimmermans@voormedia.com>
|
||||
Rolf van de Krol <info@rolfvandekrol.nl>
|
||||
|
@ -27,7 +27,7 @@ please do two things:
|
||||
|
||||
Pull requests will be treated as "review requests", and we will give
|
||||
feedback we expect to see corrected on
|
||||
[style](https://github.com/rust-lang/rust/wiki/Note-style-guide) and
|
||||
[style](http://aturon.github.io/) and
|
||||
substance before pulling. Changes contributed via pull request should
|
||||
focus on a single issue at a time, like any other. We will not accept
|
||||
pull-requests that try to "sneak" unrelated changes in.
|
||||
|
@ -97,10 +97,9 @@
|
||||
# make check-stage1-std RUST_TEST_TASKS=1
|
||||
#
|
||||
# This is hardly all there is to know of The Rust Build System's
|
||||
# mysteries. The tale continues on the wiki[1][2].
|
||||
# mysteries. The tale continues on the wiki[1].
|
||||
#
|
||||
# [1]: https://github.com/rust-lang/rust/wiki/Note-getting-started-developing-Rust
|
||||
# [2]: https://github.com/rust-lang/rust/wiki/Note-testsuite
|
||||
# [1]: https://github.com/rust-lang/rust/wiki/Note-testsuite
|
||||
#
|
||||
# If you really feel like getting your hands dirty, then:
|
||||
#
|
||||
|
15
README.md
15
README.md
@ -58,16 +58,23 @@ documentation.
|
||||
|
||||
### Building on Windows
|
||||
|
||||
To easily build on windows we can use [MSYS2](http://sourceforge.net/projects/msys2/):
|
||||
To easily build on windows we can use [MSYS2](http://msys2.github.io/):
|
||||
|
||||
1. Grab the latest MSYS2 installer and go through the installer.
|
||||
2. Now from the MSYS2 terminal we want to install the mingw64 toolchain and the other
|
||||
tools we need.
|
||||
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ pacman -S base-devel
|
||||
```bash
|
||||
# choose one based on platform
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ pacman -S mingw-w64-x86_64-toolchain
|
||||
|
||||
3. With that now start `mingw32_shell.bat` from where you installed MSYS2 (i.e. `C:\msys`).
|
||||
$ pacman -S base-devel
|
||||
```
|
||||
|
||||
3. With that now start `mingw32_shell.bat` or `mingw64_shell.bat`
|
||||
from where you installed MSYS2 (i.e. `C:\msys`). Which one you
|
||||
choose depends on if you want 32 or 64 bit Rust.
|
||||
4. From there just navigate to where you have Rust's source code, configure and build it:
|
||||
|
||||
$ ./configure
|
||||
|
@ -11,7 +11,7 @@ AR_aarch64-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
|
||||
endif
|
||||
CFG_LIB_NAME_aarch64-apple-ios = lib$(1).a
|
||||
CFG_LIB_GLOB_aarch64-apple-ios = lib$(1)-*.a
|
||||
CFG_LIB_SKIP_INSTALL_aarch64-apple-ios = 1 #lib$(1)-*.a
|
||||
CFG_INSTALL_ONLY_RLIB_aarch64-apple-ios = 1
|
||||
CFG_STATIC_LIB_NAME_aarch64-apple-ios=lib$(1).a
|
||||
CFG_LIB_DSYM_GLOB_aarch64-apple-ios = lib$(1)-*.a.dSYM
|
||||
CFG_CFLAGS_aarch64-apple-ios := $(CFG_IOS_SDK_FLAGS_aarch64-apple-ios)
|
||||
|
@ -11,7 +11,7 @@ AR_armv7-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
|
||||
endif
|
||||
CFG_LIB_NAME_armv7-apple-ios = lib$(1).a
|
||||
CFG_LIB_GLOB_armv7-apple-ios = lib$(1)-*.a
|
||||
CFG_LIB_SKIP_INSTALL_armv7-apple-ios = 1 #lib$(1)-*.a
|
||||
CFG_INSTALL_ONLY_RLIB_armv7-apple-ios = 1
|
||||
CFG_STATIC_LIB_NAME_armv7-apple-ios=lib$(1).a
|
||||
CFG_LIB_DSYM_GLOB_armv7-apple-ios = lib$(1)-*.a.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_armv7-apple-ios := -arch armv7 -mfpu=vfp3 $(CFG_IOS_SDK_FLAGS_armv7-apple-ios)
|
||||
|
@ -11,7 +11,7 @@ AR_armv7s-apple-ios = $(shell xcrun -find -sdk iphoneos ar)
|
||||
endif
|
||||
CFG_LIB_NAME_armv7s-apple-ios = lib$(1).a
|
||||
CFG_LIB_GLOB_armv7s-apple-ios = lib$(1)-*.a
|
||||
CFG_LIB_SKIP_INSTALL_armv7s-apple-ios = 1 #lib$(1)-*.a
|
||||
CFG_INSTALL_ONLY_RLIB_armv7s-apple-ios = 1
|
||||
CFG_STATIC_LIB_NAME_armv7s-apple-ios=lib$(1).a
|
||||
CFG_LIB_DSYM_GLOB_armv7s-apple-ios = lib$(1)-*.a.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_armv7s-apple-ios := -arch armv7s -mfpu=vfp4 $(CFG_IOS_SDK_FLAGS_armv7s-apple-ios)
|
||||
|
@ -11,6 +11,7 @@ AR_i386-apple-ios = $(shell xcrun -find -sdk iphonesimulator ar)
|
||||
endif
|
||||
CFG_LIB_NAME_i386-apple-ios = lib$(1).a
|
||||
CFG_LIB_GLOB_i386-apple-ios = lib$(1)-*.dylib
|
||||
CFG_INSTALL_ONLY_RLIB_i386-apple-ios = 1
|
||||
CFG_STATIC_LIB_NAME_i386-apple-ios=lib$(1).a
|
||||
CFG_LIB_DSYM_GLOB_i386-apple-ios = lib$(1)-*.dylib.dSYM
|
||||
CFG_GCCISH_CFLAGS_i386-apple-ios := -Wall -Werror -g -fPIC -m32 $(CFG_IOSSIM_FLAGS_i386-apple-ios)
|
||||
|
@ -11,7 +11,7 @@ AR_x86_64-apple-ios = $(shell xcrun -find -sdk iphonesimulator ar)
|
||||
endif
|
||||
CFG_LIB_NAME_x86_64-apple-ios = lib$(1).a
|
||||
CFG_LIB_GLOB_x86_64-apple-ios = lib$(1)-*.a
|
||||
CFG_LIB_SKIP_INSTALL_x86_64-apple-ios = 1 #lib$(1)-*.a
|
||||
CFG_INSTALL_ONLY_RLIB_x86_64-apple-ios = 1
|
||||
CFG_STATIC_LIB_NAME_x86_64-apple-ios=lib$(1).a
|
||||
CFG_LIB_DSYM_GLOB_x86_64-apple-ios = lib$(1)-*.a.dSYM
|
||||
CFG_CFLAGS_x86_64-apple-ios := $(CFG_IOSSIM_FLAGS_x86_64-apple-ios)
|
||||
|
@ -18,7 +18,7 @@ CFG_RELEASE_NUM=1.0.0
|
||||
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
||||
# NB Make sure it starts with a dot to conform to semver pre-release
|
||||
# versions (section 9)
|
||||
CFG_PRERELEASE_VERSION=
|
||||
CFG_PRERELEASE_VERSION=.1
|
||||
|
||||
CFG_FILENAME_EXTRA=4e7c5e5c
|
||||
|
||||
@ -30,9 +30,8 @@ CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)
|
||||
CFG_DISABLE_UNSTABLE_FEATURES=1
|
||||
endif
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),beta)
|
||||
# The beta channel is temporarily called 'alpha'
|
||||
CFG_RELEASE=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
|
||||
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-alpha$(CFG_PRERELEASE_VERSION)
|
||||
CFG_RELEASE=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION)
|
||||
CFG_PACKAGE_VERS=$(CFG_RELEASE_NUM)-beta(CFG_PRERELEASE_VERSION)
|
||||
CFG_DISABLE_UNSTABLE_FEATURES=1
|
||||
endif
|
||||
ifeq ($(CFG_RELEASE_CHANNEL),nightly)
|
||||
|
@ -134,7 +134,7 @@ prepare-target-$(2)-host-$(3)-$(1)-$(4): prepare-maybe-clean-$(4) \
|
||||
$$(if $$(findstring $(3), $$(PREPARE_HOST)), \
|
||||
$$(call PREPARE_DIR,$$(PREPARE_WORKING_DEST_LIB_DIR)) \
|
||||
$$(foreach crate,$$(TARGET_CRATES), \
|
||||
$$(if $$(findstring 1, $$(ONLY_RLIB_$$(crate))),, \
|
||||
$$(if $$(or $$(findstring 1, $$(ONLY_RLIB_$$(crate))),$$(findstring 1,$$(CFG_INSTALL_ONLY_RLIB_$(2)))),, \
|
||||
$$(call PREPARE_LIB,$$(call CFG_LIB_GLOB_$(2),$$(crate)))) \
|
||||
$$(call PREPARE_LIB,$$(call CFG_RLIB_GLOB,$$(crate)))) \
|
||||
$$(if $$(findstring $(2),$$(CFG_HOST)), \
|
||||
|
@ -10,7 +10,7 @@ There aren't many large programs yet. The Rust [compiler][rustc], 60,000+ lines
|
||||
|
||||
A research browser engine called [Servo][servo], currently 30,000+ lines across more than a dozen crates, will be exercising a lot of Rust's distinctive type-system and concurrency features, and integrating many native libraries.
|
||||
|
||||
[servo]: https://github.com/mozilla/servo
|
||||
[servo]: https://github.com/servo/servo
|
||||
|
||||
Some examples that demonstrate different aspects of the language:
|
||||
|
||||
|
@ -30,7 +30,7 @@ No. It started as a Graydon Hoare's part-time side project in 2006 and remained
|
||||
|
||||
# What will Mozilla use Rust for?
|
||||
|
||||
Mozilla intends to use Rust as a platform for prototyping experimental browser architectures. Specifically, the hope is to develop a browser that is more amenable to parallelization than existing ones, while also being less prone to common C++ coding errors that result in security exploits. The name of that project is _[Servo](http://github.com/mozilla/servo)_.
|
||||
Mozilla intends to use Rust as a platform for prototyping experimental browser architectures. Specifically, the hope is to develop a browser that is more amenable to parallelization than existing ones, while also being less prone to common C++ coding errors that result in security exploits. The name of that project is _[Servo](http://github.com/servo/servo)_.
|
||||
|
||||
# Why a BSD-style permissive license rather than MPL or tri-license?
|
||||
|
||||
|
@ -5,7 +5,7 @@ accomplishes these goals by being memory safe without using garbage collection.
|
||||
|
||||
This introduction will give you a rough idea of what Rust is like, eliding many
|
||||
details. It does not require prior experience with systems programming, but you
|
||||
may find the syntax easier if you've used a 'curly brace' programming language
|
||||
may find the syntax easier if you've used a "curly brace" programming language
|
||||
before, like C or JavaScript. The concepts are more important than the syntax,
|
||||
so don't worry if you don't get every last detail: you can read [The
|
||||
Rust Programming Language](book/index.html) to get a more complete explanation.
|
||||
@ -15,7 +15,7 @@ Rust to follow along. If you'd like to anyway, check out [the
|
||||
homepage](http://rust-lang.org) for explanation.
|
||||
|
||||
To show off Rust, let's talk about how easy it is to get started with Rust.
|
||||
Then, we'll talk about Rust's most interesting feature, **ownership**, and
|
||||
Then, we'll talk about Rust's most interesting feature, *ownership*, and
|
||||
then discuss how it makes concurrency easier to reason about. Finally,
|
||||
we'll talk about how Rust breaks down the perceived dichotomy between speed
|
||||
and safety.
|
||||
@ -57,7 +57,7 @@ version = "0.0.1"
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
```
|
||||
|
||||
This is called a **manifest**, and it contains all of the metadata that Cargo
|
||||
This is called a *manifest*, and it contains all of the metadata that Cargo
|
||||
needs to compile your project.
|
||||
|
||||
Here's what's in `src/main.rs`:
|
||||
@ -68,7 +68,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Cargo generated a 'hello world' for us. We'll talk more about the syntax here
|
||||
Cargo generated a "Hello World" for us. We'll talk more about the syntax here
|
||||
later, but that's what Rust code looks like! Let's compile and run it:
|
||||
|
||||
```{bash}
|
||||
@ -146,8 +146,8 @@ Enough about tools, let's talk code!
|
||||
|
||||
# Ownership
|
||||
|
||||
Rust's defining feature is 'memory safety without garbage collection.' Let's
|
||||
take a moment to talk about what that means. **Memory safety** means that the
|
||||
Rust's defining feature is "memory safety without garbage collection". Let's
|
||||
take a moment to talk about what that means. *Memory safety* means that the
|
||||
programming language eliminates certain kinds of bugs, such as [buffer
|
||||
overflows](http://en.wikipedia.org/wiki/Buffer_overflow) and [dangling
|
||||
pointers](http://en.wikipedia.org/wiki/Dangling_pointer). These problems occur
|
||||
@ -170,7 +170,7 @@ We make an array, `v`, and then call `push` on it. `push` is a method which
|
||||
adds an element to the end of an array.
|
||||
|
||||
Next, we make a new variable, `x`, that's equal to the first element of
|
||||
the array. Simple, but this is where the 'bug' will appear.
|
||||
the array. Simple, but this is where the "bug" will appear.
|
||||
|
||||
Let's keep going. We then call `push` again, pushing "world" onto the
|
||||
end of the array. `v` now is `["Hello", "world"]`.
|
||||
@ -222,7 +222,7 @@ its length changes, we may need to allocate more memory. In Ruby, this happens
|
||||
as well, we just don't think about it very often. So why does the C++ version
|
||||
segfault when we allocate more memory?
|
||||
|
||||
The answer is that in the C++ version, `x` is a **reference** to the memory
|
||||
The answer is that in the C++ version, `x` is a *reference* to the memory
|
||||
location where the first element of the array is stored. But in Ruby, `x` is a
|
||||
standalone value, not connected to the underyling array at all. Let's dig into
|
||||
the details for a moment. Your program has access to memory, provided to it by
|
||||
@ -332,11 +332,11 @@ error: aborting due to previous error
|
||||
|
||||
When we try to mutate the array by `push`ing it the second time, Rust throws
|
||||
an error. It says that we "cannot borrow v as mutable because it is also
|
||||
borrowed as immutable." What's up with "borrowed"?
|
||||
borrowed as immutable." What does it mean by "borrowed"?
|
||||
|
||||
In Rust, the type system encodes the notion of **ownership**. The variable `v`
|
||||
is an "owner" of the vector. When we make a reference to `v`, we let that
|
||||
variable (in this case, `x`) 'borrow' it for a while. Just like if you own a
|
||||
In Rust, the type system encodes the notion of *ownership*. The variable `v`
|
||||
is an *owner* of the vector. When we make a reference to `v`, we let that
|
||||
variable (in this case, `x`) *borrow* it for a while. Just like if you own a
|
||||
book, and you lend it to me, I'm borrowing the book.
|
||||
|
||||
So, when I try to modify the vector with the second call to `push`, I need
|
||||
@ -392,22 +392,23 @@ Here's an example of a concurrent Rust program:
|
||||
use std::thread::Thread;
|
||||
|
||||
fn main() {
|
||||
for _ in range(0u, 10u) {
|
||||
Thread::spawn(move || {
|
||||
let guards: Vec<_> = (0..10).map(|_| {
|
||||
Thread::scoped(|| {
|
||||
println!("Hello, world!");
|
||||
});
|
||||
}
|
||||
})
|
||||
}).collect();
|
||||
}
|
||||
```
|
||||
|
||||
This program creates ten threads, who all print `Hello, world!`. The
|
||||
`spawn` function takes one argument, a closure, indicated by the
|
||||
double bars `||`. (The `move` keyword indicates that the closure takes
|
||||
ownership of any data it uses; we'll have more on the significance of
|
||||
this shortly.) This closure is executed in a new thread created by
|
||||
`spawn`.
|
||||
This program creates ten threads, which all print `Hello, world!`. The `scoped`
|
||||
function takes one argument, a closure, indicated by the double bars `||`. This
|
||||
closure is executed in a new thread created by `scoped`. The method is called
|
||||
`scoped` because it returns a 'join guard', which will automatically join the
|
||||
child thread when it goes out of scope. Because we `collect` these guards into
|
||||
a `Vec<T>`, and that vector goes out of scope at the end of our program, our
|
||||
program will wait for every thread to finish before finishing.
|
||||
|
||||
One common form of problem in concurrent programs is a 'data race.'
|
||||
One common form of problem in concurrent programs is a *data race*.
|
||||
This occurs when two different threads attempt to access the same
|
||||
location in memory in a non-synchronized way, where at least one of
|
||||
them is a write. If one thread is attempting to read, and one thread
|
||||
@ -460,9 +461,9 @@ code tries to make three owners. This may cause a safety problem, so
|
||||
Rust disallows it.
|
||||
|
||||
What to do here? Rust has two types that helps us: `Arc<T>` and `Mutex<T>`.
|
||||
"Arc" stands for "atomically reference counted." In other words, an Arc will
|
||||
*Arc* stands for "atomically reference counted". In other words, an Arc will
|
||||
keep track of the number of references to something, and not free the
|
||||
associated resource until the count is zero. The 'atomic' portion refers to an
|
||||
associated resource until the count is zero. The *atomic* portion refers to an
|
||||
Arc's usage of concurrency primitives to atomically update the count, making it
|
||||
safe across threads. If we use an Arc, we can have our three references. But,
|
||||
an Arc does not allow mutable borrows of the data it holds, and we want to
|
||||
@ -525,13 +526,13 @@ give us assurance _at compile time_ that we weren't doing something incorrect
|
||||
with regards to concurrency. In order to share ownership, we were forced to be
|
||||
explicit and use a mechanism to ensure that it would be properly handled.
|
||||
|
||||
# Safety _and_ speed
|
||||
# Safety _and_ Speed
|
||||
|
||||
Safety and speed are always presented as a continuum. On one hand, you have
|
||||
maximum speed, but no safety. On the other, you have absolute safety, with no
|
||||
speed. Rust seeks to break out of this mode by introducing safety at compile
|
||||
time, ensuring that you haven't done anything wrong, while compiling to the
|
||||
same low-level code you'd expect without the safety.
|
||||
Safety and speed are always presented as a continuum. At one end of the spectrum,
|
||||
you have maximum speed, but no safety. On the other end, you have absolute safety
|
||||
with no speed. Rust seeks to break out of this paradigm by introducing safety at
|
||||
compile time, ensuring that you haven't done anything wrong, while compiling to
|
||||
the same low-level code you'd expect without the safety.
|
||||
|
||||
As an example, Rust's ownership system is _entirely_ at compile time. The
|
||||
safety check that makes this an error about moved values:
|
||||
|
@ -12,6 +12,7 @@ Looks like you've taken a wrong turn.
|
||||
Some things that might be helpful to you though:
|
||||
|
||||
## Search
|
||||
|
||||
* <form action="https://duckduckgo.com/">
|
||||
<input type="text" id="site-search" name="q" size="80"></input>
|
||||
<input type="submit" value="Search DuckDuckGo">
|
||||
@ -19,10 +20,12 @@ Some things that might be helpful to you though:
|
||||
* Rust doc search: <span id="core-search"></span>
|
||||
|
||||
## Reference
|
||||
|
||||
* [The Rust official site](http://rust-lang.org)
|
||||
* [The Rust reference](http://doc.rust-lang.org/reference.html) (* [PDF](http://doc.rust-lang.org/reference.pdf))
|
||||
* [The Rust reference](http://doc.rust-lang.org/reference.html)
|
||||
|
||||
## Docs
|
||||
|
||||
* [The standard library](http://doc.rust-lang.org/std/)
|
||||
|
||||
<script>
|
||||
|
@ -1588,7 +1588,6 @@ pointer values (pointing to a type for which an implementation of the given
|
||||
trait is in scope) to pointers to the trait name, used as a type.
|
||||
|
||||
```
|
||||
# use std::boxed::Box;
|
||||
# trait Shape { }
|
||||
# impl Shape for int { }
|
||||
# let mycircle = 0i;
|
||||
@ -1647,7 +1646,6 @@ fn radius_times_area<T: Circle>(c: T) -> f64 {
|
||||
Likewise, supertrait methods may also be called on trait objects.
|
||||
|
||||
```{.ignore}
|
||||
# use std::boxed::Box;
|
||||
# trait Shape { fn area(&self) -> f64; }
|
||||
# trait Circle : Shape { fn radius(&self) -> f64; }
|
||||
# impl Shape for int { fn area(&self) -> f64 { 0.0 } }
|
||||
@ -2432,15 +2430,15 @@ There are three different types of inline attributes:
|
||||
* `#[inline(always)]` asks the compiler to always perform an inline expansion.
|
||||
* `#[inline(never)]` asks the compiler to never perform an inline expansion.
|
||||
|
||||
### Deriving
|
||||
### Derive
|
||||
|
||||
The `deriving` attribute allows certain traits to be automatically implemented
|
||||
The `derive` attribute allows certain traits to be automatically implemented
|
||||
for data structures. For example, the following will create an `impl` for the
|
||||
`PartialEq` and `Clone` traits for `Foo`, the type parameter `T` will be given
|
||||
the `PartialEq` or `Clone` constraints for the appropriate `impl`:
|
||||
|
||||
```
|
||||
#[deriving(PartialEq, Clone)]
|
||||
#[derive(PartialEq, Clone)]
|
||||
struct Foo<T> {
|
||||
a: int,
|
||||
b: T
|
||||
@ -2462,7 +2460,7 @@ impl<T: PartialEq> PartialEq for Foo<T> {
|
||||
}
|
||||
```
|
||||
|
||||
Supported traits for `deriving` are:
|
||||
Supported traits for `derive` are:
|
||||
|
||||
* Comparison traits: `PartialEq`, `Eq`, `PartialOrd`, `Ord`.
|
||||
* Serialization: `Encodable`, `Decodable`. These require `serialize`.
|
||||
@ -2967,8 +2965,8 @@ _panicked state_.
|
||||
|
||||
### Unary operator expressions
|
||||
|
||||
Rust defines six symbolic unary operators. They are all written as prefix
|
||||
operators, before the expression they apply to.
|
||||
Rust defines three unary operators. They are all written as prefix operators,
|
||||
before the expression they apply to.
|
||||
|
||||
* `-`
|
||||
: Negation. May only be applied to numeric types.
|
||||
@ -2986,13 +2984,6 @@ operators, before the expression they apply to.
|
||||
: Logical negation. On the boolean type, this flips between `true` and
|
||||
`false`. On integer types, this inverts the individual bits in the
|
||||
two's complement representation of the value.
|
||||
* `box`
|
||||
: [Boxing](#pointer-types) operators. Allocate a box to hold the value they
|
||||
are applied to, and store the value in it. `box` creates a box.
|
||||
* `&`
|
||||
: Borrow operator. Returns a reference, pointing to its operand. The operand
|
||||
of a borrow is statically proven to outlive the resulting pointer. If the
|
||||
borrow-checker cannot prove this, it is a compilation error.
|
||||
|
||||
### Binary operator expressions
|
||||
|
||||
@ -3799,7 +3790,6 @@ enclosing `enum` or `struct` type itself. Such recursion has restrictions:
|
||||
An example of a *recursive* type and its use:
|
||||
|
||||
```
|
||||
# use std::boxed::Box;
|
||||
enum List<T> {
|
||||
Nil,
|
||||
Cons(T, Box<List<T>>)
|
||||
@ -3912,7 +3902,6 @@ implementation of `R`, and the pointer value of `E`.
|
||||
An example of an object type:
|
||||
|
||||
```
|
||||
# use std::boxed::Box;
|
||||
trait Printable {
|
||||
fn stringify(&self) -> String;
|
||||
}
|
||||
@ -4120,7 +4109,6 @@ the type of a box is `std::owned::Box<T>`.
|
||||
An example of a box type and value:
|
||||
|
||||
```
|
||||
# use std::boxed::Box;
|
||||
let x: Box<int> = Box::new(10);
|
||||
```
|
||||
|
||||
@ -4130,7 +4118,6 @@ copy of a box to move ownership of the value. After a value has been moved,
|
||||
the source location cannot be used unless it is reinitialized.
|
||||
|
||||
```
|
||||
# use std::boxed::Box;
|
||||
let x: Box<int> = Box::new(10);
|
||||
let y = x;
|
||||
// attempting to use `x` will result in an error here
|
||||
|
@ -195,6 +195,7 @@ h5 a:hover {text-decoration: none;}
|
||||
|
||||
pre, code {
|
||||
font-family: "Source Code Pro", Menlo, Monaco, Consolas, "DejaVu Sans Mono", monospace;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
pre {
|
||||
border-left: 2px solid #eee;
|
||||
@ -204,7 +205,6 @@ pre {
|
||||
margin: 20px 0;
|
||||
font-size: 13px;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
code {
|
||||
padding: 0 2px;
|
||||
@ -315,6 +315,8 @@ hr {
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
overflow-x: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
table tr.odd {
|
||||
|
@ -198,7 +198,7 @@ Rustdoc also supplies some extra sugar for helping with some tedious
|
||||
documentation examples. If a line is prefixed with `# `, then the line
|
||||
will not show up in the HTML documentation, but it will be used when
|
||||
testing the code block (NB. the space after the `#` is required, so
|
||||
that one can still write things like `#[deriving(Eq)]`).
|
||||
that one can still write things like `#[derive(Eq)]`).
|
||||
|
||||
~~~md
|
||||
```
|
||||
@ -217,6 +217,35 @@ spawn(move || { fib(200); })
|
||||
The documentation online would look like `spawn(move || { fib(200); })`, but when
|
||||
testing this code, the `fib` function will be included (so it can compile).
|
||||
|
||||
Rustdoc will automatically add a `main()` wrapper around your code, and in the right
|
||||
place. For example:
|
||||
|
||||
```
|
||||
/// ```
|
||||
/// use std::rc::Rc;
|
||||
///
|
||||
/// let five = Rc::new(5);
|
||||
/// ```
|
||||
# fn foo() {}
|
||||
```
|
||||
|
||||
This will end up testing:
|
||||
|
||||
```
|
||||
fn main() {
|
||||
use std::rc::Rc;
|
||||
let five = Rc::new(5);
|
||||
}
|
||||
```
|
||||
|
||||
Here's the full algorithm:
|
||||
|
||||
1. Given a code block, if it does not contain `fn main`, it is wrapped in `fn main() { your_code }`
|
||||
2. Given that result, if it contains no `extern crate` directives but it also
|
||||
contains the name of the crate being tested, then `extern crate <name>` is
|
||||
injected at the top.
|
||||
3. Some common `allow` attributes are added for documentation examples at the top.
|
||||
|
||||
## Running tests (advanced)
|
||||
|
||||
Running tests often requires some special configuration to filter tests, find
|
||||
|
@ -8,7 +8,7 @@ memory safe without using garbage collection.
|
||||
"The Rust Programming Language" is split into three sections, which you can
|
||||
navigate through the menu on the left.
|
||||
|
||||
## Basics
|
||||
<h2 class="section-header"><a href="basic.html">Basics</a></h2>
|
||||
|
||||
This section is a linear introduction to the basic syntax and semantics of
|
||||
Rust. It has individual sections on each part of Rust's syntax, and culminates
|
||||
@ -17,7 +17,7 @@ in a small project: a guessing game.
|
||||
After reading "Basics," you will have a good foundation to learn more about
|
||||
Rust, and can write very simple programs.
|
||||
|
||||
## Intermediate
|
||||
<h2 class="section-header"><a href="intermediate.html">Intermediate</a></h2>
|
||||
|
||||
This section contains individual chapters, which are self-contained. They focus
|
||||
on specific topics, and can be read in any order.
|
||||
@ -25,7 +25,7 @@ on specific topics, and can be read in any order.
|
||||
After reading "Intermediate," you will have a solid understanding of Rust,
|
||||
and will be able to understand most Rust code and write more complex programs.
|
||||
|
||||
## Advanced
|
||||
<h2 class="section-header"><a href="advanced.html">Advanced</a></h2>
|
||||
|
||||
In a similar fashion to "Intermediate," this section is full of individual,
|
||||
deep-dive chapters, which stand alone and can be read in any order. These
|
||||
|
@ -26,7 +26,7 @@
|
||||
* [Iterators](iterators.md)
|
||||
* [Generics](generics.md)
|
||||
* [Traits](traits.md)
|
||||
* [Tasks](tasks.md)
|
||||
* [Threads](threads.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [III: Advanced Topics](advanced.md)
|
||||
* [FFI](ffi.md)
|
||||
|
@ -82,7 +82,7 @@ arrays:
|
||||
|
||||
```{rust}
|
||||
let a = [0, 1, 2, 3, 4];
|
||||
let middle = a.slice(1, 4); // A slice of a: just the elements [1,2,3]
|
||||
let middle = &a[1..4]; // A slice of a: just the elements 1, 2, and 3
|
||||
|
||||
for e in middle.iter() {
|
||||
println!("{}", e); // Prints 1, 2, 3
|
||||
|
@ -51,7 +51,7 @@ defined. The closure borrows any variables it uses, so this will error:
|
||||
|
||||
```{rust,ignore}
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
let mut x: i32 = 5;
|
||||
|
||||
let printer = |&:| { println!("x is: {}", x); };
|
||||
|
||||
|
@ -182,7 +182,7 @@ and with a struct, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that's a
|
||||
tuple struct with only one element. We call this a *newtype*, because it lets
|
||||
you create a new type that's a synonym for another one:
|
||||
you create a new type that's similar to another one:
|
||||
|
||||
```{rust}
|
||||
struct Inches(i32);
|
||||
@ -194,7 +194,8 @@ println!("length is {} inches", integer_length);
|
||||
```
|
||||
|
||||
As you can see here, you can extract the inner integer type through a
|
||||
destructuring `let`.
|
||||
destructuring `let`, as we discussed previously in 'tuples.' In this case, the
|
||||
`let Inches(integer_length)` assigns `10` to `integer_length`.
|
||||
|
||||
## Enums
|
||||
|
||||
|
@ -181,7 +181,7 @@ errors that can occur.
|
||||
# Non-recoverable errors with `panic!`
|
||||
|
||||
In the case of an error that is unexpected and not recoverable, the `panic!`
|
||||
macro will induce a panic. This will crash the current task, and give an error:
|
||||
macro will induce a panic. This will crash the current thread, and give an error:
|
||||
|
||||
```{rust,ignore}
|
||||
panic!("boom");
|
||||
@ -190,7 +190,7 @@ panic!("boom");
|
||||
gives
|
||||
|
||||
```text
|
||||
task '<main>' panicked at 'boom', hello.rs:2
|
||||
thread '<main>' panicked at 'boom', hello.rs:2
|
||||
```
|
||||
|
||||
when you run it.
|
||||
|
@ -166,12 +166,12 @@ GitHub](https://github.com/thestinger/rust-snappy).
|
||||
|
||||
# Stack management
|
||||
|
||||
Rust tasks by default run on a *large stack*. This is actually implemented as a
|
||||
Rust threads by default run on a *large stack*. This is actually implemented as a
|
||||
reserving a large segment of the address space and then lazily mapping in pages
|
||||
as they are needed. When calling an external C function, the code is invoked on
|
||||
the same stack as the rust stack. This means that there is no extra
|
||||
stack-switching mechanism in place because it is assumed that the large stack
|
||||
for the rust task is plenty for the C function to have.
|
||||
for the rust thread is plenty for the C function to have.
|
||||
|
||||
A planned future improvement (not yet implemented at the time of this writing)
|
||||
is to have a guard page at the end of every rust stack. No rust function will
|
||||
@ -184,8 +184,8 @@ For normal external function usage, this all means that there shouldn't be any
|
||||
need for any extra effort on a user's perspective. The C stack naturally
|
||||
interleaves with the rust stack, and it's "large enough" for both to
|
||||
interoperate. If, however, it is determined that a larger stack is necessary,
|
||||
there are appropriate functions in the task spawning API to control the size of
|
||||
the stack of the task which is spawned.
|
||||
there are appropriate functions in the thread spawning API to control the size of
|
||||
the stack of the thread which is spawned.
|
||||
|
||||
# Destructors
|
||||
|
||||
@ -262,8 +262,6 @@ referenced Rust object.
|
||||
Rust code:
|
||||
|
||||
~~~~no_run
|
||||
# use std::boxed::Box;
|
||||
|
||||
#[repr(C)]
|
||||
struct RustObject {
|
||||
a: i32,
|
||||
@ -320,8 +318,7 @@ In the previously given examples the callbacks are invoked as a direct reaction
|
||||
to a function call to the external C library.
|
||||
The control over the current thread is switched from Rust to C to Rust for the
|
||||
execution of the callback, but in the end the callback is executed on the
|
||||
same thread (and Rust task) that lead called the function which triggered
|
||||
the callback.
|
||||
same thread that called the function which triggered the callback.
|
||||
|
||||
Things get more complicated when the external library spawns its own threads
|
||||
and invokes callbacks from there.
|
||||
@ -329,7 +326,7 @@ In these cases access to Rust data structures inside the callbacks is
|
||||
especially unsafe and proper synchronization mechanisms must be used.
|
||||
Besides classical synchronization mechanisms like mutexes, one possibility in
|
||||
Rust is to use channels (in `std::comm`) to forward data from the C thread
|
||||
that invoked the callback into a Rust task.
|
||||
that invoked the callback into a Rust thread.
|
||||
|
||||
If an asynchronous callback targets a special object in the Rust address space
|
||||
it is also absolutely necessary that no more callbacks are performed by the
|
||||
|
@ -142,5 +142,23 @@ fn foo(x: i32) -> i32 {
|
||||
}
|
||||
```
|
||||
|
||||
The previous definition without `return` may look a bit strange if you haven't
|
||||
worked in an expression-based language before, but it becomes intutive over
|
||||
time. If this were production code, we wouldn't write it in that way anyway,
|
||||
we'd write this:
|
||||
|
||||
```rust
|
||||
fn foo(x: i32) -> i32 {
|
||||
if x < 5 {
|
||||
x
|
||||
} else {
|
||||
x + 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Because `if` is an expression, and it's the only expression in this function,
|
||||
the value will be the result of the `if`.
|
||||
|
||||
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.
|
||||
|
@ -88,9 +88,9 @@ enum Result<H, N> {
|
||||
if we wanted to. Convention says that the first generic parameter should be
|
||||
`T`, for 'type,' and that we use `E` for 'error.' Rust doesn't care, however.
|
||||
|
||||
The `Result<T, E>` type is intended to
|
||||
be used to return the result of a computation, and to have the ability to
|
||||
return an error if it didn't work out. Here's an example:
|
||||
The `Result<T, E>` type is intended to be used to return the result of a
|
||||
computation, and to have the ability to return an error if it didn't work out.
|
||||
Here's an example:
|
||||
|
||||
```{rust}
|
||||
let x: Result<f64, String> = Ok(2.3f64);
|
||||
|
@ -239,7 +239,7 @@ use std::rand;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -283,7 +283,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -318,7 +318,7 @@ $ cargo build
|
||||
src/main.rs:20:15: 20:20 error: mismatched types: expected `i32` but found `collections::string::String` (expected i32 but found struct collections::string::String)
|
||||
src/main.rs:20 match cmp(input, secret_number) {
|
||||
^~~~~
|
||||
src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `uint` (expected i32 but found uint)
|
||||
src/main.rs:20:22: 20:35 error: mismatched types: expected `i32` but found `u32` (expected i32 but found u32)
|
||||
src/main.rs:20 match cmp(input, secret_number) {
|
||||
^~~~~~~~~~~~~
|
||||
error: aborting due to 2 previous errors
|
||||
@ -328,7 +328,7 @@ This often happens when writing Rust programs, and is one of Rust's greatest
|
||||
strengths. You try out some code, see if it compiles, and Rust tells you that
|
||||
you've done something wrong. In this case, our `cmp` function works on integers,
|
||||
but we've given it unsigned integers. In this case, the fix is easy, because
|
||||
we wrote the `cmp` function! Let's change it to take `uint`s:
|
||||
we wrote the `cmp` function! Let's change it to take `u32`s:
|
||||
|
||||
```{rust,ignore}
|
||||
use std::io;
|
||||
@ -338,7 +338,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -358,7 +358,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
@ -370,13 +370,13 @@ And try compiling again:
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:20:15: 20:20 error: mismatched types: expected `uint` but found `collections::string::String` (expected uint but found struct collections::string::String)
|
||||
src/main.rs:20:15: 20:20 error: mismatched types: expected `u32` but found `collections::string::String` (expected u32 but found struct collections::string::String)
|
||||
src/main.rs:20 match cmp(input, secret_number) {
|
||||
^~~~~
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
This error is similar to the last one: we expected to get a `uint`, but we got
|
||||
This error is similar to the last one: we expected to get a `u32`, but we got
|
||||
a `String` instead! That's because our `input` variable is coming from the
|
||||
standard input, and you can guess anything. Try it:
|
||||
|
||||
@ -393,14 +393,14 @@ Oops! Also, you'll note that we just ran our program even though it didn't compi
|
||||
This works because the older version we did successfully compile was still lying
|
||||
around. Gotta be careful!
|
||||
|
||||
Anyway, we have a `String`, but we need a `uint`. What to do? Well, there's
|
||||
Anyway, we have a `String`, but we need a `u32`. What to do? Well, there's
|
||||
a function for that:
|
||||
|
||||
```{rust,ignore}
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.parse();
|
||||
let input_num: Option<u32> = input.parse();
|
||||
```
|
||||
|
||||
The `parse` function takes in a `&str` value and converts it into something.
|
||||
@ -408,22 +408,22 @@ We tell it what kind of something with a type hint. Remember our type hint with
|
||||
`random()`? It looked like this:
|
||||
|
||||
```{rust,ignore}
|
||||
rand::random::<uint>();
|
||||
rand::random::<u32>();
|
||||
```
|
||||
|
||||
There's an alternate way of providing a hint too, and that's declaring the type
|
||||
in a `let`:
|
||||
|
||||
```{rust,ignore}
|
||||
let x: uint = rand::random();
|
||||
let x: u32 = rand::random();
|
||||
```
|
||||
|
||||
In this case, we say `x` is a `uint` explicitly, so Rust is able to properly
|
||||
In this case, we say `x` is a `u32` explicitly, so Rust is able to properly
|
||||
tell `random()` what to generate. In a similar fashion, both of these work:
|
||||
|
||||
```{rust,ignore}
|
||||
let input_num = "5".parse::<uint>(); // input_num: Option<uint>
|
||||
let input_num: Option<uint> = "5".parse(); // input_num: Option<uint>
|
||||
let input_num = "5".parse::<u32>(); // input_num: Option<u32>
|
||||
let input_num: Option<u32> = "5".parse(); // input_num: Option<u32>
|
||||
```
|
||||
|
||||
Anyway, with us now converting our input to a number, our code looks like this:
|
||||
@ -436,7 +436,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -445,7 +445,7 @@ fn main() {
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.parse();
|
||||
let input_num: Option<u32> = input.parse();
|
||||
|
||||
println!("You guessed: {}", input_num);
|
||||
|
||||
@ -456,7 +456,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
@ -468,13 +468,13 @@ Let's try it out!
|
||||
```bash
|
||||
$ cargo build
|
||||
Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
|
||||
src/main.rs:22:15: 22:24 error: mismatched types: expected `uint` but found `core::option::Option<uint>` (expected uint but found enum core::option::Option)
|
||||
src/main.rs:22:15: 22:24 error: mismatched types: expected `u32` but found `core::option::Option<u32>` (expected u32 but found enum core::option::Option)
|
||||
src/main.rs:22 match cmp(input_num, secret_number) {
|
||||
^~~~~~~~~
|
||||
error: aborting due to previous error
|
||||
```
|
||||
|
||||
Oh yeah! Our `input_num` has the type `Option<uint>`, rather than `uint`. We
|
||||
Oh yeah! Our `input_num` has the type `Option<u32>`, rather than `u32`. We
|
||||
need to unwrap the Option. If you remember from before, `match` is a great way
|
||||
to do that. Try this code:
|
||||
|
||||
@ -486,7 +486,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -495,7 +495,7 @@ fn main() {
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.parse();
|
||||
let input_num: Option<u32> = input.parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
@ -515,14 +515,14 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
}
|
||||
```
|
||||
|
||||
We use a `match` to either give us the `uint` inside of the `Option`, or else
|
||||
We use a `match` to either give us the `u32` inside of the `Option`, or else
|
||||
print an error message and return. Let's give this a shot:
|
||||
|
||||
```bash
|
||||
@ -553,7 +553,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -562,7 +562,7 @@ fn main() {
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
let input_num: Option<u32> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
@ -582,7 +582,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
@ -627,7 +627,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -638,7 +638,7 @@ fn main() {
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
let input_num: Option<u32> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
@ -659,7 +659,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
@ -703,7 +703,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -714,7 +714,7 @@ fn main() {
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
let input_num: Option<u32> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
@ -738,7 +738,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
@ -759,7 +759,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
println!("The secret number is: {}", secret_number);
|
||||
|
||||
@ -770,7 +770,7 @@ fn main() {
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
let input_num: Option<u32> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
@ -794,7 +794,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
@ -838,7 +838,7 @@ use std::cmp::Ordering;
|
||||
fn main() {
|
||||
println!("Guess the number!");
|
||||
|
||||
let secret_number = (rand::random::<uint>() % 100u) + 1u;
|
||||
let secret_number = (rand::random::<u32>() % 100) + 1;
|
||||
|
||||
loop {
|
||||
|
||||
@ -847,7 +847,7 @@ fn main() {
|
||||
let input = io::stdin().read_line()
|
||||
.ok()
|
||||
.expect("Failed to read line");
|
||||
let input_num: Option<uint> = input.trim().parse();
|
||||
let input_num: Option<u32> = input.trim().parse();
|
||||
|
||||
let num = match input_num {
|
||||
Some(num) => num,
|
||||
@ -871,7 +871,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(a: uint, b: uint) -> Ordering {
|
||||
fn cmp(a: u32, b: u32) -> Ordering {
|
||||
if a < b { Ordering::Less }
|
||||
else if a > b { Ordering::Greater }
|
||||
else { Ordering::Equal }
|
||||
|
@ -71,8 +71,8 @@ These lines define a *function* in Rust. The `main` function is special:
|
||||
it's the beginning of every Rust program. The first line says "I'm declaring a
|
||||
function named `main`, which takes no arguments and returns nothing." If there
|
||||
were arguments, they would go inside the parentheses (`(` and `)`), and because
|
||||
we aren't returning anything from this function, we've dropped that notation
|
||||
entirely. We'll get to it later.
|
||||
we aren't returning anything from this function, we can omit the return type
|
||||
entirely. We'll get to it later.
|
||||
|
||||
You'll also note that the function is wrapped in curly braces (`{` and `}`).
|
||||
Rust requires these around all function bodies. It is also considered good
|
||||
|
@ -42,7 +42,7 @@ the pattern in the above code:
|
||||
# let input_1 = T::SpecialA(0);
|
||||
# let input_2 = T::SpecialA(0);
|
||||
macro_rules! early_return {
|
||||
($inp:expr, $sp:path) => ( // invoke it like `(input_5 SpecialE)`
|
||||
($inp:expr, $sp:path) => ( // invoke it like `(input_5, SpecialE)`
|
||||
match $inp {
|
||||
$sp(x) => { return x; }
|
||||
_ => {}
|
||||
@ -59,7 +59,7 @@ early_return!(input_2, T::SpecialB);
|
||||
~~~~
|
||||
|
||||
Macros are defined in pattern-matching style: in the above example, the text
|
||||
`($inp:expr $sp:ident)` that appears on the left-hand side of the `=>` is the
|
||||
`($inp:expr, $sp:path)` that appears on the left-hand side of the `=>` is the
|
||||
*macro invocation syntax*, a pattern denoting how to write a call to the
|
||||
macro. The text on the right-hand side of the `=>`, beginning with `match
|
||||
$inp`, is the *macro transcription syntax*: what the macro expands to.
|
||||
@ -74,6 +74,8 @@ conforms to the following rules:
|
||||
2. `$` has special meaning (described below).
|
||||
3. The `()`s, `[]`s, and `{}`s it contains must balance. For example, `([)` is
|
||||
forbidden.
|
||||
4. Some arguments can be followed only by a limited set of separators, to
|
||||
avoid ambiguity (described below).
|
||||
|
||||
Otherwise, the invocation syntax is free-form.
|
||||
|
||||
@ -86,7 +88,8 @@ To take a fragment of Rust code as an argument, write `$` followed by a name
|
||||
`foo`.)
|
||||
* `expr` (an expression. Examples: `2 + 2`; `if true then { 1 } else { 2 }`;
|
||||
`f(42)`.)
|
||||
* `ty` (a type. Examples: `int`, `Vec<(char, String)>`, `&T`.)
|
||||
* `ty` (a type. Examples: `i32`, `Vec<(char, String)>`, `&T`.)
|
||||
* `path` (a path to struct or enum variant. Example: `T::SpecialA`)
|
||||
* `pat` (a pattern, usually appearing in a `match` or on the left-hand side of
|
||||
a declaration. Examples: `Some(t)`; `(17, 'a')`; `_`.)
|
||||
* `block` (a sequence of actions. Example: `{ log(error, "hi"); return 12; }`)
|
||||
@ -97,6 +100,12 @@ rules of tokenization apply,
|
||||
So `($x:ident -> (($e:expr)))`, though excessively fancy, would designate a macro
|
||||
that could be invoked like: `my_macro!(i->(( 2+2 )))`.
|
||||
|
||||
To avoid ambiguity, macro invocation syntax must conform to the following rules:
|
||||
* `expr` must be followed by `=>`, `,` or `;`.
|
||||
* `ty` and `path` must be followed by `=>`, `,`, `:`, `=`, `>` or `as`.
|
||||
* `pat` must be followed by `=>`, `,` or `=`.
|
||||
* `ident` and `block` can be followed by any token.
|
||||
|
||||
## Invocation location
|
||||
|
||||
A macro invocation may take the place of (and therefore expand to) an
|
||||
@ -571,7 +580,7 @@ intermediate states out, and passing the flag `--pretty expanded` as a
|
||||
command-line argument to the compiler will show the result of expansion.
|
||||
|
||||
If Rust's macro system can't do what you need, you may want to write a
|
||||
[compiler plugin](plugin.html) instead. Compared to `macro_rules!`
|
||||
[compiler plugin](plugins.html) instead. Compared to `macro_rules!`
|
||||
macros, this is significantly more work, the interfaces are much less stable,
|
||||
and the warnings about debugging apply ten-fold. In exchange you get the
|
||||
flexibility of running arbitrary Rust code within the compiler. Syntax
|
||||
|
@ -81,7 +81,6 @@ therefore deallocates the memory for you. Here's the equivalent example in
|
||||
Rust:
|
||||
|
||||
```rust
|
||||
# use std::boxed::Box;
|
||||
{
|
||||
let x = Box::new(5);
|
||||
}
|
||||
@ -101,7 +100,6 @@ This is pretty straightforward, but what happens when we want to pass our box
|
||||
to a function? Let's look at some code:
|
||||
|
||||
```rust
|
||||
# use std::boxed::Box;
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
@ -117,7 +115,6 @@ This code works, but it's not ideal. For example, let's add one more line of
|
||||
code, where we print out the value of `x`:
|
||||
|
||||
```{rust,ignore}
|
||||
# use std::boxed::Box;
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
@ -151,7 +148,6 @@ To fix this, we can have `add_one` give ownership back when it's done with the
|
||||
box:
|
||||
|
||||
```rust
|
||||
# use std::boxed::Box;
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
|
||||
@ -207,6 +203,26 @@ fn add_one(num: &mut i32) {
|
||||
This function borrows an `i32` from its caller, and then increments it. When
|
||||
the function is over, and `num` goes out of scope, the borrow is over.
|
||||
|
||||
We have to change our `main` a bit too:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let mut x = 5;
|
||||
|
||||
add_one(&mut x);
|
||||
|
||||
println!("{}", x);
|
||||
}
|
||||
|
||||
fn add_one(num: &mut i32) {
|
||||
*num += 1;
|
||||
}
|
||||
```
|
||||
|
||||
We don't need to assign the result of `add_one()` anymore, because it doesn't
|
||||
return anything anymore. This is because we're not passing ownership back,
|
||||
since we just borrow, not take ownership.
|
||||
|
||||
# Lifetimes
|
||||
|
||||
Lending out a reference to a resource that someone else owns can be
|
||||
@ -225,7 +241,7 @@ To fix this, we have to make sure that step four never happens after step
|
||||
three. The ownership system in Rust does this through a concept called
|
||||
*lifetimes*, which describe the scope that a reference is valid for.
|
||||
|
||||
Let's look at that function which borrows an `i32` again:
|
||||
Remember the function that borrowed an `i32`? Let's look at it again.
|
||||
|
||||
```rust
|
||||
fn add_one(num: &i32) -> i32 {
|
||||
|
@ -126,7 +126,7 @@ The advantages over a simple `fn(&str) -> uint` are:
|
||||
a way to define new literal syntax for any data type.
|
||||
|
||||
In addition to procedural macros, you can define new
|
||||
[`deriving`](../reference.html#deriving)-like attributes and other kinds of
|
||||
[`derive`](../reference.html#derive)-like attributes and other kinds of
|
||||
extensions. See
|
||||
[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
|
||||
and the [`SyntaxExtension`
|
||||
|
@ -455,7 +455,6 @@ fn rc_succ(x: Rc<int>) -> int { *x + 1 }
|
||||
Note that the caller of your function will have to modify their calls slightly:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
use std::rc::Rc;
|
||||
|
||||
fn succ(x: &int) -> int { *x + 1 }
|
||||
@ -478,7 +477,6 @@ those contents.
|
||||
heap allocation in Rust. Creating a box looks like this:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
let x = Box::new(5i);
|
||||
```
|
||||
|
||||
@ -486,7 +484,6 @@ Boxes are heap allocated and they are deallocated automatically by Rust when
|
||||
they go out of scope:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
{
|
||||
let x = Box::new(5i);
|
||||
|
||||
@ -507,7 +504,6 @@ You don't need to fully grok the theory of affine types or regions to grok
|
||||
boxes, though. As a rough approximation, you can treat this Rust code:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
{
|
||||
let x = Box::new(5i);
|
||||
|
||||
@ -548,7 +544,6 @@ for more detail on how lifetimes work.
|
||||
Using boxes and references together is very common. For example:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
fn add_one(x: &int) -> int {
|
||||
*x + 1
|
||||
}
|
||||
@ -566,7 +561,6 @@ function, and since it's only reading the value, allows it.
|
||||
We can borrow `x` multiple times, as long as it's not simultaneous:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
fn add_one(x: &int) -> int {
|
||||
*x + 1
|
||||
}
|
||||
@ -583,7 +577,6 @@ fn main() {
|
||||
Or as long as it's not a mutable borrow. This will error:
|
||||
|
||||
```{rust,ignore}
|
||||
# use std::boxed::Box;
|
||||
fn add_one(x: &mut int) -> int {
|
||||
*x + 1
|
||||
}
|
||||
@ -610,7 +603,6 @@ Sometimes, you need a recursive data structure. The simplest is known as a
|
||||
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
#[derive(Show)]
|
||||
enum List<T> {
|
||||
Cons(T, Box<List<T>>),
|
||||
@ -666,7 +658,6 @@ In many languages with pointers, you'd return a pointer from a function
|
||||
so as to avoid copying a large data structure. For example:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
struct BigStruct {
|
||||
one: int,
|
||||
two: int,
|
||||
@ -695,7 +686,6 @@ than the hundred `int`s that make up the `BigStruct`.
|
||||
This is an antipattern in Rust. Instead, write this:
|
||||
|
||||
```{rust}
|
||||
# use std::boxed::Box;
|
||||
struct BigStruct {
|
||||
one: int,
|
||||
two: int,
|
||||
@ -721,11 +711,10 @@ fn main() {
|
||||
This gives you flexibility without sacrificing performance.
|
||||
|
||||
You may think that this gives us terrible performance: return a value and then
|
||||
immediately box it up ?! Isn't that the worst of both worlds? Rust is smarter
|
||||
than that. There is no copy in this code. `main` allocates enough room for the
|
||||
`box`, passes a pointer to that memory into `foo` as `x`, and then `foo` writes
|
||||
the value straight into that pointer. This writes the return value directly into
|
||||
the allocated box.
|
||||
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
|
||||
smarter than that. There is no copy in this code. `main` allocates enough room
|
||||
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
|
||||
`foo` writes the value straight into the `Box<T>`.
|
||||
|
||||
This is important enough that it bears repeating: pointers are not for
|
||||
optimizing returning values from your code. Allow the caller to choose how they
|
||||
|
@ -96,7 +96,7 @@ test it_works ... FAILED
|
||||
failures:
|
||||
|
||||
---- it_works stdout ----
|
||||
task 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
|
||||
thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
|
||||
|
||||
|
||||
|
||||
@ -105,7 +105,7 @@ failures:
|
||||
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
|
||||
|
||||
task '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
|
||||
thread '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
|
||||
```
|
||||
|
||||
Rust indicates that our test failed:
|
||||
@ -254,7 +254,6 @@ a large module, and so this is a common use of the `glob` feature. Let's change
|
||||
our `src/lib.rs` to make use of it:
|
||||
|
||||
```{rust,ignore}
|
||||
#![feature(globs)]
|
||||
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
a + 2
|
||||
@ -271,8 +270,7 @@ mod tests {
|
||||
}
|
||||
```
|
||||
|
||||
Note the `feature` attribute, as well as the different `use` line. Now we run
|
||||
our tests:
|
||||
Note the different `use` line. Now we run our tests:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
@ -370,8 +368,6 @@ with examples:
|
||||
//! assert_eq!(4, adder::add_two(2));
|
||||
//! ```
|
||||
|
||||
#![feature(globs)]
|
||||
|
||||
/// This function adds two to its argument.
|
||||
///
|
||||
/// # Examples
|
||||
@ -440,8 +436,6 @@ Rust also supports benchmark tests, which can test the performance of your
|
||||
code. Let's make our `src/lib.rs` look like this (comments elided):
|
||||
|
||||
```{rust,ignore}
|
||||
#![feature(globs)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
pub fn add_two(a: i32) -> i32 {
|
||||
|
@ -315,3 +315,76 @@ The names don't actually change to this, it's just for illustration. But
|
||||
as you can see, there's no overhead of deciding which version to call here,
|
||||
hence *statically dispatched*. The downside is that we have two copies of
|
||||
the same function, so our binary is a little bit larger.
|
||||
|
||||
## Our `inverse` Example
|
||||
|
||||
Back in [Generics](generics.html), we were trying to write code like this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn inverse<T>(x: T) -> Result<T, String> {
|
||||
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
|
||||
|
||||
Ok(1.0 / x)
|
||||
}
|
||||
```
|
||||
|
||||
If we try to compile it, we get this error:
|
||||
|
||||
```text
|
||||
error: binary operation `==` cannot be applied to type `T`
|
||||
```
|
||||
|
||||
This is because `T` is too generic: we don't know if a random `T` can be
|
||||
compared. For that, we can use trait bounds. It doesn't quite work, but try
|
||||
this:
|
||||
|
||||
```{rust,ignore}
|
||||
fn inverse<T: PartialEq>(x: T) -> Result<T, String> {
|
||||
if x == 0.0 { return Err("x cannot be zero!".to_string()); }
|
||||
|
||||
Ok(1.0 / x)
|
||||
}
|
||||
```
|
||||
|
||||
You should get this error:
|
||||
|
||||
```text
|
||||
error: mismatched types:
|
||||
expected `T`,
|
||||
found `_`
|
||||
(expected type parameter,
|
||||
found floating-point variable)
|
||||
```
|
||||
|
||||
So this won't work. While our `T` is `PartialEq`, we expected to have another `T`,
|
||||
but instead, we found a floating-point variable. We need a different bound. `Float`
|
||||
to the rescue:
|
||||
|
||||
```
|
||||
use std::num::Float;
|
||||
|
||||
fn inverse<T: Float>(x: T) -> Result<T, String> {
|
||||
if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
|
||||
|
||||
let one: T = Float::one();
|
||||
Ok(one / x)
|
||||
}
|
||||
```
|
||||
|
||||
We've had to replace our generic `0.0` and `1.0` with the appropriate methods
|
||||
from the `Float` trait. Both `f32` and `f64` implement `Float`, so our function
|
||||
works just fine:
|
||||
|
||||
```
|
||||
# use std::num::Float;
|
||||
# fn inverse<T: Float>(x: T) -> Result<T, String> {
|
||||
# if x == Float::zero() { return Err("x cannot be zero!".to_string()) }
|
||||
# let one: T = Float::one();
|
||||
# Ok(one / x)
|
||||
# }
|
||||
println!("the inverse of {} is {:?}", 2.0f32, inverse(2.0f32));
|
||||
println!("the inverse of {} is {:?}", 2.0f64, inverse(2.0f64));
|
||||
|
||||
println!("the inverse of {} is {:?}", 0.0f32, inverse(0.0f32));
|
||||
println!("the inverse of {} is {:?}", 0.0f64, inverse(0.0f64));
|
||||
```
|
||||
|
@ -182,7 +182,7 @@ code:
|
||||
- implement the `Drop` for resource clean-up via a destructor, and use
|
||||
RAII (Resource Acquisition Is Initialization). This reduces the need
|
||||
for any manual memory management by users, and automatically ensures
|
||||
that clean-up is always run, even when the task panics.
|
||||
that clean-up is always run, even when the thread panics.
|
||||
- ensure that any data stored behind a raw pointer is destroyed at the
|
||||
appropriate time.
|
||||
|
||||
@ -197,7 +197,6 @@ extern crate libc;
|
||||
use libc::{c_void, size_t, malloc, free};
|
||||
use std::mem;
|
||||
use std::ptr;
|
||||
# use std::boxed::Box;
|
||||
|
||||
// Define a wrapper around the handle returned by the foreign code.
|
||||
// Unique<T> has the same semantics as Box<T>
|
||||
@ -499,7 +498,7 @@ library, but without it you must define your own.
|
||||
The first of these three functions, `stack_exhausted`, is invoked whenever stack
|
||||
overflow is detected. This function has a number of restrictions about how it
|
||||
can be called and what it must do, but if the stack limit register is not being
|
||||
maintained then a task always has an "infinite stack" and this function
|
||||
maintained then a thread always has an "infinite stack" and this function
|
||||
shouldn't get triggered.
|
||||
|
||||
The second of these three functions, `eh_personality`, is used by the
|
||||
@ -530,7 +529,6 @@ vectors provided from C, using idiomatic Rust practices.
|
||||
|
||||
```
|
||||
#![no_std]
|
||||
#![feature(globs)]
|
||||
#![feature(lang_items)]
|
||||
|
||||
# extern crate libc;
|
||||
|
@ -89,25 +89,7 @@ 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 them. If we try...
|
||||
|
||||
```{ignore}
|
||||
let x;
|
||||
```
|
||||
|
||||
...we'll get an error:
|
||||
|
||||
```text
|
||||
src/main.rs:2:9: 2:10 error: unable to infer enough type information about `_`; type annotations required
|
||||
src/main.rs:2 let x;
|
||||
^
|
||||
```
|
||||
|
||||
Giving it a type will compile, though:
|
||||
|
||||
```{rust}
|
||||
let x: i32;
|
||||
```
|
||||
value before you're allowed to use them.
|
||||
|
||||
Let's try it out. Change your `src/main.rs` file to look like this:
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
% The Rust Tutorial
|
||||
|
||||
This tutorial has been deprecated in favor of [the Guide](guide.html). Go check that out instead!
|
||||
This tutorial has been deprecated in favor of [the Book](book/index.html). Go check that out instead!
|
||||
|
@ -194,8 +194,13 @@ LIT_STR_RAW
|
||||
: 'r' LIT_STR_RAW_INNER SUFFIX?
|
||||
;
|
||||
|
||||
|
||||
QUESTION : '?';
|
||||
|
||||
IDENT : XID_start XID_continue* ;
|
||||
|
||||
fragment QUESTION_IDENTIFIER : QUESTION? IDENT;
|
||||
|
||||
LIFETIME : '\'' IDENT ;
|
||||
|
||||
WHITESPACE : [ \r\n\t]+ ;
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(globs, plugin)]
|
||||
#![feature(plugin)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate rustc;
|
||||
@ -107,13 +107,14 @@ fn parse_token_list(file: &str) -> HashMap<String, token::Token> {
|
||||
"LE" => token::Le,
|
||||
"LIT_BINARY" => token::Literal(token::Binary(Name(0)), None),
|
||||
"LIT_BINARY_RAW" => token::Literal(token::BinaryRaw(Name(0), 0), None),
|
||||
"QUESTION" => token::Question,
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
res.insert(num.to_string(), tok);
|
||||
}
|
||||
|
||||
debug!("Token map: {}", res);
|
||||
debug!("Token map: {:?}", res);
|
||||
res
|
||||
}
|
||||
|
||||
@ -161,7 +162,7 @@ fn fixchar(mut lit: &str) -> ast::Name {
|
||||
parse::token::intern(lit.slice(1, lit.len() - 1))
|
||||
}
|
||||
|
||||
fn count(lit: &str) -> uint {
|
||||
fn count(lit: &str) -> usize {
|
||||
lit.chars().take_while(|c| *c == '#').count()
|
||||
}
|
||||
|
||||
@ -176,12 +177,12 @@ fn parse_antlr_token(s: &str, tokens: &HashMap<String, token::Token>) -> TokenAn
|
||||
let toknum = m.name("toknum").unwrap_or("");
|
||||
let content = m.name("content").unwrap_or("");
|
||||
|
||||
let proto_tok = tokens.get(toknum).expect(format!("didn't find token {} in the map",
|
||||
let proto_tok = tokens.get(toknum).expect(format!("didn't find token {:?} in the map",
|
||||
toknum).as_slice());
|
||||
|
||||
let nm = parse::token::intern(content);
|
||||
|
||||
debug!("What we got: content (`{}`), proto: {}", content, proto_tok);
|
||||
debug!("What we got: content (`{}`), proto: {:?}", content, proto_tok);
|
||||
|
||||
let real_tok = match *proto_tok {
|
||||
token::BinOp(..) => token::BinOp(str_to_binop(content)),
|
||||
@ -265,7 +266,7 @@ fn main() {
|
||||
continue
|
||||
}
|
||||
|
||||
assert!(rustc_tok.sp == antlr_tok.sp, "{} and {} have different spans", rustc_tok,
|
||||
assert!(rustc_tok.sp == antlr_tok.sp, "{:?} and {:?} have different spans", rustc_tok,
|
||||
antlr_tok);
|
||||
|
||||
macro_rules! matches {
|
||||
@ -276,12 +277,12 @@ fn main() {
|
||||
if !tok_cmp(&rustc_tok.tok, &antlr_tok.tok) {
|
||||
// FIXME #15677: needs more robust escaping in
|
||||
// antlr
|
||||
warn!("Different names for {} and {}", rustc_tok, antlr_tok);
|
||||
warn!("Different names for {:?} and {:?}", rustc_tok, antlr_tok);
|
||||
}
|
||||
}
|
||||
_ => panic!("{} is not {}", antlr_tok, rustc_tok)
|
||||
_ => panic!("{:?} is not {:?}", antlr_tok, rustc_tok)
|
||||
},)*
|
||||
ref c => assert!(c == &antlr_tok.tok, "{} is not {}", rustc_tok, antlr_tok)
|
||||
ref c => assert!(c == &antlr_tok.tok, "{:?} is not {:?}", rustc_tok, antlr_tok)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -2526,7 +2526,7 @@ mod bitv_bench {
|
||||
for _ in range(0u, 100) {
|
||||
bitv |= 1 << ((r.next_u32() as uint) % u32::BITS);
|
||||
}
|
||||
black_box(&bitv)
|
||||
black_box(&bitv);
|
||||
});
|
||||
}
|
||||
|
||||
@ -2538,7 +2538,7 @@ mod bitv_bench {
|
||||
for _ in range(0u, 100) {
|
||||
bitv.set((r.next_u32() as uint) % BENCH_BITS, true);
|
||||
}
|
||||
black_box(&bitv)
|
||||
black_box(&bitv);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1422,7 +1422,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use prelude::*;
|
||||
use std::borrow::BorrowFrom;
|
||||
|
||||
use super::{BTreeMap, Occupied, Vacant};
|
||||
|
||||
|
@ -18,6 +18,8 @@ use core::cmp::Ordering::{self, Less, Greater, Equal};
|
||||
use core::default::Default;
|
||||
use core::fmt::Show;
|
||||
use core::fmt;
|
||||
// NOTE(stage0) remove import after a snapshot
|
||||
#[cfg(stage0)]
|
||||
use core::hash::Hash;
|
||||
use core::iter::{Peekable, Map, FromIterator};
|
||||
use core::ops::{BitOr, BitAnd, BitXor, Sub};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -230,7 +230,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut a = DList::new();
|
||||
@ -304,6 +304,18 @@ impl<T> DList<T> {
|
||||
/// Returns `true` if the `DList` is empty.
|
||||
///
|
||||
/// This operation should compute in O(1) time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
/// assert!(dl.is_empty());
|
||||
///
|
||||
/// dl.push_front("foo");
|
||||
/// assert!(!dl.is_empty());
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
@ -313,6 +325,24 @@ impl<T> DList<T> {
|
||||
/// Returns the length of the `DList`.
|
||||
///
|
||||
/// This operation should compute in O(1) time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
///
|
||||
/// dl.push_front(2is);
|
||||
/// assert_eq!(dl.len(), 1);
|
||||
///
|
||||
/// dl.push_front(1);
|
||||
/// assert_eq!(dl.len(), 2);
|
||||
///
|
||||
/// dl.push_back(3);
|
||||
/// assert_eq!(dl.len(), 3);
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn len(&self) -> uint {
|
||||
@ -322,6 +352,24 @@ impl<T> DList<T> {
|
||||
/// Removes all elements from the `DList`.
|
||||
///
|
||||
/// This operation should compute in O(n) time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
///
|
||||
/// dl.push_front(2is);
|
||||
/// dl.push_front(1);
|
||||
/// assert_eq!(dl.len(), 2);
|
||||
/// assert_eq!(dl.front(), Some(&1is));
|
||||
///
|
||||
/// dl.clear();
|
||||
/// assert_eq!(dl.len(), 0);
|
||||
/// assert_eq!(dl.front(), None);
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn clear(&mut self) {
|
||||
@ -330,6 +378,19 @@ impl<T> DList<T> {
|
||||
|
||||
/// Provides a reference to the front element, or `None` if the list is
|
||||
/// empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
/// assert_eq!(dl.front(), None);
|
||||
///
|
||||
/// dl.push_front(1);
|
||||
/// assert_eq!(dl.front(), Some(&1is));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn front(&self) -> Option<&T> {
|
||||
@ -338,6 +399,25 @@ impl<T> DList<T> {
|
||||
|
||||
/// Provides a mutable reference to the front element, or `None` if the list
|
||||
/// is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
/// assert_eq!(dl.front(), None);
|
||||
///
|
||||
/// dl.push_front(1);
|
||||
/// assert_eq!(dl.front(), Some(&1is));
|
||||
///
|
||||
/// match dl.front_mut() {
|
||||
/// None => {},
|
||||
/// Some(x) => *x = 5is,
|
||||
/// }
|
||||
/// assert_eq!(dl.front(), Some(&5is));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn front_mut(&mut self) -> Option<&mut T> {
|
||||
@ -346,6 +426,19 @@ impl<T> DList<T> {
|
||||
|
||||
/// Provides a reference to the back element, or `None` if the list is
|
||||
/// empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
/// assert_eq!(dl.back(), None);
|
||||
///
|
||||
/// dl.push_back(1);
|
||||
/// assert_eq!(dl.back(), Some(&1is));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn back(&self) -> Option<&T> {
|
||||
@ -354,6 +447,25 @@ impl<T> DList<T> {
|
||||
|
||||
/// Provides a mutable reference to the back element, or `None` if the list
|
||||
/// is empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
/// assert_eq!(dl.back(), None);
|
||||
///
|
||||
/// dl.push_back(1);
|
||||
/// assert_eq!(dl.back(), Some(&1is));
|
||||
///
|
||||
/// match dl.back_mut() {
|
||||
/// None => {},
|
||||
/// Some(x) => *x = 5is,
|
||||
/// }
|
||||
/// assert_eq!(dl.back(), Some(&5is));
|
||||
///
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable]
|
||||
pub fn back_mut(&mut self) -> Option<&mut T> {
|
||||
@ -363,6 +475,21 @@ impl<T> DList<T> {
|
||||
/// Adds an element first in the list.
|
||||
///
|
||||
/// This operation should compute in O(1) time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut dl = DList::new();
|
||||
///
|
||||
/// dl.push_front(2is);
|
||||
/// assert_eq!(dl.front().unwrap(), &2is);
|
||||
///
|
||||
/// dl.push_front(1);
|
||||
/// assert_eq!(dl.front().unwrap(), &1);
|
||||
///
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn push_front(&mut self, elt: T) {
|
||||
self.push_front_node(box Node::new(elt))
|
||||
@ -372,6 +499,23 @@ impl<T> DList<T> {
|
||||
/// empty.
|
||||
///
|
||||
/// This operation should compute in O(1) time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut d = DList::new();
|
||||
/// assert_eq!(d.pop_front(), None);
|
||||
///
|
||||
/// d.push_front(1is);
|
||||
/// d.push_front(3);
|
||||
/// assert_eq!(d.pop_front(), Some(3));
|
||||
/// assert_eq!(d.pop_front(), Some(1));
|
||||
/// assert_eq!(d.pop_front(), None);
|
||||
///
|
||||
/// ```
|
||||
///
|
||||
#[stable]
|
||||
pub fn pop_front(&mut self) -> Option<T> {
|
||||
self.pop_front_node().map(|box Node{value, ..}| value)
|
||||
@ -381,7 +525,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut d = DList::new();
|
||||
@ -399,7 +543,7 @@ impl<T> DList<T> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut d = DList::new();
|
||||
@ -417,6 +561,22 @@ impl<T> DList<T> {
|
||||
/// including the index.
|
||||
///
|
||||
/// This operation should compute in O(n) time.
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut d = DList::new();
|
||||
///
|
||||
/// d.push_front(1is);
|
||||
/// d.push_front(2);
|
||||
/// d.push_front(3);
|
||||
///
|
||||
/// let mut splitted = d.split_off(2);
|
||||
///
|
||||
/// assert_eq!(splitted.pop_front(), Some(1));
|
||||
/// assert_eq!(splitted.pop_front(), None);
|
||||
/// ```
|
||||
#[stable]
|
||||
pub fn split_off(&mut self, at: uint) -> DList<T> {
|
||||
let len = self.len();
|
||||
@ -593,7 +753,7 @@ impl<'a, A> IterMut<'a, A> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut list: DList<int> = vec![1, 3, 4].into_iter().collect();
|
||||
@ -619,7 +779,7 @@ impl<'a, A> IterMut<'a, A> {
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::collections::DList;
|
||||
///
|
||||
/// let mut list: DList<int> = vec![1, 2, 3].into_iter().collect();
|
||||
|
@ -2841,7 +2841,7 @@ mod bench {
|
||||
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
|
||||
|
||||
b.iter(|| {
|
||||
for ch in s.chars() { black_box(ch) }
|
||||
for ch in s.chars() { black_box(ch); }
|
||||
});
|
||||
}
|
||||
|
||||
@ -2869,7 +2869,7 @@ mod bench {
|
||||
let s = "ศไทย中华Việt Nam; Mary had a little lamb, Little lamb";
|
||||
|
||||
b.iter(|| {
|
||||
for ch in s.chars().rev() { black_box(ch) }
|
||||
for ch in s.chars().rev() { black_box(ch); }
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! A growable list type, written `Vec<T>` but pronounced 'vector.'
|
||||
//! A growable list type with heap-allocated contents, written `Vec<T>` but pronounced 'vector.'
|
||||
//!
|
||||
//! Vectors have `O(1)` indexing, push (to the end) and pop (from the end).
|
||||
//!
|
||||
@ -1511,6 +1511,9 @@ pub struct IntoIter<T> {
|
||||
end: *const T
|
||||
}
|
||||
|
||||
unsafe impl<T: Send> Send for IntoIter<T> { }
|
||||
unsafe impl<T: Sync> Sync for IntoIter<T> { }
|
||||
|
||||
impl<T> IntoIter<T> {
|
||||
#[inline]
|
||||
/// Drops all items that have not yet been moved and returns the empty vector.
|
||||
|
@ -198,6 +198,10 @@ extern "rust-intrinsic" {
|
||||
pub fn pref_align_of<T>() -> uint;
|
||||
|
||||
/// Get a static pointer to a type descriptor.
|
||||
#[cfg(not(stage0))]
|
||||
pub fn get_tydesc<T: ?Sized>() -> *const TyDesc;
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub fn get_tydesc<T>() -> *const TyDesc;
|
||||
|
||||
/// Gets an identifier which is globally unique to the specified type. This
|
||||
|
@ -66,7 +66,6 @@
|
||||
//! not (`None`).
|
||||
//!
|
||||
//! ```
|
||||
//! # use std::boxed::Box;
|
||||
//! let optional: Option<Box<int>> = None;
|
||||
//! check_optional(&optional);
|
||||
//!
|
||||
|
@ -46,7 +46,6 @@
|
||||
//! though unsafely, transformed from one type to the other.
|
||||
//!
|
||||
//! ```
|
||||
//! # use std::boxed::Box;
|
||||
//! use std::mem;
|
||||
//!
|
||||
//! unsafe {
|
||||
|
@ -119,7 +119,7 @@
|
||||
//! drop(file);
|
||||
//! ```
|
||||
//!
|
||||
//! If you *do* write that in Rust, the compiler will by give you a
|
||||
//! If you *do* write that in Rust, the compiler will give you a
|
||||
//! warning (by default, controlled by the `unused_must_use` lint).
|
||||
//!
|
||||
//! You might instead, if you don't want to handle the error, simply
|
||||
@ -178,13 +178,11 @@
|
||||
//! fn write_info(info: &Info) -> Result<(), IoError> {
|
||||
//! let mut file = File::open_mode(&Path::new("my_best_friends.txt"), Open, Write);
|
||||
//! // Early return on error
|
||||
//! match file.write_line(format!("name: {}", info.name).as_slice()) {
|
||||
//! Ok(_) => (),
|
||||
//! Err(e) => return Err(e)
|
||||
//! if let Err(e) = file.write_line(format!("name: {}", info.name).as_slice()) {
|
||||
//! return Err(e)
|
||||
//! }
|
||||
//! match file.write_line(format!("age: {}", info.age).as_slice()) {
|
||||
//! Ok(_) => (),
|
||||
//! Err(e) => return Err(e)
|
||||
//! if let Err(e) = file.write_line(format!("age: {}", info.age).as_slice()) {
|
||||
//! return Err(e)
|
||||
//! }
|
||||
//! return file.write_line(format!("rating: {}", info.rating).as_slice());
|
||||
//! }
|
||||
|
@ -35,9 +35,6 @@
|
||||
|
||||
#![stable]
|
||||
|
||||
#[unstable = "this is just a documentation module and should not be part \
|
||||
of the public api"]
|
||||
|
||||
use clone::Clone;
|
||||
use cmp::*;
|
||||
use cmp::Ordering::*;
|
||||
|
@ -28,6 +28,8 @@ pub struct LabelledCFG<'a, 'ast: 'a> {
|
||||
pub ast_map: &'a ast_map::Map<'ast>,
|
||||
pub cfg: &'a cfg::CFG,
|
||||
pub name: String,
|
||||
/// `labelled_edges` controls whether we emit labels on the edges
|
||||
pub labelled_edges: bool,
|
||||
}
|
||||
|
||||
fn replace_newline_with_backslash_l(s: String) -> String {
|
||||
@ -75,6 +77,9 @@ impl<'a, 'ast> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a, 'ast> {
|
||||
|
||||
fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> {
|
||||
let mut label = String::new();
|
||||
if !self.labelled_edges {
|
||||
return dot::LabelText::EscStr(label.into_cow());
|
||||
}
|
||||
let mut put_one = false;
|
||||
for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() {
|
||||
if put_one {
|
||||
|
@ -12,7 +12,7 @@
|
||||
//
|
||||
// There are various parts of the compiler that must impose arbitrary limits
|
||||
// on how deeply they recurse to prevent stack overflow. Users can override
|
||||
// this via an attribute on the crate like `#![recursion_limit(22)]`. This pass
|
||||
// this via an attribute on the crate like `#![recursion_limit="22"]`. This pass
|
||||
// just peeks and looks for that attribute.
|
||||
|
||||
use session::Session;
|
||||
@ -34,6 +34,6 @@ pub fn update_recursion_limit(sess: &Session, krate: &ast::Crate) {
|
||||
}
|
||||
|
||||
sess.span_err(attr.span, "malformed recursion limit attribute, \
|
||||
expected #![recursion_limit(\"N\")]");
|
||||
expected #![recursion_limit=\"N\"]");
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
|
||||
use util::common::can_reach;
|
||||
|
||||
use std::cell::RefCell;
|
||||
// NOTE(stage0) remove import after a snapshot
|
||||
#[cfg(stage0)]
|
||||
use std::hash::{Hash};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::{ast, visit};
|
||||
|
@ -2605,12 +2605,17 @@ impl FlagComputation {
|
||||
|
||||
&ty_projection(ref data) => {
|
||||
self.add_flags(HAS_PROJECTION);
|
||||
self.add_substs(data.trait_ref.substs);
|
||||
self.add_projection_ty(data);
|
||||
}
|
||||
|
||||
&ty_trait(box TyTrait { ref principal, ref bounds }) => {
|
||||
let mut computation = FlagComputation::new();
|
||||
computation.add_substs(principal.0.substs);
|
||||
for projection_bound in bounds.projection_bounds.iter() {
|
||||
let mut proj_computation = FlagComputation::new();
|
||||
proj_computation.add_projection_predicate(&projection_bound.0);
|
||||
computation.add_bound_computation(&proj_computation);
|
||||
}
|
||||
self.add_bound_computation(&computation);
|
||||
|
||||
self.add_bounds(bounds);
|
||||
@ -2674,6 +2679,15 @@ impl FlagComputation {
|
||||
}
|
||||
}
|
||||
|
||||
fn add_projection_predicate(&mut self, projection_predicate: &ProjectionPredicate) {
|
||||
self.add_projection_ty(&projection_predicate.projection_ty);
|
||||
self.add_ty(projection_predicate.ty);
|
||||
}
|
||||
|
||||
fn add_projection_ty(&mut self, projection_ty: &ProjectionTy) {
|
||||
self.add_substs(projection_ty.trait_ref.substs);
|
||||
}
|
||||
|
||||
fn add_substs(&mut self, substs: &Substs) {
|
||||
self.add_tys(substs.types.as_slice());
|
||||
match substs.regions {
|
||||
@ -4133,12 +4147,8 @@ pub fn node_id_to_trait_ref<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Option<Ty<'tcx>> {
|
||||
cx.node_types.borrow().get(&id).cloned()
|
||||
}
|
||||
|
||||
pub fn node_id_to_type<'tcx>(cx: &ctxt<'tcx>, id: ast::NodeId) -> Ty<'tcx> {
|
||||
match try_node_id_to_type(cx, id) {
|
||||
match node_id_to_type_opt(cx, id) {
|
||||
Some(ty) => ty,
|
||||
None => cx.sess.bug(
|
||||
&format!("node_id_to_type: no type for node `{}`",
|
||||
|
@ -1430,7 +1430,7 @@ impl<'tcx> UserString<'tcx> for ty::ProjectionPredicate<'tcx> {
|
||||
impl<'tcx> Repr<'tcx> for ty::ProjectionTy<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("<{} as {}>::{}",
|
||||
self.trait_ref.self_ty().repr(tcx),
|
||||
self.trait_ref.substs.self_ty().repr(tcx),
|
||||
self.trait_ref.repr(tcx),
|
||||
self.item_name.repr(tcx))
|
||||
}
|
||||
|
@ -103,6 +103,13 @@ pub fn compile_input(sess: Session,
|
||||
|
||||
write_out_deps(&sess, input, &outputs, &id[]);
|
||||
|
||||
controller_entry_point!(after_write_deps,
|
||||
CompileState::state_after_write_deps(input,
|
||||
&sess,
|
||||
outdir,
|
||||
&ast_map,
|
||||
&id[]));
|
||||
|
||||
let arenas = ty::CtxtArenas::new();
|
||||
let analysis = phase_3_run_analysis_passes(sess,
|
||||
ast_map,
|
||||
@ -176,6 +183,7 @@ pub fn source_name(input: &Input) -> String {
|
||||
pub struct CompileController<'a> {
|
||||
pub after_parse: PhaseController<'a>,
|
||||
pub after_expand: PhaseController<'a>,
|
||||
pub after_write_deps: PhaseController<'a>,
|
||||
pub after_analysis: PhaseController<'a>,
|
||||
pub after_llvm: PhaseController<'a>,
|
||||
|
||||
@ -187,6 +195,7 @@ impl<'a> CompileController<'a> {
|
||||
CompileController {
|
||||
after_parse: PhaseController::basic(),
|
||||
after_expand: PhaseController::basic(),
|
||||
after_write_deps: PhaseController::basic(),
|
||||
after_analysis: PhaseController::basic(),
|
||||
after_llvm: PhaseController::basic(),
|
||||
make_glob_map: resolve::MakeGlobMap::No,
|
||||
@ -271,6 +280,19 @@ impl<'a, 'ast, 'tcx> CompileState<'a, 'ast, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn state_after_write_deps(input: &'a Input,
|
||||
session: &'a Session,
|
||||
out_dir: &'a Option<Path>,
|
||||
ast_map: &'a ast_map::Map<'ast>,
|
||||
crate_name: &'a str)
|
||||
-> CompileState<'a, 'ast, 'tcx> {
|
||||
CompileState {
|
||||
crate_name: Some(crate_name),
|
||||
ast_map: Some(ast_map),
|
||||
.. CompileState::empty(input, session, out_dir)
|
||||
}
|
||||
}
|
||||
|
||||
fn state_after_analysis(input: &'a Input,
|
||||
session: &'a Session,
|
||||
out_dir: &'a Option<Path>,
|
||||
|
@ -207,7 +207,7 @@ fn build_controller<'a>(sess: &Session) -> CompileController<'a> {
|
||||
}
|
||||
|
||||
if sess.opts.no_analysis || sess.opts.debugging_opts.ast_json {
|
||||
control.after_expand.stop = true;
|
||||
control.after_write_deps.stop = true;
|
||||
}
|
||||
|
||||
if sess.opts.no_trans {
|
||||
|
@ -53,10 +53,20 @@ pub enum PpSourceMode {
|
||||
PpmExpandedHygiene,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Copy, PartialEq, Show)]
|
||||
pub enum PpFlowGraphMode {
|
||||
Default,
|
||||
/// Drops the labels from the edges in the flowgraph output. This
|
||||
/// is mostly for use in the --xpretty flowgraph run-make tests,
|
||||
/// since the labels are largely uninteresting in those cases and
|
||||
/// have become a pain to maintain.
|
||||
UnlabelledEdges,
|
||||
}
|
||||
#[derive(Copy, PartialEq, Show)]
|
||||
pub enum PpMode {
|
||||
PpmSource(PpSourceMode),
|
||||
PpmFlowGraph,
|
||||
PpmFlowGraph(PpFlowGraphMode),
|
||||
}
|
||||
|
||||
pub fn parse_pretty(sess: &Session,
|
||||
@ -73,12 +83,13 @@ pub fn parse_pretty(sess: &Session,
|
||||
("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
|
||||
("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
|
||||
("identified", _) => PpmSource(PpmIdentified),
|
||||
("flowgraph", true) => PpmFlowGraph,
|
||||
("flowgraph", true) => PpmFlowGraph(PpFlowGraphMode::Default),
|
||||
("flowgraph,unlabelled", true) => PpmFlowGraph(PpFlowGraphMode::UnlabelledEdges),
|
||||
_ => {
|
||||
if extended {
|
||||
sess.fatal(format!(
|
||||
"argument to `xpretty` must be one of `normal`, \
|
||||
`expanded`, `flowgraph=<nodeid>`, `typed`, `identified`, \
|
||||
`expanded`, `flowgraph[,unlabelled]=<nodeid>`, `typed`, `identified`, \
|
||||
`expanded,identified`, or `everybody_loops`; got {}", name).as_slice());
|
||||
} else {
|
||||
sess.fatal(format!(
|
||||
@ -417,7 +428,7 @@ fn needs_ast_map(ppm: &PpMode, opt_uii: &Option<UserIdentifiedItem>) -> bool {
|
||||
PpmSource(PpmExpandedIdentified) |
|
||||
PpmSource(PpmExpandedHygiene) |
|
||||
PpmSource(PpmTyped) |
|
||||
PpmFlowGraph => true
|
||||
PpmFlowGraph(_) => true
|
||||
}
|
||||
}
|
||||
|
||||
@ -431,7 +442,7 @@ fn needs_expansion(ppm: &PpMode) -> bool {
|
||||
PpmSource(PpmExpandedIdentified) |
|
||||
PpmSource(PpmExpandedHygiene) |
|
||||
PpmSource(PpmTyped) |
|
||||
PpmFlowGraph => true
|
||||
PpmFlowGraph(_) => true
|
||||
}
|
||||
}
|
||||
|
||||
@ -589,7 +600,7 @@ pub fn pretty_print_input(sess: Session,
|
||||
pp::eof(&mut pp_state.s)
|
||||
}),
|
||||
|
||||
(PpmFlowGraph, opt_uii) => {
|
||||
(PpmFlowGraph(mode), opt_uii) => {
|
||||
debug!("pretty printing flow graph for {:?}", opt_uii);
|
||||
let uii = opt_uii.unwrap_or_else(|| {
|
||||
sess.fatal(&format!("`pretty flowgraph=..` needs NodeId (int) or
|
||||
@ -613,7 +624,7 @@ pub fn pretty_print_input(sess: Session,
|
||||
&arenas,
|
||||
id,
|
||||
resolve::MakeGlobMap::No);
|
||||
print_flowgraph(variants, analysis, code, out)
|
||||
print_flowgraph(variants, analysis, code, mode, out)
|
||||
}
|
||||
None => {
|
||||
let message = format!("--pretty=flowgraph needs \
|
||||
@ -635,20 +646,23 @@ pub fn pretty_print_input(sess: Session,
|
||||
fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
|
||||
analysis: ty::CrateAnalysis,
|
||||
code: blocks::Code,
|
||||
mode: PpFlowGraphMode,
|
||||
mut out: W) -> io::IoResult<()> {
|
||||
let ty_cx = &analysis.ty_cx;
|
||||
let cfg = match code {
|
||||
blocks::BlockCode(block) => cfg::CFG::new(ty_cx, &*block),
|
||||
blocks::FnLikeCode(fn_like) => cfg::CFG::new(ty_cx, &*fn_like.body()),
|
||||
};
|
||||
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
|
||||
let lcfg = LabelledCFG {
|
||||
ast_map: &ty_cx.map,
|
||||
cfg: &cfg,
|
||||
name: format!("node_{}", code.id()),
|
||||
labelled_edges: labelled_edges,
|
||||
};
|
||||
|
||||
match code {
|
||||
_ if variants.len() == 0 => {
|
||||
let lcfg = LabelledCFG {
|
||||
ast_map: &ty_cx.map,
|
||||
cfg: &cfg,
|
||||
name: format!("node_{}", code.id()),
|
||||
};
|
||||
let r = dot::render(&lcfg, &mut out);
|
||||
return expand_err_details(r);
|
||||
}
|
||||
@ -662,11 +676,6 @@ fn print_flowgraph<W:io::Writer>(variants: Vec<borrowck_dot::Variant>,
|
||||
let (bccx, analysis_data) =
|
||||
borrowck::build_borrowck_dataflow_data_for_fn(ty_cx, fn_parts);
|
||||
|
||||
let lcfg = LabelledCFG {
|
||||
ast_map: &ty_cx.map,
|
||||
cfg: &cfg,
|
||||
name: format!("node_{}", code.id()),
|
||||
};
|
||||
let lcfg = borrowck_dot::DataflowLabeller {
|
||||
inner: lcfg,
|
||||
variants: variants,
|
||||
|
@ -167,7 +167,10 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
|
||||
llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod);
|
||||
llvm::LLVMRustAddPass(pm, "verify\0".as_ptr() as *const _);
|
||||
|
||||
let opt = sess.opts.cg.opt_level.unwrap_or(0) as libc::c_uint;
|
||||
|
||||
let builder = llvm::LLVMPassManagerBuilderCreate();
|
||||
llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt);
|
||||
llvm::LLVMPassManagerBuilderPopulateLTOPassManager(builder, pm,
|
||||
/* Internalize = */ False,
|
||||
/* RunInliner = */ True);
|
||||
|
@ -201,7 +201,7 @@ use middle::pat_util::*;
|
||||
use trans::adt;
|
||||
use trans::base::*;
|
||||
use trans::build::{AddCase, And, BitCast, Br, CondBr, GEPi, InBoundsGEP, Load};
|
||||
use trans::build::{Mul, Not, Store, Sub, add_comment};
|
||||
use trans::build::{Not, Store, Sub, add_comment};
|
||||
use trans::build;
|
||||
use trans::callee;
|
||||
use trans::cleanup::{self, CleanupMethods};
|
||||
@ -630,8 +630,7 @@ fn bind_subslice_pat(bcx: Block,
|
||||
let vec_datum = match_datum(val, vec_ty);
|
||||
let (base, len) = vec_datum.get_vec_base_and_len(bcx);
|
||||
|
||||
let slice_byte_offset = Mul(bcx, vt.llunit_size, C_uint(bcx.ccx(), offset_left));
|
||||
let slice_begin = tvec::pointer_add_byte(bcx, base, slice_byte_offset);
|
||||
let slice_begin = InBoundsGEP(bcx, base, &[C_uint(bcx.ccx(), offset_left)]);
|
||||
let slice_len_offset = C_uint(bcx.ccx(), offset_left + offset_right);
|
||||
let slice_len = Sub(bcx, len, slice_len_offset);
|
||||
let slice_ty = ty::mk_slice(bcx.tcx(),
|
||||
@ -857,16 +856,9 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
|
||||
}
|
||||
|
||||
debug!("binding {} to {}",
|
||||
binding_info.id,
|
||||
bcx.val_to_string(llval));
|
||||
debug!("binding {} to {}", binding_info.id, bcx.val_to_string(llval));
|
||||
bcx.fcx.lllocals.borrow_mut().insert(binding_info.id, datum);
|
||||
|
||||
if bcx.sess().opts.debuginfo == FullDebugInfo {
|
||||
debuginfo::create_match_binding_metadata(bcx,
|
||||
ident,
|
||||
binding_info);
|
||||
}
|
||||
debuginfo::create_match_binding_metadata(bcx, ident, binding_info);
|
||||
}
|
||||
bcx
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ use middle::subst;
|
||||
use middle::weak_lang_items;
|
||||
use middle::subst::{Subst, Substs};
|
||||
use middle::ty::{self, Ty, UnboxedClosureTyper};
|
||||
use session::config::{self, NoDebugInfo, FullDebugInfo};
|
||||
use session::config::{self, NoDebugInfo};
|
||||
use session::Session;
|
||||
use trans::_match;
|
||||
use trans::adt;
|
||||
@ -544,15 +544,6 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
}
|
||||
|
||||
// Structural comparison: a rather involved form of glue.
|
||||
pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
|
||||
if cx.sess().opts.cg.save_temps {
|
||||
let buf = CString::from_slice(s.as_bytes());
|
||||
unsafe { llvm::LLVMSetValueName(v, buf.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Used only for creating scalar comparison glue.
|
||||
#[derive(Copy)]
|
||||
pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
|
||||
@ -1626,9 +1617,8 @@ fn create_datums_for_fn_args_under_call_abi<'blk, 'tcx>(
|
||||
result
|
||||
}
|
||||
|
||||
fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>,
|
||||
fn copy_args_to_allocas<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
arg_scope: cleanup::CustomScopeIndex,
|
||||
bcx: Block<'blk, 'tcx>,
|
||||
args: &[ast::Arg],
|
||||
arg_datums: Vec<RvalueDatum<'tcx>>)
|
||||
-> Block<'blk, 'tcx> {
|
||||
@ -1649,10 +1639,7 @@ fn copy_args_to_allocas<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>,
|
||||
// the event it's not truly needed.
|
||||
|
||||
bcx = _match::store_arg(bcx, &*args[i].pat, arg_datum, arg_scope_id);
|
||||
|
||||
if fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
|
||||
debuginfo::create_argument_metadata(bcx, &args[i]);
|
||||
}
|
||||
debuginfo::create_argument_metadata(bcx, &args[i]);
|
||||
}
|
||||
|
||||
bcx
|
||||
@ -1702,9 +1689,7 @@ fn copy_unboxed_closure_args_to_allocas<'blk, 'tcx>(
|
||||
tuple_element_datum,
|
||||
arg_scope_id);
|
||||
|
||||
if bcx.fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
|
||||
debuginfo::create_argument_metadata(bcx, &args[j]);
|
||||
}
|
||||
debuginfo::create_argument_metadata(bcx, &args[j]);
|
||||
}
|
||||
|
||||
bcx
|
||||
@ -1877,9 +1862,8 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
bcx = match closure_env.kind {
|
||||
closure::NotClosure | closure::BoxedClosure(..) => {
|
||||
copy_args_to_allocas(&fcx,
|
||||
copy_args_to_allocas(bcx,
|
||||
arg_scope,
|
||||
bcx,
|
||||
&decl.inputs[],
|
||||
arg_datums)
|
||||
}
|
||||
|
@ -217,12 +217,15 @@ pub fn type_needs_drop<'tcx>(cx: &ty::ctxt<'tcx>,
|
||||
ty::type_contents(cx, ty).needs_drop(cx)
|
||||
}
|
||||
|
||||
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ty: Ty<'tcx>) -> bool {
|
||||
fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
match ty.sty {
|
||||
ty::ty_struct(def_id, substs) => {
|
||||
let fields = ty::struct_fields(ccx.tcx(), def_id, substs);
|
||||
fields.len() == 1 && type_is_immediate(ccx, fields[0].mt.ty)
|
||||
let fields = ty::lookup_struct_fields(ccx.tcx(), def_id);
|
||||
fields.len() == 1 && {
|
||||
let ty = ty::lookup_field_type(ccx.tcx(), def_id, fields[0].id, substs);
|
||||
let ty = monomorphize::normalize_associated_type(ccx.tcx(), &ty);
|
||||
type_is_immediate(ccx, ty)
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ use trans::type_::Type;
|
||||
use trans;
|
||||
use middle::ty;
|
||||
use middle::ty::MethodCall;
|
||||
use session::config::FullDebugInfo;
|
||||
use util::ppaux::Repr;
|
||||
use util::ppaux;
|
||||
|
||||
@ -66,10 +65,7 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
||||
match d.node {
|
||||
ast::DeclLocal(ref local) => {
|
||||
bcx = init_local(bcx, &**local);
|
||||
if cx.sess().opts.debuginfo == FullDebugInfo {
|
||||
trans::debuginfo::create_local_var_metadata(bcx,
|
||||
&**local);
|
||||
}
|
||||
debuginfo::create_local_var_metadata(bcx, &**local);
|
||||
}
|
||||
// Inner items are visited by `trans_item`/`trans_meth`.
|
||||
ast::DeclItem(_) => {},
|
||||
|
@ -323,28 +323,26 @@ impl<'tcx> TypeMap<'tcx> {
|
||||
fn get_unique_type_id_of_type<'a>(&mut self, cx: &CrateContext<'a, 'tcx>,
|
||||
type_: Ty<'tcx>) -> UniqueTypeId {
|
||||
|
||||
// basic type -> {:name of the type:}
|
||||
// tuple -> {tuple_(:param-uid:)*}
|
||||
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// enum variant -> {variant_:variant-name:_:enum-uid:}
|
||||
// reference (&) -> {& :pointee-uid:}
|
||||
// mut reference (&mut) -> {&mut :pointee-uid:}
|
||||
// ptr (*) -> {* :pointee-uid:}
|
||||
// mut ptr (*mut) -> {*mut :pointee-uid:}
|
||||
// unique ptr (~) -> {~ :pointee-uid:}
|
||||
// @-ptr (@) -> {@ :pointee-uid:}
|
||||
// sized vec ([T; x]) -> {[:size:] :element-uid:}
|
||||
// unsized vec ([T]) -> {[] :element-uid:}
|
||||
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// closure -> {<unsafe_> <once_> :store-sigil:
|
||||
// |(:param-uid:),* <,_...>| -> \
|
||||
// :return-type-uid: : (:bounds:)*}
|
||||
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
|
||||
// :return-type-uid:}
|
||||
// unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>}
|
||||
// gc box -> {GC_BOX<:pointee-uid:>}
|
||||
// projection (<T as U>::V) -> {<:ty-uid: as :trait-uid:> :: :name-uid: }
|
||||
// basic type -> {:name of the type:}
|
||||
// tuple -> {tuple_(:param-uid:)*}
|
||||
// struct -> {struct_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// enum -> {enum_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// enum variant -> {variant_:variant-name:_:enum-uid:}
|
||||
// reference (&) -> {& :pointee-uid:}
|
||||
// mut reference (&mut) -> {&mut :pointee-uid:}
|
||||
// ptr (*) -> {* :pointee-uid:}
|
||||
// mut ptr (*mut) -> {*mut :pointee-uid:}
|
||||
// unique ptr (~) -> {~ :pointee-uid:}
|
||||
// @-ptr (@) -> {@ :pointee-uid:}
|
||||
// sized vec ([T; x]) -> {[:size:] :element-uid:}
|
||||
// unsized vec ([T]) -> {[] :element-uid:}
|
||||
// trait (T) -> {trait_:svh: / :node-id:_<(:param-uid:),*> }
|
||||
// closure -> {<unsafe_> <once_> :store-sigil: |(:param-uid:),* <,_...>| -> \
|
||||
// :return-type-uid: : (:bounds:)*}
|
||||
// function -> {<unsafe_> <abi_> fn( (:param-uid:)* <,_...> ) -> \
|
||||
// :return-type-uid:}
|
||||
// unique vec box (~[]) -> {HEAP_VEC_BOX<:pointee-uid:>}
|
||||
// gc box -> {GC_BOX<:pointee-uid:>}
|
||||
|
||||
match self.type_to_unique_id.get(&type_).cloned() {
|
||||
Some(unique_type_id) => return unique_type_id,
|
||||
@ -437,25 +435,6 @@ impl<'tcx> TypeMap<'tcx> {
|
||||
principal.substs,
|
||||
&mut unique_type_id);
|
||||
},
|
||||
ty::ty_projection(ref projection) => {
|
||||
unique_type_id.push_str("<");
|
||||
|
||||
let self_ty = projection.trait_ref.self_ty();
|
||||
let self_type_id = self.get_unique_type_id_of_type(cx, self_ty);
|
||||
let self_type_id = self.get_unique_type_id_as_string(self_type_id);
|
||||
unique_type_id.push_str(&self_type_id[]);
|
||||
|
||||
unique_type_id.push_str(" as ");
|
||||
|
||||
from_def_id_and_substs(self,
|
||||
cx,
|
||||
projection.trait_ref.def_id,
|
||||
projection.trait_ref.substs,
|
||||
&mut unique_type_id);
|
||||
|
||||
unique_type_id.push_str(">::");
|
||||
unique_type_id.push_str(token::get_name(projection.item_name).get());
|
||||
},
|
||||
ty::ty_bare_fn(_, &ty::BareFnTy{ unsafety, abi, ref sig } ) => {
|
||||
if unsafety == ast::Unsafety::Unsafe {
|
||||
unique_type_id.push_str("unsafe ");
|
||||
@ -499,10 +478,7 @@ impl<'tcx> TypeMap<'tcx> {
|
||||
closure_ty,
|
||||
&mut unique_type_id);
|
||||
},
|
||||
ty::ty_err |
|
||||
ty::ty_infer(_) |
|
||||
ty::ty_open(_) |
|
||||
ty::ty_param(_) => {
|
||||
_ => {
|
||||
cx.sess().bug(&format!("get_unique_type_id_of_type() - unexpected type: {}, {:?}",
|
||||
&ppaux::ty_to_string(cx.tcx(), type_)[],
|
||||
type_.sty)[])
|
||||
@ -878,7 +854,9 @@ pub fn create_global_var_metadata(cx: &CrateContext,
|
||||
/// local in `bcx.fcx.lllocals`.
|
||||
/// Adds the created metadata nodes directly to the crate's IR.
|
||||
pub fn create_local_var_metadata(bcx: Block, local: &ast::Local) {
|
||||
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
|
||||
if bcx.unreachable.get() ||
|
||||
fn_should_be_ignored(bcx.fcx) ||
|
||||
bcx.sess().opts.debuginfo != FullDebugInfo {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -922,7 +900,9 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
env_index: uint,
|
||||
captured_by_ref: bool,
|
||||
span: Span) {
|
||||
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
|
||||
if bcx.unreachable.get() ||
|
||||
fn_should_be_ignored(bcx.fcx) ||
|
||||
bcx.sess().opts.debuginfo != FullDebugInfo {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1005,7 +985,9 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
variable_ident: ast::Ident,
|
||||
binding: BindingInfo<'tcx>) {
|
||||
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
|
||||
if bcx.unreachable.get() ||
|
||||
fn_should_be_ignored(bcx.fcx) ||
|
||||
bcx.sess().opts.debuginfo != FullDebugInfo {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1045,7 +1027,9 @@ pub fn create_match_binding_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
/// argument in `bcx.fcx.lllocals`.
|
||||
/// Adds the created metadata nodes directly to the crate's IR.
|
||||
pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
|
||||
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
|
||||
if bcx.unreachable.get() ||
|
||||
fn_should_be_ignored(bcx.fcx) ||
|
||||
bcx.sess().opts.debuginfo != FullDebugInfo {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1099,7 +1083,9 @@ pub fn create_argument_metadata(bcx: Block, arg: &ast::Arg) {
|
||||
/// loop variable in `bcx.fcx.lllocals`.
|
||||
/// Adds the created metadata nodes directly to the crate's IR.
|
||||
pub fn create_for_loop_var_metadata(bcx: Block, pat: &ast::Pat) {
|
||||
if bcx.unreachable.get() || fn_should_be_ignored(bcx.fcx) {
|
||||
if bcx.unreachable.get() ||
|
||||
fn_should_be_ignored(bcx.fcx) ||
|
||||
bcx.sess().opts.debuginfo != FullDebugInfo {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3880,22 +3866,10 @@ fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
ty::ty_unboxed_closure(..) => {
|
||||
output.push_str("closure");
|
||||
}
|
||||
ty::ty_projection(ref projection) => {
|
||||
output.push_str("<");
|
||||
let self_ty = projection.trait_ref.self_ty();
|
||||
push_debuginfo_type_name(cx, self_ty, true, output);
|
||||
|
||||
output.push_str(" as ");
|
||||
|
||||
push_item_name(cx, projection.trait_ref.def_id, false, output);
|
||||
push_type_params(cx, projection.trait_ref.substs, output);
|
||||
|
||||
output.push_str(">::");
|
||||
output.push_str(token::get_name(projection.item_name).get());
|
||||
}
|
||||
ty::ty_err |
|
||||
ty::ty_infer(_) |
|
||||
ty::ty_open(_) |
|
||||
ty::ty_projection(..) |
|
||||
ty::ty_param(_) => {
|
||||
cx.sess().bug(&format!("debuginfo: Trying to create type name for \
|
||||
unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t))[]);
|
||||
|
@ -768,7 +768,6 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
tvec::vec_types(bcx,
|
||||
ty::sequence_element_type(bcx.tcx(),
|
||||
base_datum.ty));
|
||||
base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz");
|
||||
|
||||
let (base, len) = base_datum.get_vec_base_and_len(bcx);
|
||||
|
||||
|
@ -346,12 +346,14 @@ fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info:
|
||||
let align_ptr = GEPi(bcx, info, &[2u]);
|
||||
(Load(bcx, size_ptr), Load(bcx, align_ptr))
|
||||
}
|
||||
ty::ty_vec(unit_ty, None) => {
|
||||
// The info in this case is the length of the vec, so the size is that
|
||||
ty::ty_vec(_, None) | ty::ty_str => {
|
||||
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
|
||||
// The info in this case is the length of the str, so the size is that
|
||||
// times the unit size.
|
||||
let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
|
||||
let unit_align = llalign_of_min(bcx.ccx(), llunit_ty);
|
||||
let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
|
||||
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size)), C_uint(bcx.ccx(), 8u))
|
||||
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size)), C_uint(bcx.ccx(), unit_align))
|
||||
}
|
||||
_ => bcx.sess().bug(&format!("Unexpected unsized type, found {}",
|
||||
bcx.ty_to_string(t))[])
|
||||
@ -456,8 +458,11 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: Ty<'tcx>)
|
||||
&[PointerCast(bcx, Load(bcx, lluniquevalue), Type::i8p(bcx.ccx()))],
|
||||
None);
|
||||
bcx
|
||||
}
|
||||
ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
|
||||
},
|
||||
ty::ty_vec(_, None) | ty::ty_str => {
|
||||
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
|
||||
tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, false)
|
||||
},
|
||||
_ => {
|
||||
assert!(type_is_sized(bcx.tcx(), t));
|
||||
if type_needs_drop(bcx.tcx(), t) &&
|
||||
|
@ -82,17 +82,6 @@ pub fn llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
|
||||
return C_uint(cx, llsize_of_alloc(cx, ty));
|
||||
}
|
||||
|
||||
// Returns the "default" size of t (see above), or 1 if the size would
|
||||
// be zero. This is important for things like vectors that expect
|
||||
// space to be consumed.
|
||||
pub fn nonzero_llsize_of(cx: &CrateContext, ty: Type) -> ValueRef {
|
||||
if llbitsize_of_real(cx, ty) == 0 {
|
||||
unsafe { llvm::LLVMConstInt(cx.int_type().to_ref(), 1, False) }
|
||||
} else {
|
||||
llsize_of(cx, ty)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the preferred alignment of the given type for the current target.
|
||||
// The preferred alignment may be larger than the alignment used when
|
||||
// packing the type into structs. This will be used for things like
|
||||
|
@ -288,6 +288,17 @@ pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
param_substs,
|
||||
callee_substs)
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
let trait_item_def_ids =
|
||||
ty::trait_item_def_ids(ccx.tcx(), trait_id);
|
||||
let method_offset_in_trait =
|
||||
trait_item_def_ids.iter()
|
||||
.position(|item| item.def_id() == method_id)
|
||||
.unwrap();
|
||||
let (llfn, ty) =
|
||||
trans_object_shim(ccx, data.object_ty, trait_id, method_offset_in_trait);
|
||||
immediate_rvalue(llfn, ty)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug(&format!("static call to invalid vtable: {}",
|
||||
vtbl.repr(tcx))[]);
|
||||
@ -371,7 +382,7 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
let llfn = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
|
||||
let (llfn, _) = trans_object_shim(bcx.ccx(), data.object_ty, trait_id, n_method);
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
}
|
||||
traits::VtableBuiltin(..) |
|
||||
@ -540,7 +551,7 @@ pub fn trans_object_shim<'a, 'tcx>(
|
||||
object_ty: Ty<'tcx>,
|
||||
trait_id: ast::DefId,
|
||||
method_offset_in_trait: uint)
|
||||
-> ValueRef
|
||||
-> (ValueRef, Ty<'tcx>)
|
||||
{
|
||||
let _icx = push_ctxt("trans_object_shim");
|
||||
let tcx = ccx.tcx();
|
||||
@ -667,7 +678,7 @@ pub fn trans_object_shim<'a, 'tcx>(
|
||||
|
||||
finish_fn(&fcx, bcx, sig.output);
|
||||
|
||||
llfn
|
||||
(llfn, method_bare_fn_ty)
|
||||
}
|
||||
|
||||
/// Creates a returns a dynamic vtable for the given type and vtable origin.
|
||||
|
@ -25,7 +25,7 @@ use trans::expr::{Dest, Ignore, SaveIn};
|
||||
use trans::expr;
|
||||
use trans::glue;
|
||||
use trans::machine;
|
||||
use trans::machine::{nonzero_llsize_of, llsize_of_alloc};
|
||||
use trans::machine::llsize_of_alloc;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
use middle::ty::{self, Ty};
|
||||
@ -44,13 +44,6 @@ fn get_dataptr(bcx: Block, vptr: ValueRef) -> ValueRef {
|
||||
Load(bcx, expr::get_dataptr(bcx, vptr))
|
||||
}
|
||||
|
||||
pub fn pointer_add_byte(bcx: Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
|
||||
let _icx = push_ctxt("tvec::pointer_add_byte");
|
||||
let old_ty = val_ty(ptr);
|
||||
let bptr = PointerCast(bcx, ptr, Type::i8p(bcx.ccx()));
|
||||
return PointerCast(bcx, InBoundsGEP(bcx, bptr, &[bytes]), old_ty);
|
||||
}
|
||||
|
||||
pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
vptr: ValueRef,
|
||||
unit_ty: Ty<'tcx>,
|
||||
@ -94,17 +87,14 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
pub struct VecTypes<'tcx> {
|
||||
pub unit_ty: Ty<'tcx>,
|
||||
pub llunit_ty: Type,
|
||||
pub llunit_size: ValueRef,
|
||||
pub llunit_alloc_size: u64
|
||||
}
|
||||
|
||||
impl<'tcx> VecTypes<'tcx> {
|
||||
pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
|
||||
format!("VecTypes {{unit_ty={}, llunit_ty={}, \
|
||||
llunit_size={}, llunit_alloc_size={}}}",
|
||||
format!("VecTypes {{unit_ty={}, llunit_ty={}, llunit_alloc_size={}}}",
|
||||
ty_to_string(ccx.tcx(), self.unit_ty),
|
||||
ccx.tn().type_to_string(self.llunit_ty),
|
||||
ccx.tn().val_to_string(self.llunit_size),
|
||||
self.llunit_alloc_size)
|
||||
}
|
||||
}
|
||||
@ -333,13 +323,11 @@ pub fn vec_types<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
-> VecTypes<'tcx> {
|
||||
let ccx = bcx.ccx();
|
||||
let llunit_ty = type_of::type_of(ccx, unit_ty);
|
||||
let llunit_size = nonzero_llsize_of(ccx, llunit_ty);
|
||||
let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty);
|
||||
|
||||
VecTypes {
|
||||
unit_ty: unit_ty,
|
||||
llunit_ty: llunit_ty,
|
||||
llunit_size: llunit_size,
|
||||
llunit_alloc_size: llunit_alloc_size
|
||||
}
|
||||
}
|
||||
@ -486,17 +474,13 @@ pub fn iter_vec_raw<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||
let fcx = bcx.fcx;
|
||||
|
||||
let vt = vec_types(bcx, unit_ty);
|
||||
let fill = Mul(bcx, len, vt.llunit_size);
|
||||
|
||||
if vt.llunit_alloc_size == 0 {
|
||||
// Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
|
||||
iter_vec_loop(bcx, data_ptr, &vt, fill, f)
|
||||
iter_vec_loop(bcx, data_ptr, &vt, len, f)
|
||||
} else {
|
||||
// Calculate the last pointer address we want to handle.
|
||||
// FIXME (#3729): Optimize this when the size of the unit type is
|
||||
// statically known to not use pointer casts, which tend to confuse
|
||||
// LLVM.
|
||||
let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
|
||||
let data_end_ptr = InBoundsGEP(bcx, data_ptr, &[len]);
|
||||
|
||||
// Now perform the iteration.
|
||||
let header_bcx = fcx.new_temp_block("iter_vec_loop_header");
|
||||
|
@ -516,8 +516,15 @@ pub fn instantiate_poly_trait_ref<'tcx>(
|
||||
{
|
||||
let mut projections = Vec::new();
|
||||
|
||||
// the trait reference introduces a binding level here, so
|
||||
// we need to shift the `rscope`. It'd be nice if we could
|
||||
// do away with this rscope stuff and work this knowledge
|
||||
// into resolve_lifetimes, as we do with non-omitted
|
||||
// lifetimes. Oh well, not there yet.
|
||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
||||
|
||||
let trait_ref =
|
||||
instantiate_trait_ref(this, rscope, &ast_trait_ref.trait_ref,
|
||||
instantiate_trait_ref(this, &shifted_rscope, &ast_trait_ref.trait_ref,
|
||||
self_ty, Some(&mut projections));
|
||||
|
||||
for projection in projections.into_iter() {
|
||||
@ -561,6 +568,29 @@ pub fn instantiate_trait_ref<'tcx>(
|
||||
}
|
||||
}
|
||||
|
||||
fn object_path_to_poly_trait_ref<'a,'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
trait_def_id: ast::DefId,
|
||||
path: &ast::Path,
|
||||
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
// we are introducing a binder here, so shift the
|
||||
// anonymous regions depth to account for that
|
||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
||||
|
||||
let mut tmp = Vec::new();
|
||||
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
|
||||
&shifted_rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
Some(&mut tmp)));
|
||||
projections.extend(tmp.into_iter().map(ty::Binder));
|
||||
trait_ref
|
||||
}
|
||||
|
||||
fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
@ -573,13 +603,6 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
debug!("ast_path_to_trait_ref {:?}", path);
|
||||
let trait_def = this.get_trait_def(trait_def_id);
|
||||
|
||||
// the trait reference introduces a binding level here, so
|
||||
// we need to shift the `rscope`. It'd be nice if we could
|
||||
// do away with this rscope stuff and work this knowledge
|
||||
// into resolve_lifetimes, as we do with non-omitted
|
||||
// lifetimes. Oh well, not there yet.
|
||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
||||
|
||||
let (regions, types, assoc_bindings) = match path.segments.last().unwrap().parameters {
|
||||
ast::AngleBracketedParameters(ref data) => {
|
||||
// For now, require that parenthetical notation be used
|
||||
@ -595,7 +618,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
the crate attributes to enable");
|
||||
}
|
||||
|
||||
convert_angle_bracketed_parameters(this, &shifted_rscope, data)
|
||||
convert_angle_bracketed_parameters(this, rscope, data)
|
||||
}
|
||||
ast::ParenthesizedParameters(ref data) => {
|
||||
// For now, require that parenthetical notation be used
|
||||
@ -616,7 +639,7 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
};
|
||||
|
||||
let substs = create_substs_for_ast_path(this,
|
||||
&shifted_rscope,
|
||||
rscope,
|
||||
path.span,
|
||||
&trait_def.generics,
|
||||
self_ty,
|
||||
@ -851,15 +874,11 @@ fn ast_ty_to_trait_ref<'tcx>(this: &AstConv<'tcx>,
|
||||
match this.tcx().def_map.borrow().get(&id) {
|
||||
Some(&def::DefTrait(trait_def_id)) => {
|
||||
let mut projection_bounds = Vec::new();
|
||||
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
Some(&mut projection_bounds)));
|
||||
let projection_bounds = projection_bounds.into_iter()
|
||||
.map(ty::Binder)
|
||||
.collect();
|
||||
let trait_ref = object_path_to_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
path,
|
||||
&mut projection_bounds);
|
||||
Ok((trait_ref, projection_bounds))
|
||||
}
|
||||
_ => {
|
||||
@ -1098,16 +1117,13 @@ pub fn ast_ty_to_ty<'tcx>(
|
||||
// N.B. this case overlaps somewhat with
|
||||
// TyObjectSum, see that fn for details
|
||||
let mut projection_bounds = Vec::new();
|
||||
let trait_ref = ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
None,
|
||||
path,
|
||||
Some(&mut projection_bounds));
|
||||
let trait_ref = ty::Binder(trait_ref);
|
||||
let projection_bounds = projection_bounds.into_iter()
|
||||
.map(ty::Binder)
|
||||
.collect();
|
||||
|
||||
let trait_ref = object_path_to_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_def_id,
|
||||
path,
|
||||
&mut projection_bounds);
|
||||
|
||||
trait_ref_to_object_type(this, rscope, path.span,
|
||||
trait_ref, projection_bounds, &[])
|
||||
}
|
||||
|
48
src/librustc_typeck/coherence/impls.rs
Normal file
48
src/librustc_typeck/coherence/impls.rs
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
//! Implementations checker: builtin traits and default impls are allowed just
|
||||
//! for structs and enums.
|
||||
|
||||
use middle::ty;
|
||||
use syntax::ast::{Item, ItemImpl};
|
||||
use syntax::ast;
|
||||
use syntax::visit;
|
||||
|
||||
pub fn check(tcx: &ty::ctxt) {
|
||||
let mut impls = ImplsChecker { tcx: tcx };
|
||||
visit::walk_crate(&mut impls, tcx.map.krate());
|
||||
}
|
||||
|
||||
struct ImplsChecker<'cx, 'tcx:'cx> {
|
||||
tcx: &'cx ty::ctxt<'tcx>
|
||||
}
|
||||
|
||||
impl<'cx, 'tcx,'v> visit::Visitor<'v> for ImplsChecker<'cx, 'tcx> {
|
||||
fn visit_item(&mut self, item: &'v ast::Item) {
|
||||
match item.node {
|
||||
ast::ItemImpl(_, _, _, Some(ref opt_trait), _, _) => {
|
||||
let trait_ref = ty::node_id_to_trait_ref(self.tcx, opt_trait.ref_id);
|
||||
if let Some(_) = self.tcx.lang_items.to_builtin_kind(trait_ref.def_id) {
|
||||
match trait_ref.self_ty().sty {
|
||||
ty::ty_struct(..) | ty::ty_enum(..) => {}
|
||||
_ => {
|
||||
self.tcx.sess.span_err(
|
||||
item.span,
|
||||
&format!("builtin traits can only be \
|
||||
implemented on structs or enums")[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ use syntax::visit;
|
||||
use util::nodemap::{DefIdMap, FnvHashMap};
|
||||
use util::ppaux::Repr;
|
||||
|
||||
mod impls;
|
||||
mod orphan;
|
||||
mod overlap;
|
||||
mod unsafety;
|
||||
@ -596,6 +597,7 @@ pub fn check_coherence(crate_context: &CrateCtxt) {
|
||||
inference_context: new_infer_ctxt(crate_context.tcx),
|
||||
inherent_impls: RefCell::new(FnvHashMap::new()),
|
||||
}.check(crate_context.tcx.map.krate());
|
||||
impls::check(crate_context.tcx);
|
||||
unsafety::check(crate_context.tcx);
|
||||
orphan::check(crate_context.tcx);
|
||||
overlap::check(crate_context.tcx);
|
||||
|
@ -91,6 +91,7 @@ pub fn render(input: &str, mut output: Path, matches: &getopts::Matches,
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="generator" content="rustdoc">
|
||||
<title>{title}</title>
|
||||
|
||||
|
@ -21,6 +21,8 @@ use prelude::v1::*;
|
||||
use collections::HashMap;
|
||||
use ffi::CString;
|
||||
use fmt;
|
||||
// NOTE(stage0) remove import after a snapshot
|
||||
#[cfg(stage0)]
|
||||
use hash::Hash;
|
||||
use io::pipe::{PipeStream, PipePair};
|
||||
use io::{IoResult, IoError};
|
||||
|
@ -374,9 +374,13 @@ impl Rng for ThreadRng {
|
||||
/// `random()` can generate various types of random things, and so may require
|
||||
/// type hinting to generate the specific type you want.
|
||||
///
|
||||
/// This function uses the thread local random number generator. This means
|
||||
/// that if you're calling `random()` in a loop, caching the generator can
|
||||
/// increase performance. An example is shown below.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// ```
|
||||
/// use std::rand;
|
||||
///
|
||||
/// let x = rand::random();
|
||||
@ -389,6 +393,27 @@ impl Rng for ThreadRng {
|
||||
/// println!("Better lucky than good!");
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Caching the thread local random number generator:
|
||||
///
|
||||
/// ```
|
||||
/// use std::rand;
|
||||
/// use std::rand::Rng;
|
||||
///
|
||||
/// let mut v = vec![1, 2, 3];
|
||||
///
|
||||
/// for x in v.iter_mut() {
|
||||
/// *x = rand::random()
|
||||
/// }
|
||||
///
|
||||
/// // would be faster as
|
||||
///
|
||||
/// let mut rng = rand::thread_rng();
|
||||
///
|
||||
/// for x in v.iter_mut() {
|
||||
/// *x = rng.gen();
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn random<T: Rand>() -> T {
|
||||
thread_rng().gen()
|
||||
|
@ -63,6 +63,12 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
|
||||
'statement: loop {
|
||||
match state {
|
||||
Asm => {
|
||||
if asm_str_style.is_some() {
|
||||
// If we already have a string with instructions,
|
||||
// ending up in Asm state again is an error.
|
||||
cx.span_err(sp, "malformed inline assembly");
|
||||
return DummyResult::expr(sp);
|
||||
}
|
||||
let (s, style) = match expr_to_string(cx, p.parse_expr(),
|
||||
"inline assembly must be a string literal") {
|
||||
Some((s, st)) => (s, st),
|
||||
|
@ -92,11 +92,10 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
|
||||
let recurse = vec!(cx.ident_of(krate),
|
||||
cx.ident_of("Decodable"),
|
||||
cx.ident_of("decode"));
|
||||
let exprdecode = cx.expr_path(cx.path_global(trait_span, recurse));
|
||||
// throw an underscore in front to suppress unused variable warnings
|
||||
let blkarg = cx.ident_of("_d");
|
||||
let blkdecoder = cx.expr_ident(trait_span, blkarg);
|
||||
let calldecode = cx.expr_call_global(trait_span, recurse, vec!(blkdecoder.clone()));
|
||||
let lambdadecode = cx.lambda_expr_1(trait_span, calldecode, blkarg);
|
||||
|
||||
return match *substr.fields {
|
||||
StaticStruct(_, ref summary) => {
|
||||
@ -116,7 +115,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
|
||||
cx.expr_method_call(span, blkdecoder.clone(), read_struct_field,
|
||||
vec!(cx.expr_str(span, name),
|
||||
cx.expr_uint(span, field),
|
||||
lambdadecode.clone())))
|
||||
exprdecode.clone())))
|
||||
});
|
||||
let result = cx.expr_ok(trait_span, result);
|
||||
cx.expr_method_call(trait_span,
|
||||
@ -147,7 +146,7 @@ fn decodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
|
||||
let idx = cx.expr_uint(span, field);
|
||||
cx.expr_try(span,
|
||||
cx.expr_method_call(span, blkdecoder.clone(), rvariant_arg,
|
||||
vec!(idx, lambdadecode.clone())))
|
||||
vec!(idx, exprdecode.clone())))
|
||||
});
|
||||
|
||||
arms.push(cx.arm(v_span,
|
||||
|
@ -21,13 +21,7 @@
|
||||
//! (e.g. `Option<T>`), the parameters are automatically given the
|
||||
//! current trait as a bound. (This includes separate type parameters
|
||||
//! and lifetimes for methods.)
|
||||
//! - Additional bounds on the type parameters, e.g. the `Ord` instance
|
||||
//! requires an explicit `PartialEq` bound at the
|
||||
//! moment. (`TraitDef.additional_bounds`)
|
||||
//!
|
||||
//! Unsupported: FIXME #6257: calling methods on reference fields,
|
||||
//! e.g. derive Eq/Ord/Clone don't work on `struct A(&int)`,
|
||||
//! because of how the auto-dereferencing happens.
|
||||
//! - Additional bounds on the type parameters (`TraitDef.additional_bounds`)
|
||||
//!
|
||||
//! The most important thing for implementers is the `Substructure` and
|
||||
//! `SubstructureFields` objects. The latter groups 5 possibilities of the
|
||||
@ -79,6 +73,15 @@
|
||||
//! enums (one for each variant). For empty struct and empty enum
|
||||
//! variants, it is represented as a count of 0.
|
||||
//!
|
||||
//! # "`cs`" functions
|
||||
//!
|
||||
//! The `cs_...` functions ("combine substructure) are designed to
|
||||
//! make life easier by providing some pre-made recipes for common
|
||||
//! tasks; mostly calling the function being derived on all the
|
||||
//! arguments and then combining them back together in some way (or
|
||||
//! letting the user chose that). They are not meant to be the only
|
||||
//! way to handle the structures that this code creates.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! The following simplified `PartialEq` is used for in-code examples:
|
||||
@ -102,22 +105,22 @@
|
||||
//! When generating the `expr` for the `A` impl, the `SubstructureFields` is
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! Struct(~[FieldInfo {
|
||||
//! Struct(vec![FieldInfo {
|
||||
//! span: <span of x>
|
||||
//! name: Some(<ident of x>),
|
||||
//! self_: <expr for &self.x>,
|
||||
//! other: ~[<expr for &other.x]
|
||||
//! other: vec![<expr for &other.x]
|
||||
//! }])
|
||||
//! ```
|
||||
//!
|
||||
//! For the `B` impl, called with `B(a)` and `B(b)`,
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! Struct(~[FieldInfo {
|
||||
//! Struct(vec![FieldInfo {
|
||||
//! span: <span of `int`>,
|
||||
//! name: None,
|
||||
//! <expr for &a>
|
||||
//! ~[<expr for &b>]
|
||||
//! self_: <expr for &a>
|
||||
//! other: vec![<expr for &b>]
|
||||
//! }])
|
||||
//! ```
|
||||
//!
|
||||
@ -128,11 +131,11 @@
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! EnumMatching(0, <ast::Variant for C0>,
|
||||
//! ~[FieldInfo {
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of int>
|
||||
//! name: None,
|
||||
//! self_: <expr for &a>,
|
||||
//! other: ~[<expr for &b>]
|
||||
//! other: vec![<expr for &b>]
|
||||
//! }])
|
||||
//! ```
|
||||
//!
|
||||
@ -140,11 +143,11 @@
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! EnumMatching(1, <ast::Variant for C1>,
|
||||
//! ~[FieldInfo {
|
||||
//! vec![FieldInfo {
|
||||
//! span: <span of x>
|
||||
//! name: Some(<ident of x>),
|
||||
//! self_: <expr for &self.x>,
|
||||
//! other: ~[<expr for &other.x>]
|
||||
//! other: vec![<expr for &other.x>]
|
||||
//! }])
|
||||
//! ```
|
||||
//!
|
||||
@ -152,7 +155,7 @@
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! EnumNonMatchingCollapsed(
|
||||
//! ~[<ident of self>, <ident of __arg_1>],
|
||||
//! vec![<ident of self>, <ident of __arg_1>],
|
||||
//! &[<ast::Variant for C0>, <ast::Variant for C1>],
|
||||
//! &[<ident for self index value>, <ident of __arg_1 index value>])
|
||||
//! ```
|
||||
@ -168,16 +171,16 @@
|
||||
//!
|
||||
//! ## Static
|
||||
//!
|
||||
//! A static method on the above would result in,
|
||||
//! A static method on the types above would result in,
|
||||
//!
|
||||
//! ```{.text}
|
||||
//! StaticStruct(<ast::StructDef of A>, Named(~[(<ident of x>, <span of x>)]))
|
||||
//! StaticStruct(<ast::StructDef of A>, Named(vec![(<ident of x>, <span of x>)]))
|
||||
//!
|
||||
//! StaticStruct(<ast::StructDef of B>, Unnamed(~[<span of x>]))
|
||||
//! StaticStruct(<ast::StructDef of B>, Unnamed(vec![<span of x>]))
|
||||
//!
|
||||
//! StaticEnum(<ast::EnumDef of C>, ~[(<ident of C0>, <span of C0>, Unnamed(~[<span of int>])),
|
||||
//! (<ident of C1>, <span of C1>,
|
||||
//! Named(~[(<ident of x>, <span of x>)]))])
|
||||
//! StaticEnum(<ast::EnumDef of C>,
|
||||
//! vec![(<ident of C0>, <span of C0>, Unnamed(vec![<span of int>])),
|
||||
//! (<ident of C1>, <span of C1>, Named(vec![(<ident of x>, <span of x>)]))])
|
||||
//! ```
|
||||
|
||||
pub use self::StaticFields::*;
|
||||
@ -1378,8 +1381,8 @@ pub fn cs_fold<F>(use_foldl: bool,
|
||||
/// process the collected results. i.e.
|
||||
///
|
||||
/// ```
|
||||
/// f(cx, span, ~[self_1.method(__arg_1_1, __arg_2_1),
|
||||
/// self_2.method(__arg_1_2, __arg_2_2)])
|
||||
/// f(cx, span, vec![self_1.method(__arg_1_1, __arg_2_1),
|
||||
/// self_2.method(__arg_1_2, __arg_2_2)])
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn cs_same_method<F>(f: F,
|
||||
|
@ -65,9 +65,19 @@ fn hash_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
|
||||
[ref state_expr] => state_expr,
|
||||
_ => cx.span_bug(trait_span, "incorrect number of arguments in `deriving(Hash)`")
|
||||
};
|
||||
let hash_ident = substr.method_ident;
|
||||
let call_hash = |&: span, thing_expr| {
|
||||
let expr = cx.expr_method_call(span, thing_expr, hash_ident, vec!(state_expr.clone()));
|
||||
let hash_path = {
|
||||
let strs = vec![
|
||||
cx.ident_of("std"),
|
||||
cx.ident_of("hash"),
|
||||
cx.ident_of("Hash"),
|
||||
cx.ident_of("hash"),
|
||||
];
|
||||
|
||||
cx.expr_path(cx.path_global(span, strs))
|
||||
};
|
||||
let ref_thing = cx.expr_addr_of(span, thing_expr);
|
||||
let expr = cx.expr_call(span, hash_path, vec!(ref_thing, state_expr.clone()));
|
||||
cx.stmt_expr(expr)
|
||||
};
|
||||
let mut stmts = Vec::new();
|
||||
|
@ -24,14 +24,6 @@ use ptr::P;
|
||||
pub enum ObsoleteSyntax {
|
||||
Sized,
|
||||
ForSized,
|
||||
OwnedType,
|
||||
OwnedExpr,
|
||||
OwnedPattern,
|
||||
OwnedVector,
|
||||
OwnedSelf,
|
||||
ImportRenaming,
|
||||
SubsliceMatch,
|
||||
ExternCrateRenaming,
|
||||
ProcType,
|
||||
ProcExpr,
|
||||
ClosureType,
|
||||
@ -69,38 +61,6 @@ impl<'a> ParserObsoleteMethods for parser::Parser<'a> {
|
||||
"`proc` expression",
|
||||
"use a `move ||` expression instead",
|
||||
),
|
||||
ObsoleteSyntax::OwnedType => (
|
||||
"`~` notation for owned pointers",
|
||||
"use `Box<T>` in `std::owned` instead"
|
||||
),
|
||||
ObsoleteSyntax::OwnedExpr => (
|
||||
"`~` notation for owned pointer allocation",
|
||||
"use the `box` operator instead of `~`"
|
||||
),
|
||||
ObsoleteSyntax::OwnedPattern => (
|
||||
"`~` notation for owned pointer patterns",
|
||||
"use the `box` operator instead of `~`"
|
||||
),
|
||||
ObsoleteSyntax::OwnedVector => (
|
||||
"`~[T]` is no longer a type",
|
||||
"use the `Vec` type instead"
|
||||
),
|
||||
ObsoleteSyntax::OwnedSelf => (
|
||||
"`~self` is no longer supported",
|
||||
"write `self: Box<Self>` instead"
|
||||
),
|
||||
ObsoleteSyntax::ImportRenaming => (
|
||||
"`use foo = bar` syntax",
|
||||
"write `use bar as foo` instead"
|
||||
),
|
||||
ObsoleteSyntax::SubsliceMatch => (
|
||||
"subslice match syntax",
|
||||
"instead of `..xs`, write `xs..` in a pattern"
|
||||
),
|
||||
ObsoleteSyntax::ExternCrateRenaming => (
|
||||
"`extern crate foo = bar` syntax",
|
||||
"write `extern crate bar as foo` instead"
|
||||
),
|
||||
ObsoleteSyntax::ClosureType => (
|
||||
"`|uint| -> bool` closure type syntax",
|
||||
"use unboxed closures instead, no type annotation needed"
|
||||
|
@ -52,7 +52,7 @@ use ast::{SelfExplicit, SelfRegion, SelfStatic, SelfValue};
|
||||
use ast::{Delimited, SequenceRepetition, TokenTree, TraitItem, TraitRef};
|
||||
use ast::{TtDelimited, TtSequence, TtToken};
|
||||
use ast::{TupleVariantKind, Ty, Ty_, TypeBinding};
|
||||
use ast::{TypeField, TyFixedLengthVec, TyBareFn};
|
||||
use ast::{TyFixedLengthVec, TyBareFn};
|
||||
use ast::{TyTypeof, TyInfer, TypeMethod};
|
||||
use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
|
||||
use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
|
||||
@ -71,7 +71,7 @@ use parse::attr::ParserAttr;
|
||||
use parse::classify;
|
||||
use parse::common::{SeqSep, seq_sep_none, seq_sep_trailing_allowed};
|
||||
use parse::lexer::{Reader, TokenAndSpan};
|
||||
use parse::obsolete::*;
|
||||
use parse::obsolete::{ParserObsoleteMethods, ObsoleteSyntax};
|
||||
use parse::token::{self, MatchNt, SubstNt, SpecialVarNt, InternedString};
|
||||
use parse::token::{keywords, special_idents, SpecialMacroVar};
|
||||
use parse::{new_sub_parser_from_file, ParseSess};
|
||||
@ -1404,22 +1404,6 @@ impl<'a> Parser<'a> {
|
||||
MutTy { ty: t, mutbl: mutbl }
|
||||
}
|
||||
|
||||
/// Parse [mut/const/imm] ID : TY
|
||||
/// now used only by obsolete record syntax parser...
|
||||
pub fn parse_ty_field(&mut self) -> TypeField {
|
||||
let lo = self.span.lo;
|
||||
let mutbl = self.parse_mutability();
|
||||
let id = self.parse_ident();
|
||||
self.expect(&token::Colon);
|
||||
let ty = self.parse_ty_sum();
|
||||
let hi = ty.span.hi;
|
||||
ast::TypeField {
|
||||
ident: id,
|
||||
mt: MutTy { ty: ty, mutbl: mutbl },
|
||||
span: mk_sp(lo, hi),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse optional return type [ -> TY ] in function decl
|
||||
pub fn parse_ret_ty(&mut self) -> FunctionRetTy {
|
||||
if self.eat(&token::RArrow) {
|
||||
@ -1506,17 +1490,6 @@ impl<'a> Parser<'a> {
|
||||
} else {
|
||||
TyTup(ts)
|
||||
}
|
||||
} else if self.token == token::Tilde {
|
||||
// OWNED POINTER
|
||||
self.bump();
|
||||
let last_span = self.last_span;
|
||||
match self.token {
|
||||
token::OpenDelim(token::Bracket) => {
|
||||
self.obsolete(last_span, ObsoleteSyntax::OwnedVector)
|
||||
}
|
||||
_ => self.obsolete(last_span, ObsoleteSyntax::OwnedType)
|
||||
}
|
||||
TyTup(vec![self.parse_ty()])
|
||||
} else if self.check(&token::BinOp(token::Star)) {
|
||||
// STAR POINTER (bare pointer?)
|
||||
self.bump();
|
||||
@ -2830,20 +2803,6 @@ impl<'a> Parser<'a> {
|
||||
hi = e.span.hi;
|
||||
ex = ExprAddrOf(m, e);
|
||||
}
|
||||
token::Tilde => {
|
||||
self.bump();
|
||||
let last_span = self.last_span;
|
||||
match self.token {
|
||||
token::OpenDelim(token::Bracket) => {
|
||||
self.obsolete(last_span, ObsoleteSyntax::OwnedVector)
|
||||
},
|
||||
_ => self.obsolete(last_span, ObsoleteSyntax::OwnedExpr)
|
||||
}
|
||||
|
||||
let e = self.parse_prefix_expr();
|
||||
hi = e.span.hi;
|
||||
ex = self.mk_unary(UnUniq, e);
|
||||
}
|
||||
token::DotDot if !self.restrictions.contains(RESTRICTION_NO_DOTS) => {
|
||||
// A range, closed above: `..expr`.
|
||||
self.bump();
|
||||
@ -3249,10 +3208,6 @@ impl<'a> Parser<'a> {
|
||||
span: self.span,
|
||||
}));
|
||||
before_slice = false;
|
||||
} else {
|
||||
let _ = self.parse_pat();
|
||||
let span = self.span;
|
||||
self.obsolete(span, ObsoleteSyntax::SubsliceMatch);
|
||||
}
|
||||
continue
|
||||
}
|
||||
@ -3361,20 +3316,6 @@ impl<'a> Parser<'a> {
|
||||
span: mk_sp(lo, hi)
|
||||
})
|
||||
}
|
||||
token::Tilde => {
|
||||
// parse ~pat
|
||||
self.bump();
|
||||
let sub = self.parse_pat();
|
||||
pat = PatBox(sub);
|
||||
let last_span = self.last_span;
|
||||
hi = last_span.hi;
|
||||
self.obsolete(last_span, ObsoleteSyntax::OwnedPattern);
|
||||
return P(ast::Pat {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: pat,
|
||||
span: mk_sp(lo, hi)
|
||||
})
|
||||
}
|
||||
token::BinOp(token::And) | token::AndAnd => {
|
||||
// parse &pat and &mut pat
|
||||
let lo = self.span.lo;
|
||||
@ -4483,16 +4424,6 @@ impl<'a> Parser<'a> {
|
||||
self_ident_hi = self.last_span.hi;
|
||||
eself
|
||||
}
|
||||
token::Tilde => {
|
||||
// We need to make sure it isn't a type
|
||||
if self.look_ahead(1, |t| t.is_keyword(keywords::Self)) {
|
||||
self.bump();
|
||||
drop(self.expect_self_ident());
|
||||
let last_span = self.last_span;
|
||||
self.obsolete(last_span, ObsoleteSyntax::OwnedSelf)
|
||||
}
|
||||
SelfStatic
|
||||
}
|
||||
token::BinOp(token::Star) => {
|
||||
// Possibly "*self" or "*mut self" -- not supported. Try to avoid
|
||||
// emitting cryptic "unexpected token" errors.
|
||||
@ -4533,15 +4464,6 @@ impl<'a> Parser<'a> {
|
||||
} else {
|
||||
SelfValue(self_ident)
|
||||
}
|
||||
} else if self.token.is_mutability() &&
|
||||
self.look_ahead(1, |t| *t == token::Tilde) &&
|
||||
self.look_ahead(2, |t| t.is_keyword(keywords::Self)) {
|
||||
mutbl_self = self.parse_mutability();
|
||||
self.bump();
|
||||
drop(self.expect_self_ident());
|
||||
let last_span = self.last_span;
|
||||
self.obsolete(last_span, ObsoleteSyntax::OwnedSelf);
|
||||
SelfStatic
|
||||
} else {
|
||||
SelfStatic
|
||||
}
|
||||
@ -5422,13 +5344,7 @@ impl<'a> Parser<'a> {
|
||||
let (maybe_path, ident) = match self.token {
|
||||
token::Ident(..) => {
|
||||
let the_ident = self.parse_ident();
|
||||
let path = if self.token == token::Eq {
|
||||
self.bump();
|
||||
let path = self.parse_str();
|
||||
let span = self.span;
|
||||
self.obsolete(span, ObsoleteSyntax::ExternCrateRenaming);
|
||||
Some(path)
|
||||
} else if self.eat_keyword(keywords::As) {
|
||||
let path = if self.eat_keyword(keywords::As) {
|
||||
// skip the ident if there is one
|
||||
if self.token.is_ident() { self.bump(); }
|
||||
|
||||
@ -5698,17 +5614,7 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
// either a view item or an item:
|
||||
if self.eat_keyword(keywords::Extern) {
|
||||
let next_is_mod = self.eat_keyword(keywords::Mod);
|
||||
|
||||
if next_is_mod || self.eat_keyword(keywords::Crate) {
|
||||
if next_is_mod {
|
||||
let last_span = self.last_span;
|
||||
self.span_err(mk_sp(lo, last_span.hi),
|
||||
&format!("`extern mod` is obsolete, use \
|
||||
`extern crate` instead \
|
||||
to refer to external \
|
||||
crates.")[])
|
||||
}
|
||||
if self.eat_keyword(keywords::Crate) {
|
||||
return self.parse_item_extern_crate(lo, visibility, attrs);
|
||||
}
|
||||
|
||||
@ -6075,35 +5981,7 @@ impl<'a> Parser<'a> {
|
||||
|
||||
let first_ident = self.parse_ident();
|
||||
let mut path = vec!(first_ident);
|
||||
match self.token {
|
||||
token::Eq => {
|
||||
// x = foo::bar
|
||||
self.bump();
|
||||
let path_lo = self.span.lo;
|
||||
path = vec!(self.parse_ident());
|
||||
while self.check(&token::ModSep) {
|
||||
self.bump();
|
||||
let id = self.parse_ident();
|
||||
path.push(id);
|
||||
}
|
||||
let span = mk_sp(path_lo, self.span.hi);
|
||||
self.obsolete(span, ObsoleteSyntax::ImportRenaming);
|
||||
let path = ast::Path {
|
||||
span: span,
|
||||
global: false,
|
||||
segments: path.into_iter().map(|identifier| {
|
||||
ast::PathSegment {
|
||||
identifier: identifier,
|
||||
parameters: ast::PathParameters::none(),
|
||||
}
|
||||
}).collect()
|
||||
};
|
||||
return P(spanned(lo, self.span.hi,
|
||||
ViewPathSimple(first_ident, path,
|
||||
ast::DUMMY_NODE_ID)));
|
||||
}
|
||||
|
||||
token::ModSep => {
|
||||
if let token::ModSep = self.token {
|
||||
// foo::bar or foo::{a,b,c} or foo::*
|
||||
while self.check(&token::ModSep) {
|
||||
self.bump();
|
||||
@ -6156,8 +6034,6 @@ impl<'a> Parser<'a> {
|
||||
_ => break
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
let mut rename_to = path[path.len() - 1u];
|
||||
let path = ast::Path {
|
||||
|
@ -59,10 +59,6 @@
|
||||
//! line (which it can't) and so naturally place the content on its own line to
|
||||
//! avoid combining it with other lines and making matters even worse.
|
||||
|
||||
pub use self::PrintStackBreak::*;
|
||||
pub use self::Breaks::*;
|
||||
pub use self::Token::*;
|
||||
|
||||
use std::io;
|
||||
use std::string;
|
||||
use std::iter::repeat;
|
||||
@ -87,7 +83,7 @@ pub struct BeginToken {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Token {
|
||||
String(string::String, int),
|
||||
String(String, int),
|
||||
Break(BreakToken),
|
||||
Begin(BeginToken),
|
||||
End,
|
||||
@ -96,12 +92,15 @@ pub enum Token {
|
||||
|
||||
impl Token {
|
||||
pub fn is_eof(&self) -> bool {
|
||||
match *self { Eof => true, _ => false }
|
||||
match *self {
|
||||
Token::Eof => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_hardbreak_tok(&self) -> bool {
|
||||
match *self {
|
||||
Break(BreakToken {
|
||||
Token::Break(BreakToken {
|
||||
offset: 0,
|
||||
blank_space: bs
|
||||
}) if bs == SIZE_INFINITY =>
|
||||
@ -112,22 +111,22 @@ impl Token {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tok_str(t: Token) -> string::String {
|
||||
match t {
|
||||
String(s, len) => return format!("STR({},{})", s, len),
|
||||
Break(_) => return "BREAK".to_string(),
|
||||
Begin(_) => return "BEGIN".to_string(),
|
||||
End => return "END".to_string(),
|
||||
Eof => return "EOF".to_string()
|
||||
pub fn tok_str(token: &Token) -> String {
|
||||
match *token {
|
||||
Token::String(ref s, len) => format!("STR({},{})", s, len),
|
||||
Token::Break(_) => "BREAK".to_string(),
|
||||
Token::Begin(_) => "BEGIN".to_string(),
|
||||
Token::End => "END".to_string(),
|
||||
Token::Eof => "EOF".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buf_str(toks: Vec<Token>,
|
||||
szs: Vec<int>,
|
||||
pub fn buf_str(toks: &[Token],
|
||||
szs: &[int],
|
||||
left: uint,
|
||||
right: uint,
|
||||
lim: uint)
|
||||
-> string::String {
|
||||
-> String {
|
||||
let n = toks.len();
|
||||
assert_eq!(n, szs.len());
|
||||
let mut i = left;
|
||||
@ -140,7 +139,7 @@ pub fn buf_str(toks: Vec<Token>,
|
||||
}
|
||||
s.push_str(&format!("{}={}",
|
||||
szs[i],
|
||||
tok_str(toks[i].clone()))[]);
|
||||
tok_str(&toks[i]))[]);
|
||||
i += 1u;
|
||||
i %= n;
|
||||
}
|
||||
@ -167,7 +166,7 @@ pub fn mk_printer(out: Box<io::Writer+'static>, linewidth: uint) -> Printer {
|
||||
// fall behind.
|
||||
let n: uint = 3 * linewidth;
|
||||
debug!("mk_printer {}", linewidth);
|
||||
let token: Vec<Token> = repeat(Eof).take(n).collect();
|
||||
let token: Vec<Token> = repeat(Token::Eof).take(n).collect();
|
||||
let size: Vec<int> = repeat(0i).take(n).collect();
|
||||
let scan_stack: Vec<uint> = repeat(0u).take(n).collect();
|
||||
Printer {
|
||||
@ -312,20 +311,18 @@ impl Printer {
|
||||
pub fn replace_last_token(&mut self, t: Token) {
|
||||
self.token[self.right] = t;
|
||||
}
|
||||
pub fn pretty_print(&mut self, t: Token) -> io::IoResult<()> {
|
||||
pub fn pretty_print(&mut self, token: Token) -> io::IoResult<()> {
|
||||
debug!("pp ~[{},{}]", self.left, self.right);
|
||||
match t {
|
||||
Eof => {
|
||||
match token {
|
||||
Token::Eof => {
|
||||
if !self.scan_stack_empty {
|
||||
self.check_stack(0);
|
||||
let left = self.token[self.left].clone();
|
||||
let left_size = self.size[self.left];
|
||||
try!(self.advance_left(left, left_size));
|
||||
try!(self.advance_left());
|
||||
}
|
||||
self.indent(0);
|
||||
Ok(())
|
||||
}
|
||||
Begin(b) => {
|
||||
Token::Begin(b) => {
|
||||
if self.scan_stack_empty {
|
||||
self.left_total = 1;
|
||||
self.right_total = 1;
|
||||
@ -334,27 +331,27 @@ impl Printer {
|
||||
} else { self.advance_right(); }
|
||||
debug!("pp Begin({})/buffer ~[{},{}]",
|
||||
b.offset, self.left, self.right);
|
||||
self.token[self.right] = t;
|
||||
self.token[self.right] = token;
|
||||
self.size[self.right] = -self.right_total;
|
||||
let right = self.right;
|
||||
self.scan_push(right);
|
||||
Ok(())
|
||||
}
|
||||
End => {
|
||||
Token::End => {
|
||||
if self.scan_stack_empty {
|
||||
debug!("pp End/print ~[{},{}]", self.left, self.right);
|
||||
self.print(t, 0)
|
||||
self.print(token, 0)
|
||||
} else {
|
||||
debug!("pp End/buffer ~[{},{}]", self.left, self.right);
|
||||
self.advance_right();
|
||||
self.token[self.right] = t;
|
||||
self.token[self.right] = token;
|
||||
self.size[self.right] = -1;
|
||||
let right = self.right;
|
||||
self.scan_push(right);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Break(b) => {
|
||||
Token::Break(b) => {
|
||||
if self.scan_stack_empty {
|
||||
self.left_total = 1;
|
||||
self.right_total = 1;
|
||||
@ -366,21 +363,21 @@ impl Printer {
|
||||
self.check_stack(0);
|
||||
let right = self.right;
|
||||
self.scan_push(right);
|
||||
self.token[self.right] = t;
|
||||
self.token[self.right] = token;
|
||||
self.size[self.right] = -self.right_total;
|
||||
self.right_total += b.blank_space;
|
||||
Ok(())
|
||||
}
|
||||
String(ref s, len) => {
|
||||
Token::String(s, len) => {
|
||||
if self.scan_stack_empty {
|
||||
debug!("pp String('{}')/print ~[{},{}]",
|
||||
*s, self.left, self.right);
|
||||
self.print(t.clone(), len)
|
||||
s, self.left, self.right);
|
||||
self.print(Token::String(s, len), len)
|
||||
} else {
|
||||
debug!("pp String('{}')/buffer ~[{},{}]",
|
||||
*s, self.left, self.right);
|
||||
s, self.left, self.right);
|
||||
self.advance_right();
|
||||
self.token[self.right] = t.clone();
|
||||
self.token[self.right] = Token::String(s, len);
|
||||
self.size[self.right] = len;
|
||||
self.right_total += len;
|
||||
self.check_stream()
|
||||
@ -401,9 +398,7 @@ impl Printer {
|
||||
self.size[scanned] = SIZE_INFINITY;
|
||||
}
|
||||
}
|
||||
let left = self.token[self.left].clone();
|
||||
let left_size = self.size[self.left];
|
||||
try!(self.advance_left(left, left_size));
|
||||
try!(self.advance_left());
|
||||
if self.left != self.right {
|
||||
try!(self.check_stream());
|
||||
}
|
||||
@ -450,42 +445,52 @@ impl Printer {
|
||||
self.right %= self.buf_len;
|
||||
assert!((self.right != self.left));
|
||||
}
|
||||
pub fn advance_left(&mut self, x: Token, l: int) -> io::IoResult<()> {
|
||||
pub fn advance_left(&mut self) -> io::IoResult<()> {
|
||||
debug!("advance_left ~[{},{}], sizeof({})={}", self.left, self.right,
|
||||
self.left, l);
|
||||
if l >= 0 {
|
||||
let ret = self.print(x.clone(), l);
|
||||
match x {
|
||||
Break(b) => self.left_total += b.blank_space,
|
||||
String(_, len) => {
|
||||
assert_eq!(len, l); self.left_total += len;
|
||||
}
|
||||
_ => ()
|
||||
self.left, self.size[self.left]);
|
||||
|
||||
let mut left_size = self.size[self.left];
|
||||
|
||||
while left_size >= 0 {
|
||||
let left = self.token[self.left].clone();
|
||||
|
||||
let len = match left {
|
||||
Token::Break(b) => b.blank_space,
|
||||
Token::String(_, len) => {
|
||||
assert_eq!(len, left_size);
|
||||
len
|
||||
}
|
||||
_ => 0
|
||||
};
|
||||
|
||||
try!(self.print(left, left_size));
|
||||
|
||||
self.left_total += len;
|
||||
|
||||
if self.left == self.right {
|
||||
break;
|
||||
}
|
||||
if self.left != self.right {
|
||||
self.left += 1u;
|
||||
self.left %= self.buf_len;
|
||||
let left = self.token[self.left].clone();
|
||||
let left_size = self.size[self.left];
|
||||
try!(self.advance_left(left, left_size));
|
||||
}
|
||||
ret
|
||||
} else {
|
||||
Ok(())
|
||||
|
||||
self.left += 1u;
|
||||
self.left %= self.buf_len;
|
||||
|
||||
left_size = self.size[self.left];
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub fn check_stack(&mut self, k: int) {
|
||||
if !self.scan_stack_empty {
|
||||
let x = self.scan_top();
|
||||
match self.token[x] {
|
||||
Begin(_) => {
|
||||
Token::Begin(_) => {
|
||||
if k > 0 {
|
||||
let popped = self.scan_pop();
|
||||
self.size[popped] = self.size[x] + self.right_total;
|
||||
self.check_stack(k - 1);
|
||||
}
|
||||
}
|
||||
End => {
|
||||
Token::End => {
|
||||
// paper says + not =, but that makes no sense.
|
||||
let popped = self.scan_pop();
|
||||
self.size[popped] = 1;
|
||||
@ -520,7 +525,7 @@ impl Printer {
|
||||
} else {
|
||||
PrintStackElem {
|
||||
offset: 0,
|
||||
pbreak: Broken(Inconsistent)
|
||||
pbreak: PrintStackBreak::Broken(Breaks::Inconsistent)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -531,56 +536,56 @@ impl Printer {
|
||||
}
|
||||
write!(self.out, "{}", s)
|
||||
}
|
||||
pub fn print(&mut self, x: Token, l: int) -> io::IoResult<()> {
|
||||
debug!("print {} {} (remaining line space={})", tok_str(x.clone()), l,
|
||||
pub fn print(&mut self, token: Token, l: int) -> io::IoResult<()> {
|
||||
debug!("print {} {} (remaining line space={})", tok_str(&token), l,
|
||||
self.space);
|
||||
debug!("{}", buf_str(self.token.clone(),
|
||||
self.size.clone(),
|
||||
debug!("{}", buf_str(&self.token[],
|
||||
&self.size[],
|
||||
self.left,
|
||||
self.right,
|
||||
6));
|
||||
match x {
|
||||
Begin(b) => {
|
||||
match token {
|
||||
Token::Begin(b) => {
|
||||
if l > self.space {
|
||||
let col = self.margin - self.space + b.offset;
|
||||
debug!("print Begin -> push broken block at col {}", col);
|
||||
self.print_stack.push(PrintStackElem {
|
||||
offset: col,
|
||||
pbreak: Broken(b.breaks)
|
||||
pbreak: PrintStackBreak::Broken(b.breaks)
|
||||
});
|
||||
} else {
|
||||
debug!("print Begin -> push fitting block");
|
||||
self.print_stack.push(PrintStackElem {
|
||||
offset: 0,
|
||||
pbreak: Fits
|
||||
pbreak: PrintStackBreak::Fits
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
End => {
|
||||
Token::End => {
|
||||
debug!("print End -> pop End");
|
||||
let print_stack = &mut self.print_stack;
|
||||
assert!((print_stack.len() != 0u));
|
||||
print_stack.pop().unwrap();
|
||||
Ok(())
|
||||
}
|
||||
Break(b) => {
|
||||
Token::Break(b) => {
|
||||
let top = self.get_top();
|
||||
match top.pbreak {
|
||||
Fits => {
|
||||
PrintStackBreak::Fits => {
|
||||
debug!("print Break({}) in fitting block", b.blank_space);
|
||||
self.space -= b.blank_space;
|
||||
self.indent(b.blank_space);
|
||||
Ok(())
|
||||
}
|
||||
Broken(Consistent) => {
|
||||
PrintStackBreak::Broken(Breaks::Consistent) => {
|
||||
debug!("print Break({}+{}) in consistent block",
|
||||
top.offset, b.offset);
|
||||
let ret = self.print_newline(top.offset + b.offset);
|
||||
self.space = self.margin - (top.offset + b.offset);
|
||||
ret
|
||||
}
|
||||
Broken(Inconsistent) => {
|
||||
PrintStackBreak::Broken(Breaks::Inconsistent) => {
|
||||
if l > self.space {
|
||||
debug!("print Break({}+{}) w/ newline in inconsistent",
|
||||
top.offset, b.offset);
|
||||
@ -597,14 +602,14 @@ impl Printer {
|
||||
}
|
||||
}
|
||||
}
|
||||
String(s, len) => {
|
||||
Token::String(s, len) => {
|
||||
debug!("print String({})", s);
|
||||
assert_eq!(l, len);
|
||||
// assert!(l <= space);
|
||||
self.space -= len;
|
||||
self.print_str(&s[])
|
||||
}
|
||||
Eof => {
|
||||
Token::Eof => {
|
||||
// Eof should never get here.
|
||||
panic!();
|
||||
}
|
||||
@ -616,41 +621,45 @@ impl Printer {
|
||||
//
|
||||
// "raw box"
|
||||
pub fn rbox(p: &mut Printer, indent: uint, b: Breaks) -> io::IoResult<()> {
|
||||
p.pretty_print(Begin(BeginToken {
|
||||
p.pretty_print(Token::Begin(BeginToken {
|
||||
offset: indent as int,
|
||||
breaks: b
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn ibox(p: &mut Printer, indent: uint) -> io::IoResult<()> {
|
||||
rbox(p, indent, Inconsistent)
|
||||
rbox(p, indent, Breaks::Inconsistent)
|
||||
}
|
||||
|
||||
pub fn cbox(p: &mut Printer, indent: uint) -> io::IoResult<()> {
|
||||
rbox(p, indent, Consistent)
|
||||
rbox(p, indent, Breaks::Consistent)
|
||||
}
|
||||
|
||||
pub fn break_offset(p: &mut Printer, n: uint, off: int) -> io::IoResult<()> {
|
||||
p.pretty_print(Break(BreakToken {
|
||||
p.pretty_print(Token::Break(BreakToken {
|
||||
offset: off,
|
||||
blank_space: n as int
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn end(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(End) }
|
||||
pub fn end(p: &mut Printer) -> io::IoResult<()> {
|
||||
p.pretty_print(Token::End)
|
||||
}
|
||||
|
||||
pub fn eof(p: &mut Printer) -> io::IoResult<()> { p.pretty_print(Eof) }
|
||||
pub fn eof(p: &mut Printer) -> io::IoResult<()> {
|
||||
p.pretty_print(Token::Eof)
|
||||
}
|
||||
|
||||
pub fn word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
|
||||
p.pretty_print(String(/* bad */ wrd.to_string(), wrd.len() as int))
|
||||
p.pretty_print(Token::String(/* bad */ wrd.to_string(), wrd.len() as int))
|
||||
}
|
||||
|
||||
pub fn huge_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
|
||||
p.pretty_print(String(/* bad */ wrd.to_string(), SIZE_INFINITY))
|
||||
p.pretty_print(Token::String(/* bad */ wrd.to_string(), SIZE_INFINITY))
|
||||
}
|
||||
|
||||
pub fn zero_word(p: &mut Printer, wrd: &str) -> io::IoResult<()> {
|
||||
p.pretty_print(String(/* bad */ wrd.to_string(), 0))
|
||||
p.pretty_print(Token::String(/* bad */ wrd.to_string(), 0))
|
||||
}
|
||||
|
||||
pub fn spaces(p: &mut Printer, n: uint) -> io::IoResult<()> {
|
||||
@ -670,7 +679,9 @@ pub fn hardbreak(p: &mut Printer) -> io::IoResult<()> {
|
||||
}
|
||||
|
||||
pub fn hardbreak_tok_offset(off: int) -> Token {
|
||||
Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
|
||||
Token::Break(BreakToken {offset: off, blank_space: SIZE_INFINITY})
|
||||
}
|
||||
|
||||
pub fn hardbreak_tok() -> Token { return hardbreak_tok_offset(0); }
|
||||
pub fn hardbreak_tok() -> Token {
|
||||
hardbreak_tok_offset(0)
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ use parse::token::{self, BinOpToken, Token};
|
||||
use parse::lexer::comments;
|
||||
use parse;
|
||||
use print::pp::{self, break_offset, word, space, zerobreak, hardbreak};
|
||||
use print::pp::{Breaks, Consistent, Inconsistent, eof};
|
||||
use print::pp::{Breaks, eof};
|
||||
use print::pp::Breaks::{Consistent, Inconsistent};
|
||||
use ptr::P;
|
||||
|
||||
use std::{ascii, mem};
|
||||
@ -459,7 +460,7 @@ fn needs_parentheses(expr: &ast::Expr) -> bool {
|
||||
|
||||
impl<'a> State<'a> {
|
||||
pub fn ibox(&mut self, u: uint) -> IoResult<()> {
|
||||
self.boxes.push(pp::Inconsistent);
|
||||
self.boxes.push(pp::Breaks::Inconsistent);
|
||||
pp::ibox(&mut self.s, u)
|
||||
}
|
||||
|
||||
@ -469,7 +470,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
pub fn cbox(&mut self, u: uint) -> IoResult<()> {
|
||||
self.boxes.push(pp::Consistent);
|
||||
self.boxes.push(pp::Breaks::Consistent);
|
||||
pp::cbox(&mut self.s, u)
|
||||
}
|
||||
|
||||
@ -531,11 +532,17 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
pub fn is_begin(&mut self) -> bool {
|
||||
match self.s.last_token() { pp::Begin(_) => true, _ => false }
|
||||
match self.s.last_token() {
|
||||
pp::Token::Begin(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_end(&mut self) -> bool {
|
||||
match self.s.last_token() { pp::End => true, _ => false }
|
||||
match self.s.last_token() {
|
||||
pp::Token::End => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// is this the beginning of a line?
|
||||
@ -545,7 +552,7 @@ impl<'a> State<'a> {
|
||||
|
||||
pub fn in_cbox(&self) -> bool {
|
||||
match self.boxes.last() {
|
||||
Some(&last_box) => last_box == pp::Consistent,
|
||||
Some(&last_box) => last_box == pp::Breaks::Consistent,
|
||||
None => false
|
||||
}
|
||||
}
|
||||
@ -1497,108 +1504,168 @@ impl<'a> State<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_expr_box(&mut self,
|
||||
place: &Option<P<ast::Expr>>,
|
||||
expr: &ast::Expr) -> IoResult<()> {
|
||||
try!(word(&mut self.s, "box"));
|
||||
try!(word(&mut self.s, "("));
|
||||
try!(place.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
|
||||
try!(self.word_space(")"));
|
||||
self.print_expr(expr)
|
||||
}
|
||||
|
||||
fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
|
||||
try!(self.ibox(indent_unit));
|
||||
try!(word(&mut self.s, "["));
|
||||
try!(self.commasep_exprs(Inconsistent, &exprs[]));
|
||||
try!(word(&mut self.s, "]"));
|
||||
self.end()
|
||||
}
|
||||
|
||||
fn print_expr_repeat(&mut self,
|
||||
element: &ast::Expr,
|
||||
count: &ast::Expr) -> IoResult<()> {
|
||||
try!(self.ibox(indent_unit));
|
||||
try!(word(&mut self.s, "["));
|
||||
try!(self.print_expr(element));
|
||||
try!(self.word_space(";"));
|
||||
try!(self.print_expr(count));
|
||||
try!(word(&mut self.s, "]"));
|
||||
self.end()
|
||||
}
|
||||
|
||||
fn print_expr_struct(&mut self,
|
||||
path: &ast::Path,
|
||||
fields: &[ast::Field],
|
||||
wth: &Option<P<ast::Expr>>) -> IoResult<()> {
|
||||
try!(self.print_path(path, true));
|
||||
if !(fields.is_empty() && wth.is_none()) {
|
||||
try!(word(&mut self.s, "{"));
|
||||
try!(self.commasep_cmnt(
|
||||
Consistent,
|
||||
&fields[],
|
||||
|s, field| {
|
||||
try!(s.ibox(indent_unit));
|
||||
try!(s.print_ident(field.ident.node));
|
||||
try!(s.word_space(":"));
|
||||
try!(s.print_expr(&*field.expr));
|
||||
s.end()
|
||||
},
|
||||
|f| f.span));
|
||||
match *wth {
|
||||
Some(ref expr) => {
|
||||
try!(self.ibox(indent_unit));
|
||||
if !fields.is_empty() {
|
||||
try!(word(&mut self.s, ","));
|
||||
try!(space(&mut self.s));
|
||||
}
|
||||
try!(word(&mut self.s, ".."));
|
||||
try!(self.print_expr(&**expr));
|
||||
try!(self.end());
|
||||
}
|
||||
_ => try!(word(&mut self.s, ",")),
|
||||
}
|
||||
try!(word(&mut self.s, "}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) -> IoResult<()> {
|
||||
try!(self.popen());
|
||||
try!(self.commasep_exprs(Inconsistent, &exprs[]));
|
||||
if exprs.len() == 1 {
|
||||
try!(word(&mut self.s, ","));
|
||||
}
|
||||
self.pclose()
|
||||
}
|
||||
|
||||
fn print_expr_call(&mut self,
|
||||
func: &ast::Expr,
|
||||
args: &[P<ast::Expr>]) -> IoResult<()> {
|
||||
try!(self.print_expr_maybe_paren(func));
|
||||
self.print_call_post(args)
|
||||
}
|
||||
|
||||
fn print_expr_method_call(&mut self,
|
||||
ident: ast::SpannedIdent,
|
||||
tys: &[P<ast::Ty>],
|
||||
args: &[P<ast::Expr>]) -> IoResult<()> {
|
||||
let base_args = args.slice_from(1);
|
||||
try!(self.print_expr(&*args[0]));
|
||||
try!(word(&mut self.s, "."));
|
||||
try!(self.print_ident(ident.node));
|
||||
if tys.len() > 0u {
|
||||
try!(word(&mut self.s, "::<"));
|
||||
try!(self.commasep(Inconsistent, tys,
|
||||
|s, ty| s.print_type(&**ty)));
|
||||
try!(word(&mut self.s, ">"));
|
||||
}
|
||||
self.print_call_post(base_args)
|
||||
}
|
||||
|
||||
fn print_expr_binary(&mut self,
|
||||
op: ast::BinOp,
|
||||
lhs: &ast::Expr,
|
||||
rhs: &ast::Expr) -> IoResult<()> {
|
||||
try!(self.print_expr(lhs));
|
||||
try!(space(&mut self.s));
|
||||
try!(self.word_space(ast_util::binop_to_string(op)));
|
||||
self.print_expr(rhs)
|
||||
}
|
||||
|
||||
fn print_expr_unary(&mut self,
|
||||
op: ast::UnOp,
|
||||
expr: &ast::Expr) -> IoResult<()> {
|
||||
try!(word(&mut self.s, ast_util::unop_to_string(op)));
|
||||
self.print_expr_maybe_paren(expr)
|
||||
}
|
||||
|
||||
fn print_expr_addr_of(&mut self,
|
||||
mutability: ast::Mutability,
|
||||
expr: &ast::Expr) -> IoResult<()> {
|
||||
try!(word(&mut self.s, "&"));
|
||||
try!(self.print_mutability(mutability));
|
||||
self.print_expr_maybe_paren(expr)
|
||||
}
|
||||
|
||||
pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
|
||||
try!(self.maybe_print_comment(expr.span.lo));
|
||||
try!(self.ibox(indent_unit));
|
||||
try!(self.ann.pre(self, NodeExpr(expr)));
|
||||
match expr.node {
|
||||
ast::ExprBox(ref p, ref e) => {
|
||||
try!(word(&mut self.s, "box"));
|
||||
try!(word(&mut self.s, "("));
|
||||
try!(p.as_ref().map_or(Ok(()), |e|self.print_expr(&**e)));
|
||||
try!(self.word_space(")"));
|
||||
try!(self.print_expr(&**e));
|
||||
ast::ExprBox(ref place, ref expr) => {
|
||||
try!(self.print_expr_box(place, &**expr));
|
||||
}
|
||||
ast::ExprVec(ref exprs) => {
|
||||
try!(self.ibox(indent_unit));
|
||||
try!(word(&mut self.s, "["));
|
||||
try!(self.commasep_exprs(Inconsistent, &exprs[]));
|
||||
try!(word(&mut self.s, "]"));
|
||||
try!(self.end());
|
||||
try!(self.print_expr_vec(&exprs[]));
|
||||
}
|
||||
|
||||
ast::ExprRepeat(ref element, ref count) => {
|
||||
try!(self.ibox(indent_unit));
|
||||
try!(word(&mut self.s, "["));
|
||||
try!(self.print_expr(&**element));
|
||||
try!(self.word_space(";"));
|
||||
try!(self.print_expr(&**count));
|
||||
try!(word(&mut self.s, "]"));
|
||||
try!(self.end());
|
||||
try!(self.print_expr_repeat(&**element, &**count));
|
||||
}
|
||||
|
||||
ast::ExprStruct(ref path, ref fields, ref wth) => {
|
||||
try!(self.print_path(path, true));
|
||||
if !(fields.is_empty() && wth.is_none()) {
|
||||
try!(word(&mut self.s, "{"));
|
||||
try!(self.commasep_cmnt(
|
||||
Consistent,
|
||||
&fields[],
|
||||
|s, field| {
|
||||
try!(s.ibox(indent_unit));
|
||||
try!(s.print_ident(field.ident.node));
|
||||
try!(s.word_space(":"));
|
||||
try!(s.print_expr(&*field.expr));
|
||||
s.end()
|
||||
},
|
||||
|f| f.span));
|
||||
match *wth {
|
||||
Some(ref expr) => {
|
||||
try!(self.ibox(indent_unit));
|
||||
if !fields.is_empty() {
|
||||
try!(word(&mut self.s, ","));
|
||||
try!(space(&mut self.s));
|
||||
}
|
||||
try!(word(&mut self.s, ".."));
|
||||
try!(self.print_expr(&**expr));
|
||||
try!(self.end());
|
||||
}
|
||||
_ => try!(word(&mut self.s, ",")),
|
||||
}
|
||||
try!(word(&mut self.s, "}"));
|
||||
}
|
||||
try!(self.print_expr_struct(path, &fields[], wth));
|
||||
}
|
||||
ast::ExprTup(ref exprs) => {
|
||||
try!(self.popen());
|
||||
try!(self.commasep_exprs(Inconsistent, &exprs[]));
|
||||
if exprs.len() == 1 {
|
||||
try!(word(&mut self.s, ","));
|
||||
}
|
||||
try!(self.pclose());
|
||||
try!(self.print_expr_tup(&exprs[]));
|
||||
}
|
||||
ast::ExprCall(ref func, ref args) => {
|
||||
try!(self.print_expr_maybe_paren(&**func));
|
||||
try!(self.print_call_post(&args[]));
|
||||
try!(self.print_expr_call(&**func, &args[]));
|
||||
}
|
||||
ast::ExprMethodCall(ident, ref tys, ref args) => {
|
||||
let base_args = args.slice_from(1);
|
||||
try!(self.print_expr(&*args[0]));
|
||||
try!(word(&mut self.s, "."));
|
||||
try!(self.print_ident(ident.node));
|
||||
if tys.len() > 0u {
|
||||
try!(word(&mut self.s, "::<"));
|
||||
try!(self.commasep(Inconsistent, &tys[],
|
||||
|s, ty| s.print_type(&**ty)));
|
||||
try!(word(&mut self.s, ">"));
|
||||
}
|
||||
try!(self.print_call_post(base_args));
|
||||
try!(self.print_expr_method_call(ident, &tys[], &args[]));
|
||||
}
|
||||
ast::ExprBinary(op, ref lhs, ref rhs) => {
|
||||
try!(self.print_expr(&**lhs));
|
||||
try!(space(&mut self.s));
|
||||
try!(self.word_space(ast_util::binop_to_string(op)));
|
||||
try!(self.print_expr(&**rhs));
|
||||
try!(self.print_expr_binary(op, &**lhs, &**rhs));
|
||||
}
|
||||
ast::ExprUnary(op, ref expr) => {
|
||||
try!(word(&mut self.s, ast_util::unop_to_string(op)));
|
||||
try!(self.print_expr_maybe_paren(&**expr));
|
||||
try!(self.print_expr_unary(op, &**expr));
|
||||
}
|
||||
ast::ExprAddrOf(m, ref expr) => {
|
||||
try!(word(&mut self.s, "&"));
|
||||
try!(self.print_mutability(m));
|
||||
try!(self.print_expr_maybe_paren(&**expr));
|
||||
try!(self.print_expr_addr_of(m, &**expr));
|
||||
}
|
||||
ast::ExprLit(ref lit) => {
|
||||
try!(self.print_literal(&**lit));
|
||||
}
|
||||
ast::ExprLit(ref lit) => try!(self.print_literal(&**lit)),
|
||||
ast::ExprCast(ref expr, ref ty) => {
|
||||
try!(self.print_expr(&**expr));
|
||||
try!(space(&mut self.s));
|
||||
@ -2891,7 +2958,7 @@ impl<'a> State<'a> {
|
||||
comments::BlankLine => {
|
||||
// We need to do at least one, possibly two hardbreaks.
|
||||
let is_semi = match self.s.last_token() {
|
||||
pp::String(s, _) => ";" == s,
|
||||
pp::Token::String(s, _) => ";" == s,
|
||||
_ => false
|
||||
};
|
||||
if is_semi || self.is_begin() || self.is_end() {
|
||||
|
@ -211,6 +211,8 @@ pub struct TestDesc {
|
||||
pub should_fail: ShouldFail,
|
||||
}
|
||||
|
||||
unsafe impl Send for TestDesc {}
|
||||
|
||||
#[derive(Show)]
|
||||
pub struct TestDescAndFn {
|
||||
pub desc: TestDesc,
|
||||
@ -525,6 +527,8 @@ pub enum TestResult {
|
||||
TrBench(BenchSamples),
|
||||
}
|
||||
|
||||
unsafe impl Send for TestResult {}
|
||||
|
||||
enum OutputLocation<T> {
|
||||
Pretty(Box<term::Terminal<term::WriterWrapper> + Send>),
|
||||
Raw(T),
|
||||
@ -978,7 +982,6 @@ enum TestEvent {
|
||||
|
||||
pub type MonitorMsg = (TestDesc, TestResult, Vec<u8> );
|
||||
|
||||
unsafe impl Send for MonitorMsg {}
|
||||
|
||||
fn run_tests<F>(opts: &TestOpts,
|
||||
tests: Vec<TestDescAndFn> ,
|
||||
@ -1332,10 +1335,11 @@ impl MetricMap {
|
||||
/// elimination.
|
||||
///
|
||||
/// This function is a no-op, and does not even read from `dummy`.
|
||||
pub fn black_box<T>(dummy: T) {
|
||||
pub fn black_box<T>(dummy: T) -> T {
|
||||
// we need to "use" the argument in some way LLVM can't
|
||||
// introspect.
|
||||
unsafe {asm!("" : : "r"(&dummy))}
|
||||
dummy
|
||||
}
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ use error::{Error, CliResult, CommandResult};
|
||||
use book;
|
||||
use book::{Book, BookItem};
|
||||
use css;
|
||||
use javascript;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
@ -63,7 +64,7 @@ fn write_toc(book: &Book, path_to_root: &Path, out: &mut Writer) -> IoResult<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
try!(writeln!(out, "<div id='toc'>"));
|
||||
try!(writeln!(out, "<div id='toc' class='mobile-hidden'>"));
|
||||
try!(writeln!(out, "<ul class='chapter'>"));
|
||||
try!(walk_items(&book.chapters[], "", path_to_root, out));
|
||||
try!(writeln!(out, "</ul>"));
|
||||
@ -102,6 +103,14 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
||||
let prelude = tmp.path().join("prelude.html");
|
||||
{
|
||||
let mut toc = BufferedWriter::new(try!(File::create(&prelude)));
|
||||
try!(writeln!(&mut toc, r#"<div id="nav">
|
||||
<button id="toggle-nav">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
<span class="bar"></span>
|
||||
</button>
|
||||
</div>"#));
|
||||
let _ = write_toc(book, &item.path_to_root, &mut toc);
|
||||
try!(writeln!(&mut toc, "<div id='page-wrapper'>"));
|
||||
try!(writeln!(&mut toc, "<div id='page'>"));
|
||||
@ -111,6 +120,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
|
||||
let postlude = tmp.path().join("postlude.html");
|
||||
{
|
||||
let mut toc = BufferedWriter::new(try!(File::create(&postlude)));
|
||||
try!(toc.write_str(javascript::JAVASCRIPT));
|
||||
try!(writeln!(&mut toc, "</div></div>"));
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,7 @@ body {
|
||||
#page {
|
||||
margin-left: auto;
|
||||
margin-right:auto;
|
||||
width: 750px;
|
||||
max-width: 750px;
|
||||
}
|
||||
|
||||
.chapter {
|
||||
@ -69,4 +69,58 @@ body {
|
||||
.chapter li a {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1060px) {
|
||||
#toc {
|
||||
width: 100%;
|
||||
margin-right: 0;
|
||||
top: 40px;
|
||||
}
|
||||
#page-wrapper {
|
||||
top: 40px;
|
||||
left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.mobile-hidden {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#toggle-nav {
|
||||
height: 20px;
|
||||
width: 30px;
|
||||
padding: 3px 3px 0 3px;
|
||||
}
|
||||
|
||||
#toggle-nav {
|
||||
margin-top: 5px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
background-color: #FFF;
|
||||
border: 1px solid #666;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
}
|
||||
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.bar {
|
||||
display: block;
|
||||
background-color: #000;
|
||||
border-radius: 2px;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
margin: 2px 0 3px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
"#;
|
||||
|
43
src/rustbook/javascript.rs
Normal file
43
src/rustbook/javascript.rs
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// The rust-book JavaScript in string form.
|
||||
|
||||
pub static JAVASCRIPT: &'static str = r#"
|
||||
<script type="text/javascript">
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
document.getElementById("toggle-nav").onclick = toggleNav;
|
||||
function toggleNav() {
|
||||
var toc = document.getElementById("toc");
|
||||
var pagewrapper = document.getElementById("page-wrapper");
|
||||
toggleClass(toc, "mobile-hidden");
|
||||
toggleClass(pagewrapper, "mobile-hidden");
|
||||
};
|
||||
|
||||
function toggleClass(el, className) {
|
||||
// from http://youmightnotneedjquery.com/
|
||||
if (el.classList) {
|
||||
el.classList.toggle(className);
|
||||
} else {
|
||||
var classes = el.className.split(' ');
|
||||
var existingIndex = classes.indexOf(className);
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
classes.splice(existingIndex, 1);
|
||||
} else {
|
||||
classes.push(className);
|
||||
}
|
||||
|
||||
el.className = classes.join(' ');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
"#;
|
@ -39,6 +39,7 @@ mod serve;
|
||||
mod test;
|
||||
|
||||
mod css;
|
||||
mod javascript;
|
||||
|
||||
#[cfg(not(test))] // thanks #12327
|
||||
fn main() {
|
||||
|
37
src/test/compile-fail/coherence-impls-builtin.rs
Normal file
37
src/test/compile-fail/coherence-impls-builtin.rs
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2015 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::marker::Send;
|
||||
|
||||
enum TestE {
|
||||
A
|
||||
}
|
||||
|
||||
struct MyType;
|
||||
|
||||
unsafe impl Send for TestE {}
|
||||
unsafe impl Send for MyType {}
|
||||
unsafe impl Send for (MyType, MyType) {}
|
||||
//~^ ERROR builtin traits can only be implemented on structs or enums
|
||||
|
||||
unsafe impl Send for &'static MyType {}
|
||||
//~^ ERROR builtin traits can only be implemented on structs or enums
|
||||
|
||||
unsafe impl Send for [MyType] {}
|
||||
//~^ ERROR builtin traits can only be implemented on structs or enums
|
||||
|
||||
unsafe impl Send for &'static [MyType] {}
|
||||
//~^ ERROR builtin traits can only be implemented on structs or enums
|
||||
|
||||
fn is_send<T: Send>() {}
|
||||
|
||||
fn main() {
|
||||
is_send::<(MyType, TestE)>();
|
||||
}
|
49
src/test/compile-fail/issue-20831-debruijn.rs
Normal file
49
src/test/compile-fail/issue-20831-debruijn.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// Regression test for #20831: debruijn index account was thrown off
|
||||
// by the (anonymous) lifetime in `<Self as Publisher>::Output`
|
||||
// below. Note that changing to a named lifetime made the problem go
|
||||
// away.
|
||||
|
||||
use std::ops::{Shl, Shr};
|
||||
use std::cell::RefCell;
|
||||
|
||||
pub trait Subscriber {
|
||||
type Input;
|
||||
}
|
||||
|
||||
pub trait Publisher<'a> {
|
||||
type Output;
|
||||
fn subscribe(&mut self, Box<Subscriber<Input=Self::Output> + 'a>);
|
||||
}
|
||||
|
||||
pub trait Processor<'a> : Subscriber + Publisher<'a> { }
|
||||
|
||||
impl<'a, P> Processor<'a> for P where P : Subscriber + Publisher<'a> { }
|
||||
|
||||
struct MyStruct<'a> {
|
||||
sub: Box<Subscriber<Input=u64> + 'a>
|
||||
}
|
||||
|
||||
impl<'a> Publisher<'a> for MyStruct<'a> {
|
||||
type Output = u64;
|
||||
fn subscribe(&mut self, t : Box<Subscriber<Input=<Self as Publisher>::Output> + 'a>) {
|
||||
// Not obvious, but there is an implicit lifetime here -------^
|
||||
//~^^ ERROR cannot infer
|
||||
//
|
||||
// The fact that `Publisher` is using an implicit lifetime is
|
||||
// what was causing the debruijn accounting to be off, so
|
||||
// leave it that way!
|
||||
self.sub = t;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -7,16 +7,10 @@
|
||||
// <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(asm)]
|
||||
|
||||
fn main() {
|
||||
let x = [1is, 2, 3];
|
||||
match x {
|
||||
[a, b, ..c] => { //~ ERROR obsolete syntax
|
||||
assert_eq!(a, 1);
|
||||
assert_eq!(b, 2);
|
||||
let expected: &[_] = &[3];
|
||||
assert_eq!(c, expected);
|
||||
}
|
||||
}
|
||||
let a;
|
||||
asm!("nop" "nop"); //~ ERROR malformed inline assembly
|
||||
asm!("nop" "nop" : "=r"(a)); //~ ERROR malformed inline assembly
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
@ -8,8 +8,14 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn main() {
|
||||
struct S(isize);
|
||||
let s = S(0);
|
||||
let x = *s; //~ ERROR single-field tuple-structs can no longer be dereferenced
|
||||
struct Bar;
|
||||
|
||||
impl Bar {
|
||||
fn hash<T>(&self, _: T) {}
|
||||
}
|
||||
|
||||
#[derive(Hash)]
|
||||
struct Foo(Bar);
|
||||
//~^ error: the trait `core::hash::Hash<__S>` is not implemented for the type `Bar`
|
||||
|
||||
fn main() {}
|
@ -1,21 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Test that ~ pointers give an obsolescence message.
|
||||
|
||||
fn foo(x: ~isize) {} //~ ERROR obsolete syntax: `~` notation for owned pointers
|
||||
fn bar(x: ~str) {} //~ ERROR obsolete syntax: `~` notation for owned pointers
|
||||
fn baz(x: ~[isize]) {} //~ ERROR obsolete syntax: `~[T]` is no longer a type
|
||||
|
||||
fn main() {
|
||||
let x = ~4is; //~ ERROR obsolete syntax: `~` notation for owned pointer allocation
|
||||
let y = ~"hello"; //~ ERROR obsolete syntax: `~` notation for owned pointer allocation
|
||||
let z = ~[1is, 2, 3]; //~ ERROR obsolete syntax: `~[T]` is no longer a type
|
||||
}
|
@ -48,7 +48,11 @@ fn zzz() {()}
|
||||
fn some_function(a: int, b: int) {
|
||||
let some_variable = Struct { a: 11, b: 22 };
|
||||
let some_other_variable = 23i;
|
||||
zzz(); // #break
|
||||
|
||||
for x in range(0, 1) {
|
||||
zzz(); // #break
|
||||
}
|
||||
}
|
||||
|
||||
fn some_other_function(a: int, b: int) -> bool { true }
|
||||
|
||||
|
@ -28,7 +28,7 @@ $(TMPDIR)/%.pp: %.rs
|
||||
|
||||
$(TMPDIR)/%.dot: %.rs
|
||||
$(eval $(call FIND_LAST_BLOCK,$<))
|
||||
$(RUSTC_LIB) -Z unstable-options --xpretty flowgraph=$(LASTBLOCKNUM_$<) $< -o $@.tmp
|
||||
$(RUSTC_LIB) -Z unstable-options --xpretty flowgraph,unlabelled=$(LASTBLOCKNUM_$<) $< -o $@.tmp
|
||||
cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \
|
||||
-e 's@\[label=""\]@@' \
|
||||
-e 's@digraph [a-zA-Z0-9_]* @digraph block @' \
|
||||
|
@ -34,7 +34,7 @@ digraph block {
|
||||
N11 -> N12;
|
||||
N12 -> N13;
|
||||
N13 -> N14;
|
||||
N14 -> N6[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2is { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1is; if x == 2is { break ; \"unreachable\"; } }"];
|
||||
N14 -> N6;
|
||||
N15 -> N16;
|
||||
N16 -> N17;
|
||||
N17 -> N18;
|
||||
|
@ -61,7 +61,7 @@ digraph block {
|
||||
N12 -> N13;
|
||||
N13 -> N14;
|
||||
N14 -> N15;
|
||||
N15 -> N9[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l }\l y -= 4is;\l x -= 5is;\l}\l"];
|
||||
N15 -> N9;
|
||||
N16 -> N17;
|
||||
N17 -> N18;
|
||||
N18 -> N19;
|
||||
@ -73,7 +73,7 @@ digraph block {
|
||||
N23 -> N24;
|
||||
N24 -> N25;
|
||||
N25 -> N26;
|
||||
N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2is { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { break \'outer ; \"unreachable\"; }\l if y >= 2is { break ; \"unreachable\"; }\l y -= 3is;\l}\l"];
|
||||
N26 -> N11;
|
||||
N27 -> N28;
|
||||
N28 -> N29;
|
||||
N29 -> N30;
|
||||
|
@ -64,7 +64,7 @@ digraph block {
|
||||
N12 -> N13;
|
||||
N13 -> N14;
|
||||
N14 -> N15;
|
||||
N15 -> N8[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1is { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l }\l y -= 1is;\l x -= 1is;\l}\l"];
|
||||
N15 -> N8;
|
||||
N16 -> N17;
|
||||
N17 -> N18;
|
||||
N18 -> N19;
|
||||
@ -76,7 +76,7 @@ digraph block {
|
||||
N23 -> N24;
|
||||
N24 -> N25;
|
||||
N25 -> N26;
|
||||
N26 -> N11[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1is { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1is { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1is { continue \'outer ; \"unreachable\"; }\l if y >= 1is { break ; \"unreachable\"; }\l y -= 1is;\l}\l"];
|
||||
N26 -> N11;
|
||||
N27 -> N28;
|
||||
N28 -> N29;
|
||||
N29 -> N30;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user