Merge branch 'master' into mulit-decor
This commit is contained in:
commit
103e52b1db
85 changed files with 2390 additions and 889 deletions
|
|
@ -253,7 +253,7 @@ The two values of the boolean type are written `true` and `false`.
|
|||
### Symbols
|
||||
|
||||
```antlr
|
||||
symbol : "::" "->"
|
||||
symbol : "::" | "->"
|
||||
| '#' | '[' | ']' | '(' | ')' | '{' | '}'
|
||||
| ',' | ';' ;
|
||||
```
|
||||
|
|
@ -304,7 +304,7 @@ transcriber : '(' transcriber * ')' | '[' transcriber * ']'
|
|||
## Items
|
||||
|
||||
```antlr
|
||||
item : mod_item | fn_item | type_item | struct_item | enum_item
|
||||
item : vis ? mod_item | fn_item | type_item | struct_item | enum_item
|
||||
| const_item | static_item | trait_item | impl_item | extern_block ;
|
||||
```
|
||||
|
||||
|
|
@ -322,7 +322,7 @@ mod : [ view_item | item ] * ;
|
|||
#### View items
|
||||
|
||||
```antlr
|
||||
view_item : extern_crate_decl | use_decl ;
|
||||
view_item : extern_crate_decl | use_decl ';' ;
|
||||
```
|
||||
|
||||
##### Extern crate declarations
|
||||
|
|
@ -335,14 +335,14 @@ crate_name: ident | ( ident "as" ident )
|
|||
##### Use declarations
|
||||
|
||||
```antlr
|
||||
use_decl : "pub" ? "use" [ path "as" ident
|
||||
| path_glob ] ;
|
||||
use_decl : vis ? "use" [ path "as" ident
|
||||
| path_glob ] ;
|
||||
|
||||
path_glob : ident [ "::" [ path_glob
|
||||
| '*' ] ] ?
|
||||
| '{' path_item [ ',' path_item ] * '}' ;
|
||||
|
||||
path_item : ident | "mod" ;
|
||||
path_item : ident | "self" ;
|
||||
```
|
||||
|
||||
### Functions
|
||||
|
|
@ -414,16 +414,17 @@ extern_block : [ foreign_fn ] * ;
|
|||
|
||||
## Visibility and Privacy
|
||||
|
||||
**FIXME:** grammar?
|
||||
|
||||
```antlr
|
||||
vis : "pub" ;
|
||||
```
|
||||
### Re-exporting and Visibility
|
||||
|
||||
**FIXME:** grammar?
|
||||
See [Use declarations](#use-declarations).
|
||||
|
||||
## Attributes
|
||||
|
||||
```antlr
|
||||
attribute : "#!" ? '[' meta_item ']' ;
|
||||
attribute : '#' '!' ? '[' meta_item ']' ;
|
||||
meta_item : ident [ '=' literal
|
||||
| '(' meta_seq ')' ] ? ;
|
||||
meta_seq : meta_item [ ',' meta_seq ] ? ;
|
||||
|
|
@ -433,26 +434,19 @@ meta_seq : meta_item [ ',' meta_seq ] ? ;
|
|||
|
||||
## Statements
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
stmt : decl_stmt | expr_stmt ;
|
||||
```
|
||||
|
||||
### Declaration statements
|
||||
|
||||
**FIXME:** grammar?
|
||||
|
||||
A _declaration statement_ is one that introduces one or more *names* into the
|
||||
enclosing statement block. The declared names may denote new variables or new
|
||||
items.
|
||||
```antlr
|
||||
decl_stmt : item | let_decl ;
|
||||
```
|
||||
|
||||
#### Item declarations
|
||||
|
||||
**FIXME:** grammar?
|
||||
|
||||
An _item declaration statement_ has a syntactic form identical to an
|
||||
[item](#items) declaration within a module. Declaring an item — a
|
||||
function, enumeration, structure, type, static, trait, implementation or module
|
||||
— locally within a statement block is simply a way of restricting its
|
||||
scope to a narrow region containing all of its uses; it is otherwise identical
|
||||
in meaning to declaring the item outside the statement block.
|
||||
See [Items](#items).
|
||||
|
||||
#### Variable declarations
|
||||
|
||||
|
|
@ -463,11 +457,21 @@ init : [ '=' ] expr ;
|
|||
|
||||
### Expression statements
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
expr_stmt : expr ';' ;
|
||||
```
|
||||
|
||||
## Expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
expr : literal | path | tuple_expr | unit_expr | struct_expr
|
||||
| block_expr | method_call_expr | field_expr | array_expr
|
||||
| idx_expr | range_expr | unop_expr | binop_expr
|
||||
| paren_expr | call_expr | lambda_expr | while_expr
|
||||
| loop_expr | break_expr | continue_expr | for_expr
|
||||
| if_expr | match_expr | if_let_expr | while_let_expr
|
||||
| return_expr ;
|
||||
```
|
||||
|
||||
#### Lvalues, rvalues and temporaries
|
||||
|
||||
|
|
@ -479,19 +483,23 @@ init : [ '=' ] expr ;
|
|||
|
||||
### Literal expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
See [Literals](#literals).
|
||||
|
||||
### Path expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
See [Paths](#paths).
|
||||
|
||||
### Tuple expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
tuple_expr : '(' [ expr [ ',' expr ] * | expr ',' ] ? ')' ;
|
||||
```
|
||||
|
||||
### Unit expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
unit_expr : "()" ;
|
||||
```
|
||||
|
||||
### Structure expressions
|
||||
|
||||
|
|
@ -507,8 +515,7 @@ struct_expr : expr_path '{' ident ':' expr
|
|||
### Block expressions
|
||||
|
||||
```antlr
|
||||
block_expr : '{' [ view_item ] *
|
||||
[ stmt ';' | item ] *
|
||||
block_expr : '{' [ stmt ';' | item ] *
|
||||
[ expr ] '}' ;
|
||||
```
|
||||
|
||||
|
|
@ -529,7 +536,7 @@ field_expr : expr '.' ident ;
|
|||
```antlr
|
||||
array_expr : '[' "mut" ? array_elems? ']' ;
|
||||
|
||||
array_elems : [expr [',' expr]*] | [expr ',' ".." expr] ;
|
||||
array_elems : [expr [',' expr]*] | [expr ';' expr] ;
|
||||
```
|
||||
|
||||
### Index expressions
|
||||
|
|
@ -549,66 +556,61 @@ range_expr : expr ".." expr |
|
|||
|
||||
### Unary operator expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
unop_expr : unop expr ;
|
||||
unop : '-' | '*' | '!' ;
|
||||
```
|
||||
|
||||
### Binary operator expressions
|
||||
|
||||
```antlr
|
||||
binop_expr : expr binop expr ;
|
||||
binop_expr : expr binop expr | type_cast_expr
|
||||
| assignment_expr | compound_assignment_expr ;
|
||||
binop : arith_op | bitwise_op | lazy_bool_op | comp_op
|
||||
```
|
||||
|
||||
#### Arithmetic operators
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
arith_op : '+' | '-' | '*' | '/' | '%' ;
|
||||
```
|
||||
|
||||
#### Bitwise operators
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
bitwise_op : '&' | '|' | '^' | "<<" | ">>" ;
|
||||
```
|
||||
|
||||
#### Lazy boolean operators
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
lazy_bool_op : "&&" | "||" ;
|
||||
```
|
||||
|
||||
#### Comparison operators
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
comp_op : "==" | "!=" | '<' | '>' | "<=" | ">=" ;
|
||||
```
|
||||
|
||||
#### Type cast expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
type_cast_expr : value "as" type ;
|
||||
```
|
||||
|
||||
#### Assignment expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
```antlr
|
||||
assignment_expr : expr '=' expr ;
|
||||
```
|
||||
|
||||
#### Compound assignment expressions
|
||||
|
||||
**FIXME:** grammar?
|
||||
|
||||
#### Operator precedence
|
||||
|
||||
The precedence of Rust binary operators is ordered as follows, going from
|
||||
strong to weak:
|
||||
|
||||
```text
|
||||
* / %
|
||||
as
|
||||
+ -
|
||||
<< >>
|
||||
&
|
||||
^
|
||||
|
|
||||
< > <= >=
|
||||
== !=
|
||||
&&
|
||||
||
|
||||
=
|
||||
```antlr
|
||||
compound_assignment_expr : expr [ arith_op | bitwise_op ] '=' expr ;
|
||||
```
|
||||
|
||||
Operators at the same precedence level are evaluated left-to-right. [Unary
|
||||
operators](#unary-operator-expressions) have the same precedence level and it
|
||||
is stronger than any of the binary operators'.
|
||||
|
||||
### Grouped expressions
|
||||
|
||||
```antlr
|
||||
|
|
|
|||
|
|
@ -5,15 +5,14 @@ to jump to any particular section.
|
|||
|
||||
# Getting Started
|
||||
|
||||
If you haven't seen Rust at all yet, the first thing you should read is the [30
|
||||
minute intro](intro.html). It will give you an overview of the basic ideas of Rust
|
||||
at a high level.
|
||||
If you haven't seen Rust at all yet, the first thing you should read is the
|
||||
introduction to [The Rust Programming Language](book/index.html). It'll give
|
||||
you a good idea of what Rust is like.
|
||||
|
||||
Once you know you really want to learn Rust, the next step is reading [The
|
||||
Rust Programming Language](book/index.html). It is a lengthy explanation of
|
||||
Rust, its syntax, and its concepts. Upon completing the book, you'll be an
|
||||
intermediate Rust developer, and will have a good grasp of the fundamental
|
||||
ideas behind Rust.
|
||||
The book provides a lengthy explanation of Rust, its syntax, and its
|
||||
concepts. Upon completing the book, you'll be an intermediate Rust
|
||||
developer, and will have a good grasp of the fundamental ideas behind
|
||||
Rust.
|
||||
|
||||
[Rust By Example][rbe] was originally a community resource, but was then
|
||||
donated to the Rust project. As the name implies, it teaches you Rust through a
|
||||
|
|
@ -24,7 +23,7 @@ series of small examples.
|
|||
# Community & Getting Help
|
||||
|
||||
If you need help with something, or just want to talk about Rust with others,
|
||||
there's a few places you can do that:
|
||||
there are a few places you can do that:
|
||||
|
||||
The Rust IRC channels on [irc.mozilla.org](http://irc.mozilla.org/) are the
|
||||
fastest way to get help.
|
||||
|
|
@ -59,7 +58,7 @@ the language in as much detail as possible is in [the reference](reference.html)
|
|||
|
||||
# Tools
|
||||
|
||||
Rust's still a young language, so there isn't a ton of tooling yet, but the
|
||||
Rust is still a young language, so there isn't a ton of tooling yet, but the
|
||||
tools we have are really nice.
|
||||
|
||||
[Cargo](http://crates.io) is Rust's package manager, and its website contains
|
||||
|
|
@ -69,16 +68,21 @@ lots of good documentation.
|
|||
|
||||
# FAQs
|
||||
|
||||
There are questions that are asked quite often, and so we've made FAQs for them:
|
||||
There are questions that are asked quite often, so we've made FAQs for them:
|
||||
|
||||
* [Language Design FAQ](complement-design-faq.html)
|
||||
* [Language FAQ](complement-lang-faq.html)
|
||||
* [Project FAQ](complement-project-faq.html)
|
||||
* [How to submit a bug report](https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports)
|
||||
|
||||
# The standard library
|
||||
# The Standard Library
|
||||
|
||||
We have [API documentation for the entire standard
|
||||
library](std/index.html). There's a list of crates on the left with more
|
||||
specific sections, or you can use the search bar at the top to search for
|
||||
something if you know its name.
|
||||
|
||||
# The Error Index
|
||||
|
||||
If you encounter an error while compiling your code you may be able to look it
|
||||
up in the [Rust Compiler Error Index](error-index.html).
|
||||
|
|
|
|||
|
|
@ -31,23 +31,27 @@ You may also be interested in the [grammar].
|
|||
|
||||
## Unicode productions
|
||||
|
||||
A few productions in Rust's grammar permit Unicode code points outside the ASCII
|
||||
range. We define these productions in terms of character properties specified
|
||||
in the Unicode standard, rather than in terms of ASCII-range code points. The
|
||||
section [Special Unicode Productions](#special-unicode-productions) lists these
|
||||
productions.
|
||||
A few productions in Rust's grammar permit Unicode code points outside the
|
||||
ASCII range. We define these productions in terms of character properties
|
||||
specified in the Unicode standard, rather than in terms of ASCII-range code
|
||||
points. The grammar has a [Special Unicode Productions][unicodeproductions]
|
||||
section that lists these productions.
|
||||
|
||||
[unicodeproductions]: grammar.html#special-unicode-productions
|
||||
|
||||
## String table productions
|
||||
|
||||
Some rules in the grammar — notably [unary
|
||||
operators](#unary-operator-expressions), [binary
|
||||
operators](#binary-operator-expressions), and [keywords](#keywords) — are
|
||||
operators](#binary-operator-expressions), and [keywords][keywords] — are
|
||||
given in a simplified form: as a listing of a table of unquoted, printable
|
||||
whitespace-separated strings. These cases form a subset of the rules regarding
|
||||
the [token](#tokens) rule, and are assumed to be the result of a
|
||||
lexical-analysis phase feeding the parser, driven by a DFA, operating over the
|
||||
disjunction of all such string table entries.
|
||||
|
||||
[keywords]: grammar.html#keywords
|
||||
|
||||
When such a string enclosed in double-quotes (`"`) occurs inside the grammar,
|
||||
it is an implicit reference to a single member of such a string table
|
||||
production. See [tokens](#tokens) for more information.
|
||||
|
|
@ -75,7 +79,7 @@ An identifier is any nonempty Unicode[^non_ascii_idents] string of the following
|
|||
- The first character has property `XID_start`
|
||||
- The remaining characters have property `XID_continue`
|
||||
|
||||
that does _not_ occur in the set of [keywords](#keywords).
|
||||
that does _not_ occur in the set of [keywords][keywords].
|
||||
|
||||
> **Note**: `XID_start` and `XID_continue` as character properties cover the
|
||||
> character ranges used to form the more familiar C and Java language-family
|
||||
|
|
@ -401,7 +405,7 @@ Symbols are a general class of printable [token](#tokens) that play structural
|
|||
roles in a variety of grammar productions. They are catalogued here for
|
||||
completeness as the set of remaining miscellaneous printable tokens that do not
|
||||
otherwise appear as [unary operators](#unary-operator-expressions), [binary
|
||||
operators](#binary-operator-expressions), or [keywords](#keywords).
|
||||
operators](#binary-operator-expressions), or [keywords][keywords].
|
||||
|
||||
|
||||
## Paths
|
||||
|
|
@ -422,12 +426,12 @@ x;
|
|||
x::y::z;
|
||||
```
|
||||
|
||||
Path components are usually [identifiers](#identifiers), but the trailing
|
||||
component of a path may be an angle-bracket-enclosed list of type arguments. In
|
||||
[expression](#expressions) context, the type argument list is given after a
|
||||
final (`::`) namespace qualifier in order to disambiguate it from a relational
|
||||
expression involving the less-than symbol (`<`). In type expression context,
|
||||
the final namespace qualifier is omitted.
|
||||
Path components are usually [identifiers](#identifiers), but they may
|
||||
also include angle-bracket-enclosed lists of type arguments. In
|
||||
[expression](#expressions) context, the type argument list is given
|
||||
after a `::` namespace qualifier in order to disambiguate it from a
|
||||
relational expression involving the less-than symbol (`<`). In type
|
||||
expression context, the final namespace qualifier is omitted.
|
||||
|
||||
Two examples of paths with type arguments:
|
||||
|
||||
|
|
@ -493,8 +497,9 @@ names, and invoked through a consistent syntax: `some_extension!(...)`.
|
|||
|
||||
Users of `rustc` can define new syntax extensions in two ways:
|
||||
|
||||
* [Compiler plugins][plugin] can include arbitrary
|
||||
Rust code that manipulates syntax trees at compile time.
|
||||
* [Compiler plugins][plugin] can include arbitrary Rust code that
|
||||
manipulates syntax trees at compile time. Note that the interface
|
||||
for compiler plugins is considered highly unstable.
|
||||
|
||||
* [Macros](book/macros.html) define new syntax in a higher-level,
|
||||
declarative way.
|
||||
|
|
@ -547,7 +552,7 @@ _name_ s that occur in its body. At the "current layer", they all must repeat
|
|||
the same number of times, so ` ( $( $i:ident ),* ; $( $j:ident ),* ) => ( $(
|
||||
($i,$j) ),* )` is valid if given the argument `(a,b,c ; d,e,f)`, but not
|
||||
`(a,b,c ; d,e)`. The repetition walks through the choices at that layer in
|
||||
lockstep, so the former input transcribes to `( (a,d), (b,e), (c,f) )`.
|
||||
lockstep, so the former input transcribes to `(a,d), (b,e), (c,f)`.
|
||||
|
||||
Nested repetitions are allowed.
|
||||
|
||||
|
|
@ -556,14 +561,18 @@ Nested repetitions are allowed.
|
|||
The parser used by the macro system is reasonably powerful, but the parsing of
|
||||
Rust syntax is restricted in two ways:
|
||||
|
||||
1. The parser will always parse as much as possible. If it attempts to match
|
||||
`$i:expr [ , ]` against `8 [ , ]`, it will attempt to parse `i` as an array
|
||||
index operation and fail. Adding a separator can solve this problem.
|
||||
1. Macro definitions are required to include suitable separators after parsing
|
||||
expressions and other bits of the Rust grammar. This implies that
|
||||
a macro definition like `$i:expr [ , ]` is not legal, because `[` could be part
|
||||
of an expression. A macro definition like `$i:expr,` or `$i:expr;` would be legal,
|
||||
however, because `,` and `;` are legal separators. See [RFC 550] for more information.
|
||||
2. The parser must have eliminated all ambiguity by the time it reaches a `$`
|
||||
_name_ `:` _designator_. This requirement most often affects name-designator
|
||||
pairs when they occur at the beginning of, or immediately after, a `$(...)*`;
|
||||
requiring a distinctive token in front can solve the problem.
|
||||
|
||||
[RFC 550]: https://github.com/rust-lang/rfcs/blob/master/text/0550-macro-future-proofing.md
|
||||
|
||||
# Crates and source files
|
||||
|
||||
Although Rust, like any other language, can be implemented by an interpreter as
|
||||
|
|
@ -611,7 +620,7 @@ module needs its own source file: [module definitions](#modules) can be nested
|
|||
within one file.
|
||||
|
||||
Each source file contains a sequence of zero or more `item` definitions, and
|
||||
may optionally begin with any number of [attributes](#Items and attributes)
|
||||
may optionally begin with any number of [attributes](#items-and-attributes)
|
||||
that apply to the containing module, most of which influence the behavior of
|
||||
the compiler. The anonymous crate module can have additional attributes that
|
||||
apply to the crate as a whole.
|
||||
|
|
@ -653,9 +662,10 @@ There are several kinds of item:
|
|||
* [`use` declarations](#use-declarations)
|
||||
* [modules](#modules)
|
||||
* [functions](#functions)
|
||||
* [type definitions](#type-definitions)
|
||||
* [type definitions](grammar.html#type-definitions)
|
||||
* [structures](#structures)
|
||||
* [enumerations](#enumerations)
|
||||
* [constant items](#constant-items)
|
||||
* [static items](#static-items)
|
||||
* [traits](#traits)
|
||||
* [implementations](#implementations)
|
||||
|
|
@ -672,16 +682,17 @@ which sub-item declarations may appear.
|
|||
|
||||
### Type Parameters
|
||||
|
||||
All items except modules may be *parameterized* by type. Type parameters are
|
||||
given as a comma-separated list of identifiers enclosed in angle brackets
|
||||
(`<...>`), after the name of the item and before its definition. The type
|
||||
parameters of an item are considered "part of the name", not part of the type
|
||||
of the item. A referencing [path](#paths) must (in principle) provide type
|
||||
arguments as a list of comma-separated types enclosed within angle brackets, in
|
||||
order to refer to the type-parameterized item. In practice, the type-inference
|
||||
system can usually infer such argument types from context. There are no
|
||||
general type-parametric types, only type-parametric items. That is, Rust has
|
||||
no notion of type abstraction: there are no first-class "forall" types.
|
||||
All items except modules, constants and statics may be *parameterized* by type.
|
||||
Type parameters are given as a comma-separated list of identifiers enclosed in
|
||||
angle brackets (`<...>`), after the name of the item and before its definition.
|
||||
The type parameters of an item are considered "part of the name", not part of
|
||||
the type of the item. A referencing [path](#paths) must (in principle) provide
|
||||
type arguments as a list of comma-separated types enclosed within angle
|
||||
brackets, in order to refer to the type-parameterized item. In practice, the
|
||||
type-inference system can usually infer such argument types from context. There
|
||||
are no general type-parametric types, only type-parametric items. That is, Rust
|
||||
has no notion of type abstraction: there are no higher-ranked (or "forall") types
|
||||
abstracted over other types, though higher-ranked types do exist for lifetimes.
|
||||
|
||||
### Modules
|
||||
|
||||
|
|
@ -727,6 +738,7 @@ mod vec;
|
|||
|
||||
mod thread {
|
||||
// Load the `local_data` module from `thread/local_data.rs`
|
||||
// or `thread/local_data/mod.rs`.
|
||||
mod local_data;
|
||||
}
|
||||
```
|
||||
|
|
@ -743,7 +755,7 @@ mod thread {
|
|||
}
|
||||
```
|
||||
|
||||
##### Extern crate declarations
|
||||
#### Extern crate declarations
|
||||
|
||||
An _`extern crate` declaration_ specifies a dependency on an external crate.
|
||||
The external crate is then bound into the declaring scope as the `ident`
|
||||
|
|
@ -767,12 +779,12 @@ extern crate std; // equivalent to: extern crate std as std;
|
|||
extern crate std as ruststd; // linking to 'std' under another name
|
||||
```
|
||||
|
||||
##### Use declarations
|
||||
#### Use declarations
|
||||
|
||||
A _use declaration_ creates one or more local name bindings synonymous with
|
||||
some other [path](#paths). Usually a `use` declaration is used to shorten the
|
||||
path required to refer to a module item. These declarations may appear at the
|
||||
top of [modules](#modules) and [blocks](#blocks).
|
||||
top of [modules](#modules) and [blocks](grammar.html#block-expressions).
|
||||
|
||||
> **Note**: Unlike in many languages,
|
||||
> `use` declarations in Rust do *not* declare linkage dependency with external crates.
|
||||
|
|
@ -842,7 +854,7 @@ module declarations should be at the crate root if direct usage of the declared
|
|||
modules within `use` items is desired. It is also possible to use `self` and
|
||||
`super` at the beginning of a `use` item to refer to the current and direct
|
||||
parent modules respectively. All rules regarding accessing declared modules in
|
||||
`use` declarations applies to both module declarations and `extern crate`
|
||||
`use` declarations apply to both module declarations and `extern crate`
|
||||
declarations.
|
||||
|
||||
An example of what will and will not work for `use` items:
|
||||
|
|
@ -999,7 +1011,8 @@ the guarantee that these issues are never caused by safe code.
|
|||
* `&mut` and `&` follow LLVM’s scoped [noalias] model, except if the `&T`
|
||||
contains an `UnsafeCell<U>`. Unsafe code must not violate these aliasing
|
||||
guarantees.
|
||||
* Mutating an immutable value/reference without `UnsafeCell<U>`
|
||||
* Mutating non-mutable data (that is, data reached through a shared reference or
|
||||
data owned by a `let` binding), unless that data is contained within an `UnsafeCell<U>`.
|
||||
* Invoking undefined behavior via compiler intrinsics:
|
||||
* Indexing outside of the bounds of an object with `std::ptr::offset`
|
||||
(`offset` intrinsic), with
|
||||
|
|
@ -1029,9 +1042,13 @@ be undesired.
|
|||
* Exiting without calling destructors
|
||||
* Sending signals
|
||||
* Accessing/modifying the file system
|
||||
* Unsigned integer overflow (well-defined as wrapping)
|
||||
* Signed integer overflow (well-defined as two’s complement representation
|
||||
wrapping)
|
||||
* Integer overflow
|
||||
- Overflow is considered "unexpected" behavior and is always user-error,
|
||||
unless the `wrapping` primitives are used. In non-optimized builds, the compiler
|
||||
will insert debug checks that panic on overflow, but in optimized builds overflow
|
||||
instead results in wrapped values. See [RFC 560] for the rationale and more details.
|
||||
|
||||
[RFC 560]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md
|
||||
|
||||
#### Diverging functions
|
||||
|
||||
|
|
@ -1143,9 +1160,7 @@ let px: i32 = match p { Point(x, _) => x };
|
|||
```
|
||||
|
||||
A _unit-like struct_ is a structure without any fields, defined by leaving off
|
||||
the list of fields entirely. Such types will have a single value, just like
|
||||
the [unit value `()`](#unit-and-boolean-literals) of the unit type. For
|
||||
example:
|
||||
the list of fields entirely. Such types will have a single value. For example:
|
||||
|
||||
```
|
||||
struct Cookie;
|
||||
|
|
@ -1307,11 +1322,26 @@ type of the value is not required to ascribe to `Sync`.
|
|||
|
||||
### Traits
|
||||
|
||||
A _trait_ describes a set of method types.
|
||||
A _trait_ describes an abstract interface that types can
|
||||
implement. This interface consists of associated items, which come in
|
||||
three varieties:
|
||||
|
||||
Traits can include default implementations of methods, written in terms of some
|
||||
unknown [`self` type](#self-types); the `self` type may either be completely
|
||||
unspecified, or constrained by some other trait.
|
||||
- functions
|
||||
- constants
|
||||
- types
|
||||
|
||||
Associated functions whose first parameter is named `self` are called
|
||||
methods and may be invoked using `.` notation (e.g., `x.foo()`).
|
||||
|
||||
All traits define an implicit type parameter `Self` that refers to
|
||||
"the type that is implementing this interface". Traits may also
|
||||
contain additional type parameters. These type parameters (including
|
||||
`Self`) may be constrained by other traits and so forth as usual.
|
||||
|
||||
Trait bounds on `Self` are considered "supertraits". These are
|
||||
required to be acyclic. Supertraits are somewhat different from other
|
||||
constraints in that they affect what methods are available in the
|
||||
vtable when the trait is used as a [trait object](#trait-objects).
|
||||
|
||||
Traits are implemented for specific types through separate
|
||||
[implementations](#implementations).
|
||||
|
|
@ -1356,15 +1386,18 @@ fn draw_twice<T: Shape>(surface: Surface, sh: T) {
|
|||
}
|
||||
```
|
||||
|
||||
Traits also define an [trait object](#trait-objects) with the same name as the
|
||||
trait. Values of this type are created by [casting](#type-cast-expressions)
|
||||
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.
|
||||
Traits also define an [trait object](#trait-objects) with the same
|
||||
name as the trait. Values of this type are created by coercing from a
|
||||
pointer of some specific type to a pointer of trait type. For example,
|
||||
`&T` could be coerced to `&Shape` if `T: Shape` holds (and similarly
|
||||
for `Box<T>`). This coercion can either be implicit or
|
||||
[explicit](#type-cast-expressions). Here is an example of an explicit
|
||||
coercion:
|
||||
|
||||
```
|
||||
# trait Shape { fn dummy(&self) { } }
|
||||
# impl Shape for i32 { }
|
||||
# let mycircle = 0i32;
|
||||
trait Shape { }
|
||||
impl Shape for i32 { }
|
||||
let mycircle = 0i32;
|
||||
let myshape: Box<Shape> = Box::new(mycircle) as Box<Shape>;
|
||||
```
|
||||
|
||||
|
|
@ -2038,7 +2071,8 @@ The name `str_eq` has a special meaning to the Rust compiler, and the presence
|
|||
of this definition means that it will use this definition when generating calls
|
||||
to the string equality function.
|
||||
|
||||
A complete list of the built-in language items will be added in the future.
|
||||
The set of language items is currently considered unstable. A complete
|
||||
list of the built-in language items will be added in the future.
|
||||
|
||||
### Inline attributes
|
||||
|
||||
|
|
@ -2050,11 +2084,6 @@ The compiler automatically inlines functions based on internal heuristics.
|
|||
Incorrectly inlining functions can actually make the program slower, so it
|
||||
should be used with care.
|
||||
|
||||
Immutable statics are always considered inlineable unless marked with
|
||||
`#[inline(never)]`. It is undefined whether two different inlineable statics
|
||||
have the same memory address. In other words, the compiler is free to collapse
|
||||
duplicate inlineable statics together.
|
||||
|
||||
`#[inline]` and `#[inline(always)]` always cause the function to be serialized
|
||||
into the crate metadata to allow cross-crate inlining.
|
||||
|
||||
|
|
@ -2256,10 +2285,6 @@ The currently implemented features of the reference compiler are:
|
|||
* `unboxed_closures` - Rust's new closure design, which is currently a work in
|
||||
progress feature with many known bugs.
|
||||
|
||||
* `unsafe_destructor` - Allows use of the `#[unsafe_destructor]` attribute,
|
||||
which is considered wildly unsafe and will be
|
||||
obsoleted by language improvements.
|
||||
|
||||
* `unsafe_no_drop_flag` - Allows use of the `#[unsafe_no_drop_flag]` attribute,
|
||||
which removes hidden flag added to a type that
|
||||
implements the `Drop` trait. The design for the
|
||||
|
|
@ -2379,18 +2404,54 @@ expressions](#index-expressions) (`expr[expr]`), and [field
|
|||
references](#field-expressions) (`expr.f`). All other expressions are rvalues.
|
||||
|
||||
The left operand of an [assignment](#assignment-expressions) or
|
||||
[compound-assignment](#compound-assignment-expressions) expression is an lvalue
|
||||
context, as is the single operand of a unary
|
||||
[borrow](#unary-operator-expressions). All other expression contexts are
|
||||
rvalue contexts.
|
||||
[compound-assignment](#compound-assignment-expressions) expression is
|
||||
an lvalue context, as is the single operand of a unary
|
||||
[borrow](#unary-operator-expressions). The discriminant or subject of
|
||||
a [match expression](#match-expressions) may be an lvalue context, if
|
||||
ref bindings are made, but is otherwise an rvalue context. All other
|
||||
expression contexts are rvalue contexts.
|
||||
|
||||
When an lvalue is evaluated in an _lvalue context_, it denotes a memory
|
||||
location; when evaluated in an _rvalue context_, it denotes the value held _in_
|
||||
that memory location.
|
||||
|
||||
When an rvalue is used in an lvalue context, a temporary un-named lvalue is
|
||||
created and used instead. A temporary's lifetime equals the largest lifetime
|
||||
of any reference that points to it.
|
||||
##### Temporary lifetimes
|
||||
|
||||
When an rvalue is used in an lvalue context, a temporary un-named
|
||||
lvalue is created and used instead. The lifetime of temporary values
|
||||
is typically the innermost enclosing statement; the tail expression of
|
||||
a block is considered part of the statement that encloses the block.
|
||||
|
||||
When a temporary rvalue is being created that is assigned into a `let`
|
||||
declaration, however, the temporary is created with the lifetime of
|
||||
the enclosing block instead, as using the enclosing statement (the
|
||||
`let` declaration) would be a guaranteed error (since a pointer to the
|
||||
temporary would be stored into a variable, but the temporary would be
|
||||
freed before the variable could be used). The compiler uses simple
|
||||
syntactic rules to decide which values are being assigned into a `let`
|
||||
binding, and therefore deserve a longer temporary lifetime.
|
||||
|
||||
Here are some examples:
|
||||
|
||||
- `let x = foo(&temp())`. The expression `temp()` is an rvalue. As it
|
||||
is being borrowed, a temporary is created which will be freed after
|
||||
the innermost enclosing statement (the `let` declaration, in this case).
|
||||
- `let x = temp().foo()`. This is the same as the previous example,
|
||||
except that the value of `temp()` is being borrowed via autoref on a
|
||||
method-call. Here we are assuming that `foo()` is an `&self` method
|
||||
defined in some trait, say `Foo`. In other words, the expression
|
||||
`temp().foo()` is equivalent to `Foo::foo(&temp())`.
|
||||
- `let x = &temp()`. Here, the same temporary is being assigned into
|
||||
`x`, rather than being passed as a parameter, and hence the
|
||||
temporary's lifetime is considered to be the enclosing block.
|
||||
- `let x = SomeStruct { foo: &temp() }`. As in the previous case, the
|
||||
temporary is assigned into a struct which is then assigned into a
|
||||
binding, and hence it is given the lifetime of the enclosing block.
|
||||
- `let x = [ &temp() ]`. As in the previous case, the
|
||||
temporary is assigned into an array which is then assigned into a
|
||||
binding, and hence it is given the lifetime of the enclosing block.
|
||||
- `let ref x = temp()`. In this case, the temporary is created using a ref binding,
|
||||
but the result is the same: the lifetime is extended to the enclosing block.
|
||||
|
||||
#### Moved and copied types
|
||||
|
||||
|
|
@ -2435,11 +2496,6 @@ comma:
|
|||
(0); // zero in parentheses
|
||||
```
|
||||
|
||||
### Unit expressions
|
||||
|
||||
The expression `()` denotes the _unit value_, the only value of the type with
|
||||
the same name.
|
||||
|
||||
### Structure expressions
|
||||
|
||||
There are several forms of structure expressions. A _structure expression_
|
||||
|
|
@ -2537,8 +2593,10 @@ A field access is an [lvalue](#lvalues,-rvalues-and-temporaries) referring to
|
|||
the value of that field. When the type providing the field inherits mutability,
|
||||
it can be [assigned](#assignment-expressions) to.
|
||||
|
||||
Also, if the type of the expression to the left of the dot is a pointer, it is
|
||||
automatically dereferenced to make the field access possible.
|
||||
Also, if the type of the expression to the left of the dot is a
|
||||
pointer, it is automatically dereferenced as many times as necessary
|
||||
to make the field access possible. In cases of ambiguity, we prefer
|
||||
fewer autoderefs to more.
|
||||
|
||||
### Array expressions
|
||||
|
||||
|
|
@ -2564,14 +2622,26 @@ array is mutable, the resulting [lvalue](#lvalues,-rvalues-and-temporaries) can
|
|||
be assigned to.
|
||||
|
||||
Indices are zero-based, and may be of any integral type. Vector access is
|
||||
bounds-checked at run-time. When the check fails, it will put the thread in a
|
||||
_panicked state_.
|
||||
bounds-checked at compile-time for constant arrays being accessed with a constant index value.
|
||||
Otherwise a check will be performed at run-time that will put the thread in a _panicked state_ if it fails.
|
||||
|
||||
```{should-fail}
|
||||
([1, 2, 3, 4])[0];
|
||||
(["a", "b"])[10]; // panics
|
||||
|
||||
let x = (["a", "b"])[10]; // compiler error: const index-expr is out of bounds
|
||||
|
||||
let n = 10;
|
||||
let y = (["a", "b"])[n]; // panics
|
||||
|
||||
let arr = ["a", "b"];
|
||||
arr[10]; // panics
|
||||
```
|
||||
|
||||
Also, if the type of the expression to the left of the brackets is a
|
||||
pointer, it is automatically dereferenced as many times as necessary
|
||||
to make the indexing possible. In cases of ambiguity, we prefer fewer
|
||||
autoderefs to more.
|
||||
|
||||
### Range expressions
|
||||
|
||||
The `..` operator will construct an object of one of the `std::ops::Range` variants.
|
||||
|
|
@ -2594,7 +2664,7 @@ assert_eq!(x,y);
|
|||
|
||||
### Unary operator expressions
|
||||
|
||||
Rust defines three unary operators. They are all written as prefix operators,
|
||||
Rust defines the following unary operators. They are all written as prefix operators,
|
||||
before the expression they apply to.
|
||||
|
||||
* `-`
|
||||
|
|
@ -2608,11 +2678,20 @@ before the expression they apply to.
|
|||
implemented by the type and required for an outer expression that will or
|
||||
could mutate the dereference), and produces the result of dereferencing the
|
||||
`&` or `&mut` borrowed pointer returned from the overload method.
|
||||
|
||||
* `!`
|
||||
: 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.
|
||||
* `&` and `&mut`
|
||||
: Borrowing. When applied to an lvalue, these operators produce a
|
||||
reference (pointer) to the lvalue. The lvalue is also placed into
|
||||
a borrowed state for the duration of the reference. For a shared
|
||||
borrow (`&`), this implies that the lvalue may not be mutated, but
|
||||
it may be read or shared again. For a mutable borrow (`&mut`), the
|
||||
lvalue may not be accessed in any way until the borrow expires.
|
||||
If the `&` or `&mut` operators are applied to an rvalue, a
|
||||
temporary value is created; the lifetime of this temporary value
|
||||
is defined by [syntactic rules](#temporary-lifetimes).
|
||||
|
||||
### Binary operator expressions
|
||||
|
||||
|
|
@ -2722,6 +2801,13 @@ fn avg(v: &[f64]) -> f64 {
|
|||
}
|
||||
```
|
||||
|
||||
Some of the conversions which can be done through the `as` operator
|
||||
can also be done implicitly at various points in the program, such as
|
||||
argument passing and assignment to a `let` binding with an explicit
|
||||
type. Implicit conversions are limited to "harmless" conversions that
|
||||
do not lose information and which have minimal or no risk of
|
||||
surprising side-effects on the dynamic execution semantics.
|
||||
|
||||
#### Assignment expressions
|
||||
|
||||
An _assignment expression_ consists of an
|
||||
|
|
@ -3064,6 +3150,20 @@ of a condition expression it expects a refutable let statement. If the value of
|
|||
expression on the right hand side of the let statement matches the pattern, the corresponding
|
||||
block will execute, otherwise flow proceeds to the first `else` block that follows.
|
||||
|
||||
```
|
||||
let dish = ("Ham", "Eggs");
|
||||
|
||||
// this body will be skipped because the pattern is refuted
|
||||
if let ("Bacon", b) = dish {
|
||||
println!("Bacon is served with {}", b);
|
||||
}
|
||||
|
||||
// this body will execute
|
||||
if let ("Ham", b) = dish {
|
||||
println!("Ham is served with {}", b);
|
||||
}
|
||||
```
|
||||
|
||||
### While let loops
|
||||
|
||||
A `while let` loop is semantically identical to a `while` loop but in place of a
|
||||
|
|
@ -3259,7 +3359,7 @@ constructor or `struct` field may refer, directly or indirectly, to the
|
|||
enclosing `enum` or `struct` type itself. Such recursion has restrictions:
|
||||
|
||||
* Recursive types must include a nominal type in the recursion
|
||||
(not mere [type definitions](#type-definitions),
|
||||
(not mere [type definitions](grammar.html#type-definitions),
|
||||
or other structural types such as [arrays](#array,-and-slice-types) or [tuples](#tuple-types)).
|
||||
* A recursive `enum` item must have at least one non-recursive constructor
|
||||
(in order to give the recursion a basis case).
|
||||
|
|
@ -3329,6 +3429,22 @@ let bo: Binop = add;
|
|||
x = bo(5,7);
|
||||
```
|
||||
|
||||
#### Function types for specific items
|
||||
|
||||
Internally to the compiler, there are also function types that are specific to a particular
|
||||
function item. In the following snippet, for example, the internal types of the functions
|
||||
`foo` and `bar` are different, despite the fact that they have the same signature:
|
||||
|
||||
```
|
||||
fn foo() { }
|
||||
fn bar() { }
|
||||
```
|
||||
|
||||
The types of `foo` and `bar` can both be implicitly coerced to the fn
|
||||
pointer type `fn()`. There is currently no syntax for unique fn types,
|
||||
though the compiler will emit a type like `fn() {foo}` in error
|
||||
messages to indicate "the unique fn type for the function `foo`".
|
||||
|
||||
### Closure types
|
||||
|
||||
A [lambda expression](#lambda-expressions) produces a closure value with
|
||||
|
|
@ -3413,8 +3529,9 @@ has type `Vec<A>`, a vector with element type `A`.
|
|||
|
||||
### Self types
|
||||
|
||||
The special type `self` has a meaning within methods inside an impl item. It
|
||||
refers to the type of the implicit `self` argument. For example, in:
|
||||
The special type `Self` has a meaning within traits and impls. In a trait definition, it refers
|
||||
to an implicit type parameter representing the "implementing" type. In an impl,
|
||||
it is an alias for the implementing type. For example, in:
|
||||
|
||||
```
|
||||
trait Printable {
|
||||
|
|
@ -3428,8 +3545,9 @@ impl Printable for String {
|
|||
}
|
||||
```
|
||||
|
||||
`self` refers to the value of type `String` that is the receiver for a call to
|
||||
the method `make_string`.
|
||||
The notation `&self` is a shorthand for `self: &Self`. In this case,
|
||||
in the impl, `Self` refers to the value of type `String` that is the
|
||||
receiver for a call to the method `make_string`.
|
||||
|
||||
# Special traits
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
* [Concurrency](concurrency.md)
|
||||
* [Error Handling](error-handling.md)
|
||||
* [FFI](ffi.md)
|
||||
* [Borrow and AsRef](borrow-and-asref.md)
|
||||
* [Syntax and Semantics](syntax-and-semantics.md)
|
||||
* [Variable Bindings](variable-bindings.md)
|
||||
* [Functions](functions.md)
|
||||
|
|
|
|||
93
src/doc/trpl/borrow-and-asref.md
Normal file
93
src/doc/trpl/borrow-and-asref.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
% Borrow and AsRef
|
||||
|
||||
The [`Borrow`][borrow] and [`AsRef`][asref] traits are very similar, but
|
||||
different. Here’s a quick refresher on what these two traits mean.
|
||||
|
||||
[borrow]: ../std/borrow/trait.Borrow.html
|
||||
[asref]: ../std/convert/trait.AsRef.html
|
||||
|
||||
# Borrow
|
||||
|
||||
The `Borrow` trait is used when you’re writing a datastructure, and you want to
|
||||
use either an owned or borrowed type as synonymous for some purpose.
|
||||
|
||||
For example, [`HashMap`][hashmap] has a [`get` method][get] which uses `Borrow`:
|
||||
|
||||
```rust,ignore
|
||||
fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
|
||||
where K: Borrow<Q>,
|
||||
Q: Hash + Eq
|
||||
```
|
||||
|
||||
[hashmap]: ../std/collections/struct.HashMap.html
|
||||
[get]: ../std/collections/struct.HashMap.html#method.get
|
||||
|
||||
This signature is pretty complicated. The `K` parameter is what we’re interested
|
||||
in here. It refers to a parameter of the `HashMap` itself:
|
||||
|
||||
```rust,ignore
|
||||
struct HashMap<K, V, S = RandomState> {
|
||||
```
|
||||
|
||||
The `K` parameter is the type of _key_ the `HashMap` uses. So, looking at
|
||||
the signature of `get()` again, we can use `get()` when the key implements
|
||||
`Borrow<Q>`. That way, we can make a `HashMap` which uses `String` keys,
|
||||
but use `&str`s when we’re searching:
|
||||
|
||||
```rust
|
||||
use std::collections::HashMap;
|
||||
|
||||
let mut map = HashMap::new();
|
||||
map.insert("Foo".to_string(), 42);
|
||||
|
||||
assert_eq!(map.get("Foo"), Some(&42));
|
||||
```
|
||||
|
||||
This is because the standard library has `impl Borrow<str> for String`.
|
||||
|
||||
For most types, when you want to take an owned or borrowed type, a `&T` is
|
||||
enough. But one area where `Borrow` is effective is when there’s more than one
|
||||
kind of borrowed value. Slices are an area where this is especially true: you
|
||||
can have both an `&[T]` or a `&mut [T]`. If we wanted to accept both of these
|
||||
types, `Borrow` is up for it:
|
||||
|
||||
```
|
||||
use std::borrow::Borrow;
|
||||
use std::fmt::Display;
|
||||
|
||||
fn foo<T: Borrow<i32> + Display>(a: T) {
|
||||
println!("a is borrowed: {}", a);
|
||||
}
|
||||
|
||||
let mut i = 5;
|
||||
|
||||
foo(&i);
|
||||
foo(&mut i);
|
||||
```
|
||||
|
||||
This will print out `a is borrowed: 5` twice.
|
||||
|
||||
# AsRef
|
||||
|
||||
The `AsRef` trait is a conversion trait. It’s used for converting some value to
|
||||
a reference in generic code. Like this:
|
||||
|
||||
```rust
|
||||
let s = "Hello".to_string();
|
||||
|
||||
fn foo<T: AsRef<str>>(s: T) {
|
||||
let slice = s.as_ref();
|
||||
}
|
||||
```
|
||||
|
||||
# Which should I use?
|
||||
|
||||
We can see how they’re kind of the same: they both deal with owned and borrowed
|
||||
versions of some type. However, they’re a bit different.
|
||||
|
||||
Choose `Borrow` when you want to abstract over different kinds of borrowing, or
|
||||
when you’re building a datastructure that treats owned and borrowed values in
|
||||
equivalent ways, such as hashing and comparison.
|
||||
|
||||
Choose `AsRef` when you want to convert something to a reference directly, and
|
||||
you’re writing generic code.
|
||||
|
|
@ -176,7 +176,7 @@ for a full example, the core of which is reproduced here:
|
|||
|
||||
```ignore
|
||||
declare_lint!(TEST_LINT, Warn,
|
||||
"Warn about items named 'lintme'")
|
||||
"Warn about items named 'lintme'");
|
||||
|
||||
struct Pass;
|
||||
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ information’. Why throw it away? Well, for a basic program, we just want to
|
|||
print a generic error, as basically any issue means we can’t continue. The
|
||||
[`ok()` method][ok] returns a value which has another method defined on it:
|
||||
`expect()`. The [`expect()` method][expect] takes a value it’s called on, and
|
||||
if it isn’t a successful one, [`panic!`][panic]s with a message you passed you
|
||||
if it isn’t a successful one, [`panic!`][panic]s with a message you
|
||||
passed it. A `panic!` like this will cause our program to crash, displaying
|
||||
the message.
|
||||
|
||||
|
|
@ -713,7 +713,7 @@ variety of numbers, we need to give Rust a hint as to the exact type of number
|
|||
we want. Hence, `let guess: u32`. The colon (`:`) after `guess` tells Rust
|
||||
we’re going to annotate its type. `u32` is an unsigned, thirty-two bit
|
||||
integer. Rust has [a number of built-in number types][number], but we’ve
|
||||
chosen `u32`. It’s a good default choice for a small positive numer.
|
||||
chosen `u32`. It’s a good default choice for a small positive number.
|
||||
|
||||
[parse]: ../std/primitive.str.html#method.parse
|
||||
[number]: primitive-types.html#numeric-types
|
||||
|
|
@ -922,7 +922,7 @@ failure. Each contains more information: the successful parsed integer, or an
|
|||
error type. In this case, we `match` on `Ok(num)`, which sets the inner value
|
||||
of the `Ok` to the name `num`, and then we just return it on the right-hand
|
||||
side. In the `Err` case, we don’t care what kind of error it is, so we just
|
||||
use `_` intead of a name. This ignores the error, and `continue` causes us
|
||||
use `_` instead of a name. This ignores the error, and `continue` causes us
|
||||
to go to the next iteration of the `loop`.
|
||||
|
||||
Now we should be good! Let’s try:
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ Rust’s most unique and compelling features, with which Rust developers should
|
|||
become quite acquainted. Ownership is how Rust achieves its largest goal,
|
||||
memory safety. There are a few distinct concepts, each with its own chapter:
|
||||
|
||||
* [ownership][ownership], ownership, the key concept
|
||||
* [ownership][ownership], the key concept
|
||||
* [borrowing][borrowing], and their associated feature ‘references’
|
||||
* lifetimes, which you’re reading now
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ side of a `let` binding or directly where an expression is used:
|
|||
```rust
|
||||
let x = 5;
|
||||
|
||||
let numer = match x {
|
||||
let number = match x {
|
||||
1 => "one",
|
||||
2 => "two",
|
||||
3 => "three",
|
||||
|
|
|
|||
|
|
@ -127,12 +127,12 @@ fn grow(&self) -> Circle {
|
|||
We just say we’re returning a `Circle`. With this method, we can grow a new
|
||||
circle to any arbitrary size.
|
||||
|
||||
# Static methods
|
||||
# Associated functions
|
||||
|
||||
You can also define static methods that do not take a `self` parameter. Here’s a
|
||||
pattern that’s very common in Rust code:
|
||||
You can also define associated functions that do not take a `self` parameter.
|
||||
Here’s a pattern that’s very common in Rust code:
|
||||
|
||||
```
|
||||
```rust
|
||||
struct Circle {
|
||||
x: f64,
|
||||
y: f64,
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ When we call `clone()`, the `Arc<T>` needs to update the reference count. Yet
|
|||
we’ve not used any `mut`s here, `x` is an immutable binding, and we didn’t take
|
||||
`&mut 5` or anything. So what gives?
|
||||
|
||||
To this, we have to go back to the core of Rust’s guiding philosophy, memory
|
||||
safety, and the mechanism by which Rust guarantees it, the
|
||||
To understand this, we have to go back to the core of Rust’s guiding
|
||||
philosophy, memory safety, and the mechanism by which Rust guarantees it, the
|
||||
[ownership][ownership] system, and more specifically, [borrowing][borrowing]:
|
||||
|
||||
> You may have one or the other of these two kinds of borrows, but not both at
|
||||
|
|
@ -169,7 +169,7 @@ struct Point {
|
|||
y: Cell<i32>,
|
||||
}
|
||||
|
||||
let mut point = Point { x: 5, y: Cell::new(6) };
|
||||
let point = Point { x: 5, y: Cell::new(6) };
|
||||
|
||||
point.y.set(7);
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ become quite acquainted. Ownership is how Rust achieves its largest goal,
|
|||
memory safety. There are a few distinct concepts, each with its own
|
||||
chapter:
|
||||
|
||||
* ownership, which you’re reading now.
|
||||
* ownership, which you’re reading now
|
||||
* [borrowing][borrowing], and their associated feature ‘references’
|
||||
* [lifetimes][lifetimes], an advanced concept of borrowing
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ Before we get to the details, two important notes about the ownership system.
|
|||
Rust has a focus on safety and speed. It accomplishes these goals through many
|
||||
‘zero-cost abstractions’, which means that in Rust, abstractions cost as little
|
||||
as possible in order to make them work. The ownership system is a prime example
|
||||
of a zero cost abstraction. All of the analysis we’ll talk about in this guide
|
||||
of a zero-cost abstraction. All of the analysis we’ll talk about in this guide
|
||||
is _done at compile time_. You do not pay any run-time cost for any of these
|
||||
features.
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ With that in mind, let’s learn about ownership.
|
|||
|
||||
# Ownership
|
||||
|
||||
[`Variable bindings`][bindings] have a property in Rust: they ‘have ownership’
|
||||
[Variable bindings][bindings] have a property in Rust: they ‘have ownership’
|
||||
of what they’re bound to. This means that when a binding goes out of scope, the
|
||||
resource that they’re bound to are freed. For example:
|
||||
|
||||
|
|
@ -106,8 +106,8 @@ take(v);
|
|||
println!("v[0] is: {}", v[0]);
|
||||
```
|
||||
|
||||
Same error: “use of moved value.” When we transfer ownership to something else,
|
||||
we say that we’ve ‘moved’ the thing we refer to. You don’t need some sort of
|
||||
Same error: ‘use of moved value’. When we transfer ownership to something else,
|
||||
we say that we’ve ‘moved’ the thing we refer to. You don’t need any sort of
|
||||
special annotation here, it’s the default thing that Rust does.
|
||||
|
||||
## The details
|
||||
|
|
@ -121,19 +121,19 @@ let v = vec![1, 2, 3];
|
|||
let v2 = v;
|
||||
```
|
||||
|
||||
The first line creates some data for the vector on the [stack][sh], `v`. The
|
||||
vector’s data, however, is stored on the [heap][sh], and so it contains a
|
||||
pointer to that data. When we move `v` to `v2`, it creates a copy of that pointer,
|
||||
for `v2`. Which would mean two pointers to the contents of the vector on the
|
||||
heap. That would be a problem: it would violate Rust’s safety guarantees by
|
||||
introducing a data race. Therefore, Rust forbids using `v` after we’ve done the
|
||||
move.
|
||||
The first line allocates memory for the vector object, `v`, and for the data it
|
||||
contains. The vector object is stored on the [stack][sh] and contains a pointer
|
||||
to the content (`[1, 2, 3]`) stored on the [heap][sh]. When we move `v` to `v2`,
|
||||
it creates a copy of that pointer, for `v2`. Which means that there would be two
|
||||
pointers to the content of the vector on the heap. It would violate Rust’s
|
||||
safety guarantees by introducing a data race. Therefore, Rust forbids using `v`
|
||||
after we’ve done the move.
|
||||
|
||||
[sh]: the-stack-and-the-heap.html
|
||||
|
||||
It’s also important to note that optimizations may remove the actual copy of
|
||||
the bytes, depending on circumstances. So it may not be as inefficient as it
|
||||
initially seems.
|
||||
the bytes on the stack, depending on circumstances. So it may not be as
|
||||
inefficient as it initially seems.
|
||||
|
||||
## `Copy` types
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ fn foo(v: Vec<i32>) -> Vec<i32> {
|
|||
}
|
||||
```
|
||||
|
||||
This would get very tedius. It gets worse the more things we want to take ownership of:
|
||||
This would get very tedious. It gets worse the more things we want to take ownership of:
|
||||
|
||||
```rust
|
||||
fn foo(v1: Vec<i32>, v2: Vec<i32>) -> (Vec<i32>, Vec<i32>, i32) {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ let x = true;
|
|||
let y: bool = false;
|
||||
```
|
||||
|
||||
A common use of booleans is in [`if` statements][if].
|
||||
A common use of booleans is in [`if` conditionals][if].
|
||||
|
||||
[if]: if.html
|
||||
|
||||
|
|
@ -176,7 +176,7 @@ Slices have type `&[T]`. We’ll talk about that `T` when we cover
|
|||
|
||||
[generics]: generics.html
|
||||
|
||||
You can find more documentation for `slices`s [in the standard library
|
||||
You can find more documentation for slices [in the standard library
|
||||
documentation][slice].
|
||||
|
||||
[slice]: ../std/primitive.slice.html
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ become quite acquainted. Ownership is how Rust achieves its largest goal,
|
|||
memory safety. There are a few distinct concepts, each with its own
|
||||
chapter:
|
||||
|
||||
* [ownership][ownership], ownership, the key concept
|
||||
* [ownership][ownership], the key concept
|
||||
* borrowing, which you’re reading now
|
||||
* [lifetimes][lifetimes], an advanced concept of borrowing
|
||||
|
||||
|
|
@ -312,6 +312,7 @@ println!("{}", y);
|
|||
|
||||
We get this error:
|
||||
|
||||
```text
|
||||
error: `x` does not live long enough
|
||||
y = &x;
|
||||
^
|
||||
|
|
@ -334,3 +335,37 @@ In other words, `y` is only valid for the scope where `x` exists. As soon as
|
|||
`x` goes away, it becomes invalid to refer to it. As such, the error says that
|
||||
the borrow ‘doesn’t live long enough’ because it’s not valid for the right
|
||||
amount of time.
|
||||
|
||||
The same problem occurs when the reference is declared _before_ the variable it refers to:
|
||||
|
||||
```rust,ignore
|
||||
let y: &i32;
|
||||
let x = 5;
|
||||
y = &x;
|
||||
|
||||
println!("{}", y);
|
||||
```
|
||||
|
||||
We get this error:
|
||||
|
||||
```text
|
||||
error: `x` does not live long enough
|
||||
y = &x;
|
||||
^
|
||||
note: reference must be valid for the block suffix following statement 0 at
|
||||
2:16...
|
||||
let y: &i32;
|
||||
let x = 5;
|
||||
y = &x;
|
||||
|
||||
println!("{}", y);
|
||||
}
|
||||
|
||||
note: ...but borrowed value is only valid for the block suffix following
|
||||
statement 1 at 3:14
|
||||
let x = 5;
|
||||
y = &x;
|
||||
|
||||
println!("{}", y);
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -1,3 +1,570 @@
|
|||
% The Stack and the Heap
|
||||
|
||||
Coming Soon
|
||||
As a systems language, Rust operates at a low level. If you’re coming from a
|
||||
high-level language, there are some aspects of systems programming that you may
|
||||
not be familiar with. The most important one is how memory works, with a stack
|
||||
and a heap. If you’re familiar with how C-like languages use stack allocation,
|
||||
this chapter will be a refresher. If you’re not, you’ll learn about this more
|
||||
general concept, but with a Rust-y focus.
|
||||
|
||||
# Memory management
|
||||
|
||||
These two terms are about memory management. The stack and the heap are
|
||||
abstractions that help you determine when to allocate and deallocate memory.
|
||||
|
||||
Here’s a high-level comparison:
|
||||
|
||||
The stack is very fast, and is where memory is allocated in Rust by default.
|
||||
But the allocation is local to a function call, and is limited in size. The
|
||||
heap, on the other hand, is slower, and is explicitly allocated by your
|
||||
program. But it’s effectively unlimited in size, and is globally accessible.
|
||||
|
||||
# The Stack
|
||||
|
||||
Let’s talk about this Rust program:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = 42;
|
||||
}
|
||||
```
|
||||
|
||||
This program has one variable binding, `x`. This memory needs to be allocated
|
||||
from somewhere. Rust ‘stack allocates’ by default, which means that basic
|
||||
values ‘go on the stack’. What does that mean?
|
||||
|
||||
Well, when a function gets called, some memory gets allocated for all of its
|
||||
local variables and some other information. This is called a ‘stack frame’, and
|
||||
for the purpose of this tutorial, we’re going to ignore the extra information
|
||||
and just consider the local variables we’re allocating. So in this case, when
|
||||
`main()` is run, we’ll allocate a single 32-bit integer for our stack frame.
|
||||
This is automatically handled for you, as you can see, we didn’t have to write
|
||||
any special Rust code or anything.
|
||||
|
||||
When the function is over, its stack frame gets deallocated. This happens
|
||||
automatically, we didn’t have to do anything special here.
|
||||
|
||||
That’s all there is for this simple program. The key thing to understand here
|
||||
is that stack allocation is very, very fast. Since we know all the local
|
||||
variables we have ahead of time, we can grab the memory all at once. And since
|
||||
we’ll throw them all away at the same time as well, we can get rid of it very
|
||||
fast too.
|
||||
|
||||
The downside is that we can’t keep values around if we need them for longer
|
||||
than a single function. We also haven’t talked about what that name, ‘stack’
|
||||
means. To do that, we need a slightly more complicated example:
|
||||
|
||||
```rust
|
||||
fn foo() {
|
||||
let y = 5;
|
||||
let z = 100;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 42;
|
||||
|
||||
foo();
|
||||
}
|
||||
```
|
||||
|
||||
This program has three variables total: two in `foo()`, one in `main()`. Just
|
||||
as before, when `main()` is called, a single integer is allocated for its stack
|
||||
frame. But before we can show what happens when `foo()` is called, we need to
|
||||
visualize what’s going on with memory. Your operating system presents a view of
|
||||
memory to your program that’s pretty simple: a huge list of addresses, from 0
|
||||
to a large number, representing how much RAM your computer has. For example, if
|
||||
you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,824`. That
|
||||
number comes from 2<sup>30</sup>, the number of bytes in a gigabyte.
|
||||
|
||||
This memory is kind of like a giant array: addresses start at zero and go
|
||||
up to the final number. So here’s a diagram of our first stack frame:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 0 | x | 42 |
|
||||
|
||||
We’ve got `x` located at address `0`, with the value `42`.
|
||||
|
||||
When `foo()` is called, a new stack frame is allocated:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 2 | z | 100 |
|
||||
| 1 | y | 5 |
|
||||
| 0 | x | 42 |
|
||||
|
||||
Because `0` was taken by the first frame, `1` and `2` are used for `foo()`’s
|
||||
stack frame. It grows upward, the more functions we call.
|
||||
|
||||
|
||||
There’s some important things we have to take note of here. The numbers 0, 1,
|
||||
and 2 are all solely for illustrative purposes, and bear no relationship to the
|
||||
actual numbers the computer will actually use. In particular, the series of
|
||||
addresses are in reality going to be separated by some number of bytes that
|
||||
separate each address, and that separation may even exceed the size of the
|
||||
value being stored.
|
||||
|
||||
After `foo()` is over, its frame is deallocated:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 0 | x | 42 |
|
||||
|
||||
And then, after `main()`, even this last value goes away. Easy!
|
||||
|
||||
It’s called a ‘stack’ because it works like a stack of dinner plates: the first
|
||||
plate you put down is the last plate to pick back up. Stacks are sometimes
|
||||
called ‘last in, first out queues’ for this reason, as the last value you put
|
||||
on the stack is the first one you retrieve from it.
|
||||
|
||||
Let’s try a three-deep example:
|
||||
|
||||
```rust
|
||||
fn bar() {
|
||||
let i = 6;
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
let a = 5;
|
||||
let b = 100;
|
||||
let c = 1;
|
||||
|
||||
bar();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 42;
|
||||
|
||||
foo();
|
||||
}
|
||||
```
|
||||
|
||||
Okay, first, we call `main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 0 | x | 42 |
|
||||
|
||||
Next up, `main()` calls `foo()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 3 | c | 1 |
|
||||
| 2 | b | 100 |
|
||||
| 1 | a | 5 |
|
||||
| 0 | x | 42 |
|
||||
|
||||
And then `foo()` calls `bar()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 4 | i | 6 |
|
||||
| 3 | c | 1 |
|
||||
| 2 | b | 100 |
|
||||
| 1 | a | 5 |
|
||||
| 0 | x | 42 |
|
||||
|
||||
Whew! Our stack is growing tall.
|
||||
|
||||
After `bar()` is over, its frame is deallocated, leaving just `foo()` and
|
||||
`main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 3 | c | 1 |
|
||||
| 2 | b | 100 |
|
||||
| 1 | a | 5 |
|
||||
| 0 | x | 42 |
|
||||
|
||||
And then `foo()` ends, leaving just `main()`
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 0 | x | 42 |
|
||||
|
||||
And then we’re done. Getting the hang of it? It’s like piling up dishes: you
|
||||
add to the top, you take away from the top.
|
||||
|
||||
# The Heap
|
||||
|
||||
Now, this works pretty well, but not everything can work like this. Sometimes,
|
||||
you need to pass some memory between different functions, or keep it alive for
|
||||
longer than a single function’s execution. For this, we can use the heap.
|
||||
|
||||
In Rust, you can allocate memory on the heap with the [`Box<T>` type][box].
|
||||
Here’s an example:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
let x = Box::new(5);
|
||||
let y = 42;
|
||||
}
|
||||
```
|
||||
|
||||
[box]: ../std/boxed/index.html
|
||||
|
||||
Here’s what happens in memory when `main()` is called:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+--------+
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | ?????? |
|
||||
|
||||
We allocate space for two variables on the stack. `y` is `42`, as it always has
|
||||
been, but what about `x`? Well, `x` is a `Box<i32>`, and boxes allocate memory
|
||||
on the heap. The actual value of the box is a structure which has a pointer to
|
||||
‘the heap’. When we start executing the function, and `Box::new()` is called,
|
||||
it allocates some memory for the heap, and puts `5` there. The memory now looks
|
||||
like this:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | 2<sup>30</sup> |
|
||||
|
||||
We have 2<sup>30</sup> in our hypothetical computer with 1GB of RAM. And since
|
||||
our stack grows from zero, the easiest place to allocate memory is from the
|
||||
other end. So our first value is at the highest place in memory. And the value
|
||||
of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve
|
||||
allocated on the heap, so the value of `x` is 2<sup>30</sup>, the memory
|
||||
location we’ve asked for.
|
||||
|
||||
[rawpointer]: raw-pointers.html
|
||||
|
||||
We haven’t really talked too much about what it actually means to allocate and
|
||||
deallocate memory in these contexts. Getting into very deep detail is out of
|
||||
the scope of this tutorial, but what’s important to point out here is that
|
||||
the heap isn’t just a stack that grows from the opposite end. We’ll have an
|
||||
example of this later in the book, but because the heap can be allocated and
|
||||
freed in any order, it can end up with ‘holes’. Here’s a diagram of the memory
|
||||
layout of a program which has been running for a while now:
|
||||
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | |
|
||||
| (2<sup>30</sup>) - 2 | | |
|
||||
| (2<sup>30</sup>) - 3 | | 42 |
|
||||
| ... | ... | ... |
|
||||
| 3 | y | (2<sup>30</sup>) - 3 |
|
||||
| 2 | y | 42 |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | 2<sup>30</sup> |
|
||||
|
||||
In this case, we’ve allocated four things on the heap, but deallocated two of
|
||||
them. There’s a gap between 2<sup>30</sup> and (2<sup>30</sup>) - 3 which isn’t
|
||||
currently being used. The specific details of how and why this happens depends
|
||||
on what kind of strategy you use to manage the heap. Different programs can use
|
||||
different ‘memory allocators’, which are libraries that manage this for you.
|
||||
Rust programs use [jemalloc][jemalloc] for this purpose.
|
||||
|
||||
[jemalloc]: http://www.canonware.com/jemalloc/
|
||||
|
||||
Anyway, back to our example. Since this memory is on the heap, it can stay
|
||||
alive longer than the function which allocates the box. In this case, however,
|
||||
it doesn’t.[^moving] When the function is over, we need to free the stack frame
|
||||
for `main()`. `Box<T>`, though, has a trick up its sleve: [Drop][drop]. The
|
||||
implementation of `Drop` for `Box` deallocates the memory that was allocated
|
||||
when it was created. Great! So when `x` goes away, it first frees the memory
|
||||
allocated on the heap:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+--------+
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | ?????? |
|
||||
|
||||
[drop]: drop.html
|
||||
[moving]: We can make the memory live longer by transferring ownership,
|
||||
sometimes called ‘moving out of the box’. More complex examples will
|
||||
be covered later.
|
||||
|
||||
|
||||
And then the stack frame goes away, freeing all of our memory.
|
||||
|
||||
# Arguments and borrowing
|
||||
|
||||
We’ve got some basic examples with the stack and the heap going, but what about
|
||||
function arguments and borrowing? Here’s a small Rust program:
|
||||
|
||||
```rust
|
||||
fn foo(i: &i32) {
|
||||
let z = 42;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 5;
|
||||
let y = &x;
|
||||
|
||||
foo(y);
|
||||
}
|
||||
```
|
||||
|
||||
When we enter `main()`, memory looks like this:
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 1 | y | 0 |
|
||||
| 0 | x | 5 |
|
||||
|
||||
`x` is a plain old `5`, and `y` is a reference to `x`. So its value is the
|
||||
memory location that `x` lives at, which in this case is `0`.
|
||||
|
||||
What about when we call `foo()`, passing `y` as an argument?
|
||||
|
||||
| Address | Name | Value |
|
||||
+---------+------+-------+
|
||||
| 3 | z | 42 |
|
||||
| 2 | i | 0 |
|
||||
| 1 | y | 0 |
|
||||
| 0 | x | 5 |
|
||||
|
||||
Stack frames aren’t just for local bindings, they’re for arguments too. So in
|
||||
this case, we need to have both `i`, our argument, and `z`, our local variable
|
||||
binding. `i` is a copy of the argument, `y`. Since `y`’s value is `0`, so is
|
||||
`i`’s.
|
||||
|
||||
This is one reason why borrowing a variable doesn’t deallocate any memory: the
|
||||
value of a reference is just a pointer to a memory location. If we got rid of
|
||||
the underlying memory, things wouldn’t work very well.
|
||||
|
||||
# A complex example
|
||||
|
||||
Okay, let’s go through this complex program step-by-step:
|
||||
|
||||
```rust
|
||||
fn foo(x: &i32) {
|
||||
let y = 10;
|
||||
let z = &y;
|
||||
|
||||
baz(z);
|
||||
bar(x, z);
|
||||
}
|
||||
|
||||
fn bar(a: &i32, b: &i32) {
|
||||
let c = 5;
|
||||
let d = Box::new(5);
|
||||
let e = &d;
|
||||
|
||||
baz(e);
|
||||
}
|
||||
|
||||
fn baz(f: &i32) {
|
||||
let g = 100;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let h = 3;
|
||||
let i = Box::new(20);
|
||||
let j = &h;
|
||||
|
||||
foo(j);
|
||||
}
|
||||
```
|
||||
|
||||
First, we call `main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a
|
||||
value pointing there.
|
||||
|
||||
Next, at the end of `main()`, `foo()` gets called:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value
|
||||
as `j`, since that’s what we passed it in. It’s a pointer to the `0` address,
|
||||
since `j` points at `h`.
|
||||
|
||||
Next, `foo()` calls `baz()`, passing `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 7 | g | 100 |
|
||||
| 6 | f | 4 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s
|
||||
over, we get rid of its stack frame:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Next, `foo()` calls `bar()` with `x` and `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | 4 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
| 6 | a | 0 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We end up allocating another value on the heap, and so we have to subtract one
|
||||
from 2<sup>30</sup>. It’s easier to just write that than `1,073,741,823`. In any
|
||||
case, we set up the variables as usual.
|
||||
|
||||
At the end of `bar()`, it calls `baz()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 12 | g | 100 |
|
||||
| 11 | f | 4 |
|
||||
| 10 | e | 4 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
| 6 | a | 0 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
With this, we’re at our deepest point! Whew! Congrats for following along this
|
||||
far.
|
||||
|
||||
After `baz()` is over, we get rid of `f` and `g`:
|
||||
|
||||
| Address | Name | Value |
|
||||
+----------------------+------+----------------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | 4 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
| 6 | a | 0 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Next, we return from `bar()`. `d` in this case is a `Box<T>`, so it also frees
|
||||
what it points to: (2<sup>30</sup>) - 1.
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
And after that, `foo()` returns:
|
||||
|
||||
| Address | Name | Value |
|
||||
+-----------------+------+----------------+
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped,
|
||||
it will clean up the last of the heap too.
|
||||
|
||||
# What do other languages do?
|
||||
|
||||
Most languages with a garbage collector heap-allocate by default. This means
|
||||
that every value is boxed. There are a number of reasons why this is done, but
|
||||
they’re out of scope for this tutorial. There are some possible optimizations
|
||||
that don’t make it true 100% of the time, too. Rather than relying on the stack
|
||||
and `Drop` to clean up memory, the garbage collector deals with the heap
|
||||
instead.
|
||||
|
||||
# Which to use?
|
||||
|
||||
So if the stack is faster and easier to manage, why do we need the heap? A big
|
||||
reason is that Stack-allocation alone means you only have LIFO semantics for
|
||||
reclaiming storage. Heap-allocation is strictly more general, allowing storage
|
||||
to be taken from and returned to the pool in arbitrary order, but at a
|
||||
complexity cost.
|
||||
|
||||
Generally, you should prefer stack allocation, and so, Rust stack-allocates by
|
||||
default. The LIFO model of the stack is simpler, at a fundamental level. This
|
||||
has two big impacts: runtime efficiency and semantic impact.
|
||||
|
||||
## Runtime Efficiency.
|
||||
|
||||
Managing the memory for the stack is trivial: The machine just
|
||||
increments or decrements a single value, the so-called “stack pointer”.
|
||||
Managing memory for the heap is non-trivial: heap-allocated memory is freed at
|
||||
arbitrary points, and each block of heap-allocated memory can be of arbitrary
|
||||
size, the memory manager must generally work much harder to identify memory for
|
||||
reuse.
|
||||
|
||||
If you’d like to dive into this topic in greater detail, [this paper][wilson]
|
||||
is a great introduction.
|
||||
|
||||
[wilson]: http://www.cs.northwestern.edu/~pdinda/icsclass/doc/dsa.pdf
|
||||
|
||||
## Semantic impact
|
||||
|
||||
Stack-allocation impacts the Rust language itself, and thus the developer’s
|
||||
mental model. The LIFO semantics is what drives how the Rust language handles
|
||||
automatic memory management. Even the deallocation of a uniquely-owned
|
||||
heap-allocated box can be driven by the stack-based LIFO semantics, as
|
||||
discussed throughout this chapter. The flexibility (i.e. expressiveness) of non
|
||||
LIFO-semantics means that in general the compiler cannot automatically infer at
|
||||
compile-time where memory should be freed; it has to rely on dynamic protocols,
|
||||
potentially from outside the language itself, to drive deallocation (reference
|
||||
counting, as used by `Rc<T>` and `Arc<T>`, is one example of this).
|
||||
|
||||
When taken to the extreme, the increased expressive power of heap allocation
|
||||
comes at the cost of either significant runtime support (e.g. in the form of a
|
||||
garbage collector) or significant programmer effort (in the form of explicit
|
||||
memory management calls that require verification not provided by the Rust
|
||||
compiler).
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
% while loops
|
||||
% while Loops
|
||||
|
||||
Rust also has a `while` loop. It looks like this:
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# Configs
|
||||
|
||||
Here are some links to repos with configs which ease the use of rust:
|
||||
These are some links to repos with configs which ease the use of rust.
|
||||
|
||||
## Officially Maintained Configs
|
||||
|
||||
* [rust.vim](https://github.com/rust-lang/rust.vim)
|
||||
* [emacs rust-mode](https://github.com/rust-lang/rust-mode)
|
||||
|
|
@ -8,3 +10,7 @@ Here are some links to repos with configs which ease the use of rust:
|
|||
* [kate-config](https://github.com/rust-lang/kate-config)
|
||||
* [nano-config](https://github.com/rust-lang/nano-config)
|
||||
* [zsh-config](https://github.com/rust-lang/zsh-config)
|
||||
|
||||
## Community-maintained Configs
|
||||
|
||||
* [.editorconfig](https://gist.github.com/derhuerst/c9d1b9309e308d9851fa) ([what is this?](http://editorconfig.org/))
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
import os
|
||||
import sys
|
||||
import functools
|
||||
import resource
|
||||
|
||||
STATUS = 0
|
||||
|
||||
|
|
@ -37,6 +36,7 @@ def only_on(platforms):
|
|||
|
||||
@only_on(('linux', 'darwin', 'freebsd', 'openbsd'))
|
||||
def check_rlimit_core():
|
||||
import resource
|
||||
soft, hard = resource.getrlimit(resource.RLIMIT_CORE)
|
||||
if soft > 0:
|
||||
error_unless_permitted('ALLOW_NONZERO_RLIMIT_CORE', """\
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use core::{isize, usize};
|
||||
|
||||
#[inline(always)]
|
||||
fn check_size_and_alignment(size: usize, align: usize) {
|
||||
debug_assert!(size != 0);
|
||||
debug_assert!(size <= isize::MAX as usize, "Tried to allocate too much: {} bytes", size);
|
||||
debug_assert!(usize::is_power_of_two(align), "Invalid alignment of allocation: {}", align);
|
||||
}
|
||||
|
||||
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
|
||||
|
||||
/// Return a pointer to `size` bytes of memory aligned to `align`.
|
||||
|
|
@ -19,6 +28,7 @@
|
|||
/// size on the platform.
|
||||
#[inline]
|
||||
pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
|
||||
check_size_and_alignment(size, align);
|
||||
imp::allocate(size, align)
|
||||
}
|
||||
|
||||
|
|
@ -38,6 +48,7 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 {
|
|||
/// any value in range_inclusive(requested_size, usable_size).
|
||||
#[inline]
|
||||
pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 {
|
||||
check_size_and_alignment(size, align);
|
||||
imp::reallocate(ptr, old_size, size, align)
|
||||
}
|
||||
|
||||
|
|
@ -56,6 +67,7 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usiz
|
|||
#[inline]
|
||||
pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize,
|
||||
align: usize) -> usize {
|
||||
check_size_and_alignment(size, align);
|
||||
imp::reallocate_inplace(ptr, old_size, size, align)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1537,7 +1537,7 @@ impl BitSet {
|
|||
bit_vec.nbits = trunc_len * u32::BITS;
|
||||
}
|
||||
|
||||
/// Iterator over each u32 stored in the `BitSet`.
|
||||
/// Iterator over each usize stored in the `BitSet`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1558,7 +1558,7 @@ impl BitSet {
|
|||
SetIter {set: self, next_idx: 0}
|
||||
}
|
||||
|
||||
/// Iterator over each u32 stored in `self` union `other`.
|
||||
/// Iterator over each usize stored in `self` union `other`.
|
||||
/// See [union_with](#method.union_with) for an efficient in-place version.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -1658,7 +1658,7 @@ impl BitSet {
|
|||
})
|
||||
}
|
||||
|
||||
/// Iterator over each u32 stored in the symmetric difference of `self` and `other`.
|
||||
/// Iterator over each usize stored in the symmetric difference of `self` and `other`.
|
||||
/// See [symmetric_difference_with](#method.symmetric_difference_with) for
|
||||
/// an efficient in-place version.
|
||||
///
|
||||
|
|
@ -1796,6 +1796,89 @@ impl BitSet {
|
|||
self.other_op(other, |w1, w2| w1 ^ w2);
|
||||
}
|
||||
|
||||
/// Moves all elements from `other` into `Self`, leaving `other` empty.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections, bit_set_append_split_off)]
|
||||
/// use std::collections::{BitVec, BitSet};
|
||||
///
|
||||
/// let mut a = BitSet::new();
|
||||
/// a.insert(2);
|
||||
/// a.insert(6);
|
||||
///
|
||||
/// let mut b = BitSet::new();
|
||||
/// b.insert(1);
|
||||
/// b.insert(3);
|
||||
/// b.insert(6);
|
||||
///
|
||||
/// a.append(&mut b);
|
||||
///
|
||||
/// assert_eq!(a.len(), 4);
|
||||
/// assert_eq!(b.len(), 0);
|
||||
/// assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01110010])));
|
||||
/// ```
|
||||
#[unstable(feature = "bit_set_append_split_off",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn append(&mut self, other: &mut Self) {
|
||||
self.union_with(other);
|
||||
other.clear();
|
||||
}
|
||||
|
||||
/// Splits the `BitSet` into two at the given key including the key.
|
||||
/// Retains the first part in-place while returning the second part.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(collections, bit_set_append_split_off)]
|
||||
/// use std::collections::{BitSet, BitVec};
|
||||
/// let mut a = BitSet::new();
|
||||
/// a.insert(2);
|
||||
/// a.insert(6);
|
||||
/// a.insert(1);
|
||||
/// a.insert(3);
|
||||
///
|
||||
/// let b = a.split_off(3);
|
||||
///
|
||||
/// assert_eq!(a.len(), 2);
|
||||
/// assert_eq!(b.len(), 2);
|
||||
/// assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01100000])));
|
||||
/// assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0b00010010])));
|
||||
/// ```
|
||||
#[unstable(feature = "bit_set_append_split_off",
|
||||
reason = "recently added as part of collections reform 2")]
|
||||
pub fn split_off(&mut self, at: usize) -> Self {
|
||||
let mut other = BitSet::new();
|
||||
|
||||
if at == 0 {
|
||||
swap(self, &mut other);
|
||||
return other;
|
||||
} else if at >= self.bit_vec.len() {
|
||||
return other;
|
||||
}
|
||||
|
||||
// Calculate block and bit at which to split
|
||||
let w = at / u32::BITS;
|
||||
let b = at % u32::BITS;
|
||||
|
||||
// Pad `other` with `w` zero blocks,
|
||||
// append `self`'s blocks in the range from `w` to the end to `other`
|
||||
other.bit_vec.storage.extend(repeat(0u32).take(w)
|
||||
.chain(self.bit_vec.storage[w..].iter().cloned()));
|
||||
other.bit_vec.nbits = self.bit_vec.nbits;
|
||||
|
||||
if b > 0 {
|
||||
other.bit_vec.storage[w] &= !0 << b;
|
||||
}
|
||||
|
||||
// Sets `bit_vec.len()` and fixes the last block as well
|
||||
self.bit_vec.truncate(at);
|
||||
|
||||
other
|
||||
}
|
||||
|
||||
/// Returns the number of set bits in this set.
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ use self::Cow::*;
|
|||
/// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`. A given
|
||||
/// type can be borrowed as multiple different types. In particular, `Vec<T>:
|
||||
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
|
||||
///
|
||||
/// `Borrow` is very similar to, but different than, `AsRef`. See
|
||||
/// [the book][book] for more.
|
||||
///
|
||||
/// [book]: ../../book/borrow-and-asref.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Borrow<Borrowed: ?Sized> {
|
||||
/// Immutably borrows from an owned value.
|
||||
|
|
|
|||
|
|
@ -1002,7 +1002,7 @@ pub trait SliceConcatExt<T: ?Sized> {
|
|||
/// The resulting type after concatenation
|
||||
type Output;
|
||||
|
||||
/// Flattens a slice of `T` into a single value `U`.
|
||||
/// Flattens a slice of `T` into a single value `Self::Output`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
@ -1012,7 +1012,8 @@ pub trait SliceConcatExt<T: ?Sized> {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn concat(&self) -> Self::Output;
|
||||
|
||||
/// Flattens a slice of `T` into a single value `U`, placing a given separator between each.
|
||||
/// Flattens a slice of `T` into a single value `Self::Output`, placing a given separator
|
||||
/// between each.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1052,6 +1052,7 @@ impl<T: fmt::Display + ?Sized> ToString for T {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRef<str> for String {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ impl<V> VecMap<V> {
|
|||
// Move all elements to other
|
||||
swap(self, &mut other);
|
||||
return other
|
||||
} else if at > self.v.len() {
|
||||
} else if at >= self.v.len() {
|
||||
// No elements to copy
|
||||
return other;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -387,6 +387,67 @@ fn test_bit_vec_clone() {
|
|||
assert!(b.contains(&1000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bit_set_append() {
|
||||
let mut a = BitSet::new();
|
||||
a.insert(2);
|
||||
a.insert(6);
|
||||
|
||||
let mut b = BitSet::new();
|
||||
b.insert(1);
|
||||
b.insert(3);
|
||||
b.insert(6);
|
||||
|
||||
a.append(&mut b);
|
||||
|
||||
assert_eq!(a.len(), 4);
|
||||
assert_eq!(b.len(), 0);
|
||||
assert!(b.capacity() >= 6);
|
||||
|
||||
assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b01110010])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bit_set_split_off() {
|
||||
// Split at 0
|
||||
let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101]));
|
||||
|
||||
let b = a.split_off(0);
|
||||
|
||||
assert_eq!(a.len(), 0);
|
||||
assert_eq!(b.len(), 21);
|
||||
|
||||
assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101])));
|
||||
|
||||
// Split behind last element
|
||||
let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101]));
|
||||
|
||||
let b = a.split_off(50);
|
||||
|
||||
assert_eq!(a.len(), 21);
|
||||
assert_eq!(b.len(), 0);
|
||||
|
||||
assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101])));
|
||||
|
||||
// Split at arbitrary element
|
||||
let mut a = BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01101011, 0b10101101]));
|
||||
|
||||
let b = a.split_off(34);
|
||||
|
||||
assert_eq!(a.len(), 12);
|
||||
assert_eq!(b.len(), 9);
|
||||
|
||||
assert_eq!(a, BitSet::from_bit_vec(BitVec::from_bytes(&[0b10100000, 0b00010010, 0b10010010,
|
||||
0b00110011, 0b01000000])));
|
||||
assert_eq!(b, BitSet::from_bit_vec(BitVec::from_bytes(&[0, 0, 0, 0,
|
||||
0b00101011, 0b10101101])));
|
||||
}
|
||||
|
||||
mod bench {
|
||||
use std::collections::{BitSet, BitVec};
|
||||
use std::__rand::{Rng, thread_rng, ThreadRng};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(bit_set_append_split_off)]
|
||||
#![feature(bit_vec_append_split_off)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(collections)]
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@ use marker::Sized;
|
|||
|
||||
/// A cheap, reference-to-reference conversion.
|
||||
///
|
||||
/// `AsRef` is very similar to, but different than, `Borrow`. See
|
||||
/// [the book][book] for more.
|
||||
///
|
||||
/// [book]: ../../book/borrow-and-asref.html
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Both `String` and `&str` implement `AsRef<str>`:
|
||||
|
|
@ -173,6 +178,7 @@ impl<T> AsMut<[T]> for [T] {
|
|||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl AsRef<str> for str {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ pub trait Iterator {
|
|||
///
|
||||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert_eq!(a.iter().last().unwrap(), &5);
|
||||
/// assert_eq!(a.iter().last(), Some(&5));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -155,7 +155,7 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter();
|
||||
/// assert_eq!(it.nth(2).unwrap(), &3);
|
||||
/// assert_eq!(it.nth(2), Some(&3));
|
||||
/// assert_eq!(it.nth(2), None);
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -178,8 +178,8 @@ pub trait Iterator {
|
|||
/// let a = [0];
|
||||
/// let b = [1];
|
||||
/// let mut it = a.iter().chain(b.iter());
|
||||
/// assert_eq!(it.next().unwrap(), &0);
|
||||
/// assert_eq!(it.next().unwrap(), &1);
|
||||
/// assert_eq!(it.next(), Some(&0));
|
||||
/// assert_eq!(it.next(), Some(&1));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -201,7 +201,7 @@ pub trait Iterator {
|
|||
/// let a = [0];
|
||||
/// let b = [1];
|
||||
/// let mut it = a.iter().zip(b.iter());
|
||||
/// assert_eq!(it.next().unwrap(), (&0, &1));
|
||||
/// assert_eq!(it.next(), Some((&0, &1)));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
///
|
||||
|
|
@ -234,8 +234,8 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2];
|
||||
/// let mut it = a.iter().map(|&x| 2 * x);
|
||||
/// assert_eq!(it.next().unwrap(), 2);
|
||||
/// assert_eq!(it.next().unwrap(), 4);
|
||||
/// assert_eq!(it.next(), Some(2));
|
||||
/// assert_eq!(it.next(), Some(4));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -255,7 +255,7 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2];
|
||||
/// let mut it = a.iter().filter(|&x| *x > 1);
|
||||
/// assert_eq!(it.next().unwrap(), &2);
|
||||
/// assert_eq!(it.next(), Some(&2));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -275,7 +275,7 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2];
|
||||
/// let mut it = a.iter().filter_map(|&x| if x > 1 {Some(2 * x)} else {None});
|
||||
/// assert_eq!(it.next().unwrap(), 4);
|
||||
/// assert_eq!(it.next(), Some(4));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -310,8 +310,8 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [100, 200];
|
||||
/// let mut it = a.iter().enumerate();
|
||||
/// assert_eq!(it.next().unwrap(), (0, &100));
|
||||
/// assert_eq!(it.next().unwrap(), (1, &200));
|
||||
/// assert_eq!(it.next(), Some((0, &100)));
|
||||
/// assert_eq!(it.next(), Some((1, &200)));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -353,9 +353,9 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().skip_while(|&a| *a < 3);
|
||||
/// assert_eq!(it.next().unwrap(), &3);
|
||||
/// assert_eq!(it.next().unwrap(), &4);
|
||||
/// assert_eq!(it.next().unwrap(), &5);
|
||||
/// assert_eq!(it.next(), Some(&3));
|
||||
/// assert_eq!(it.next(), Some(&4));
|
||||
/// assert_eq!(it.next(), Some(&5));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -375,8 +375,8 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().take_while(|&a| *a < 3);
|
||||
/// assert_eq!(it.next().unwrap(), &1);
|
||||
/// assert_eq!(it.next().unwrap(), &2);
|
||||
/// assert_eq!(it.next(), Some(&1));
|
||||
/// assert_eq!(it.next(), Some(&2));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -395,8 +395,8 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().skip(3);
|
||||
/// assert_eq!(it.next().unwrap(), &4);
|
||||
/// assert_eq!(it.next().unwrap(), &5);
|
||||
/// assert_eq!(it.next(), Some(&4));
|
||||
/// assert_eq!(it.next(), Some(&5));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -413,9 +413,9 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter().take(3);
|
||||
/// assert_eq!(it.next().unwrap(), &1);
|
||||
/// assert_eq!(it.next().unwrap(), &2);
|
||||
/// assert_eq!(it.next().unwrap(), &3);
|
||||
/// assert_eq!(it.next(), Some(&1));
|
||||
/// assert_eq!(it.next(), Some(&2));
|
||||
/// assert_eq!(it.next(), Some(&3));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -437,11 +437,11 @@ pub trait Iterator {
|
|||
/// *fac = *fac * x;
|
||||
/// Some(*fac)
|
||||
/// });
|
||||
/// assert_eq!(it.next().unwrap(), 1);
|
||||
/// assert_eq!(it.next().unwrap(), 2);
|
||||
/// assert_eq!(it.next().unwrap(), 6);
|
||||
/// assert_eq!(it.next().unwrap(), 24);
|
||||
/// assert_eq!(it.next().unwrap(), 120);
|
||||
/// assert_eq!(it.next(), Some(1));
|
||||
/// assert_eq!(it.next(), Some(2));
|
||||
/// assert_eq!(it.next(), Some(6));
|
||||
/// assert_eq!(it.next(), Some(24));
|
||||
/// assert_eq!(it.next(), Some(120));
|
||||
/// assert!(it.next().is_none());
|
||||
/// ```
|
||||
#[inline]
|
||||
|
|
@ -680,7 +680,7 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter();
|
||||
/// assert_eq!(it.find(|&x| *x == 3).unwrap(), &3);
|
||||
/// assert_eq!(it.find(|&x| *x == 3), Some(&3));
|
||||
/// assert_eq!(it.collect::<Vec<_>>(), [&4, &5]);
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -715,7 +715,7 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// let mut it = a.iter();
|
||||
/// assert_eq!(it.position(|x| *x == 3).unwrap(), 2);
|
||||
/// assert_eq!(it.position(|x| *x == 3), Some(2));
|
||||
/// assert_eq!(it.collect::<Vec<_>>(), [&4, &5]);
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -743,7 +743,7 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2, 2, 4, 5];
|
||||
/// let mut it = a.iter();
|
||||
/// assert_eq!(it.rposition(|x| *x == 2).unwrap(), 2);
|
||||
/// assert_eq!(it.rposition(|x| *x == 2), Some(2));
|
||||
/// assert_eq!(it.collect::<Vec<_>>(), [&1, &2]);
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -773,7 +773,7 @@ pub trait Iterator {
|
|||
///
|
||||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert_eq!(a.iter().max().unwrap(), &5);
|
||||
/// assert_eq!(a.iter().max(), Some(&5));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -796,7 +796,7 @@ pub trait Iterator {
|
|||
///
|
||||
/// ```
|
||||
/// let a = [1, 2, 3, 4, 5];
|
||||
/// assert_eq!(a.iter().min().unwrap(), &1);
|
||||
/// assert_eq!(a.iter().min(), Some(&1));
|
||||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
|
@ -1025,9 +1025,9 @@ pub trait Iterator {
|
|||
/// ```
|
||||
/// let a = [1, 2];
|
||||
/// let mut it = a.iter().cycle();
|
||||
/// assert_eq!(it.next().unwrap(), &1);
|
||||
/// assert_eq!(it.next().unwrap(), &2);
|
||||
/// assert_eq!(it.next().unwrap(), &1);
|
||||
/// assert_eq!(it.next(), Some(&1));
|
||||
/// assert_eq!(it.next(), Some(&2));
|
||||
/// assert_eq!(it.next(), Some(&1));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ impl<T> SliceExt for [T] {
|
|||
assume(!p.is_null());
|
||||
if mem::size_of::<T>() == 0 {
|
||||
Iter {ptr: p,
|
||||
end: (p as usize + self.len()) as *const T,
|
||||
end: ((p as usize).wrapping_add(self.len())) as *const T,
|
||||
_marker: marker::PhantomData}
|
||||
} else {
|
||||
Iter {ptr: p,
|
||||
|
|
@ -277,7 +277,7 @@ impl<T> SliceExt for [T] {
|
|||
assume(!p.is_null());
|
||||
if mem::size_of::<T>() == 0 {
|
||||
IterMut {ptr: p,
|
||||
end: (p as usize + self.len()) as *mut T,
|
||||
end: ((p as usize).wrapping_add(self.len())) as *mut T,
|
||||
_marker: marker::PhantomData}
|
||||
} else {
|
||||
IterMut {ptr: p,
|
||||
|
|
@ -632,35 +632,17 @@ fn size_from_ptr<T>(_: *const T) -> usize {
|
|||
|
||||
|
||||
// Use macros to be generic over const/mut
|
||||
//
|
||||
// They require non-negative `$by` because otherwise the expression
|
||||
// `(ptr as usize + $by)` would interpret `-1` as `usize::MAX` (and
|
||||
// thus trigger a panic when overflow checks are on).
|
||||
|
||||
// Use this to do `$ptr + $by`, where `$by` is non-negative.
|
||||
macro_rules! slice_add_offset {
|
||||
macro_rules! slice_offset {
|
||||
($ptr:expr, $by:expr) => {{
|
||||
let ptr = $ptr;
|
||||
if size_from_ptr(ptr) == 0 {
|
||||
transmute(ptr as usize + $by)
|
||||
transmute((ptr as isize).wrapping_add($by))
|
||||
} else {
|
||||
ptr.offset($by)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
// Use this to do `$ptr - $by`, where `$by` is non-negative.
|
||||
macro_rules! slice_sub_offset {
|
||||
($ptr:expr, $by:expr) => {{
|
||||
let ptr = $ptr;
|
||||
if size_from_ptr(ptr) == 0 {
|
||||
transmute(ptr as usize - $by)
|
||||
} else {
|
||||
ptr.offset(-$by)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! slice_ref {
|
||||
($ptr:expr) => {{
|
||||
let ptr = $ptr;
|
||||
|
|
@ -683,14 +665,16 @@ macro_rules! iterator {
|
|||
#[inline]
|
||||
fn next(&mut self) -> Option<$elem> {
|
||||
// could be implemented with slices, but this avoids bounds checks
|
||||
unsafe {
|
||||
::intrinsics::assume(!self.ptr.is_null());
|
||||
::intrinsics::assume(!self.end.is_null());
|
||||
if self.ptr == self.end {
|
||||
None
|
||||
} else {
|
||||
if self.ptr == self.end {
|
||||
None
|
||||
} else {
|
||||
unsafe {
|
||||
if mem::size_of::<T>() != 0 {
|
||||
::intrinsics::assume(!self.ptr.is_null());
|
||||
::intrinsics::assume(!self.end.is_null());
|
||||
}
|
||||
let old = self.ptr;
|
||||
self.ptr = slice_add_offset!(self.ptr, 1);
|
||||
self.ptr = slice_offset!(self.ptr, 1);
|
||||
Some(slice_ref!(old))
|
||||
}
|
||||
}
|
||||
|
|
@ -698,7 +682,7 @@ macro_rules! iterator {
|
|||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let diff = (self.end as usize) - (self.ptr as usize);
|
||||
let diff = (self.end as usize).wrapping_sub(self.ptr as usize);
|
||||
let size = mem::size_of::<T>();
|
||||
let exact = diff / (if size == 0 {1} else {size});
|
||||
(exact, Some(exact))
|
||||
|
|
@ -726,13 +710,15 @@ macro_rules! iterator {
|
|||
#[inline]
|
||||
fn next_back(&mut self) -> Option<$elem> {
|
||||
// could be implemented with slices, but this avoids bounds checks
|
||||
unsafe {
|
||||
::intrinsics::assume(!self.ptr.is_null());
|
||||
::intrinsics::assume(!self.end.is_null());
|
||||
if self.end == self.ptr {
|
||||
None
|
||||
} else {
|
||||
self.end = slice_sub_offset!(self.end, 1);
|
||||
if self.end == self.ptr {
|
||||
None
|
||||
} else {
|
||||
unsafe {
|
||||
self.end = slice_offset!(self.end, -1);
|
||||
if mem::size_of::<T>() != 0 {
|
||||
::intrinsics::assume(!self.ptr.is_null());
|
||||
::intrinsics::assume(!self.end.is_null());
|
||||
}
|
||||
Some(slice_ref!(self.end))
|
||||
}
|
||||
}
|
||||
|
|
@ -742,29 +728,29 @@ macro_rules! iterator {
|
|||
}
|
||||
|
||||
macro_rules! make_slice {
|
||||
($t: ty => $result: ty: $start: expr, $end: expr) => {{
|
||||
let diff = $end as usize - $start as usize;
|
||||
let len = if mem::size_of::<T>() == 0 {
|
||||
diff
|
||||
($start: expr, $end: expr) => {{
|
||||
let start = $start;
|
||||
let diff = ($end as usize).wrapping_sub(start as usize);
|
||||
if size_from_ptr(start) == 0 {
|
||||
// use a non-null pointer value
|
||||
unsafe { from_raw_parts(1 as *const _, diff) }
|
||||
} else {
|
||||
diff / mem::size_of::<$t>()
|
||||
};
|
||||
unsafe {
|
||||
from_raw_parts($start, len)
|
||||
let len = diff / size_from_ptr(start);
|
||||
unsafe { from_raw_parts(start, len) }
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
macro_rules! make_mut_slice {
|
||||
($t: ty => $result: ty: $start: expr, $end: expr) => {{
|
||||
let diff = $end as usize - $start as usize;
|
||||
let len = if mem::size_of::<T>() == 0 {
|
||||
diff
|
||||
($start: expr, $end: expr) => {{
|
||||
let start = $start;
|
||||
let diff = ($end as usize).wrapping_sub(start as usize);
|
||||
if size_from_ptr(start) == 0 {
|
||||
// use a non-null pointer value
|
||||
unsafe { from_raw_parts_mut(1 as *mut _, diff) }
|
||||
} else {
|
||||
diff / mem::size_of::<$t>()
|
||||
};
|
||||
unsafe {
|
||||
from_raw_parts_mut($start, len)
|
||||
let len = diff / size_from_ptr(start);
|
||||
unsafe { from_raw_parts_mut(start, len) }
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
|
@ -787,14 +773,14 @@ impl<'a, T> Iter<'a, T> {
|
|||
/// iterator can continue to be used while this exists.
|
||||
#[unstable(feature = "core")]
|
||||
pub fn as_slice(&self) -> &'a [T] {
|
||||
make_slice!(T => &'a [T]: self.ptr, self.end)
|
||||
make_slice!(self.ptr, self.end)
|
||||
}
|
||||
|
||||
// Helper function for Iter::nth
|
||||
fn iter_nth(&mut self, n: usize) -> Option<&'a T> {
|
||||
match self.as_slice().get(n) {
|
||||
Some(elem_ref) => unsafe {
|
||||
self.ptr = slice_add_offset!(elem_ref as *const _, 1);
|
||||
self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
|
||||
Some(slice_ref!(elem_ref))
|
||||
},
|
||||
None => {
|
||||
|
|
@ -827,12 +813,7 @@ impl<'a, T> RandomAccessIterator for Iter<'a, T> {
|
|||
fn idx(&mut self, index: usize) -> Option<&'a T> {
|
||||
unsafe {
|
||||
if index < self.indexable() {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// Use a non-null pointer value
|
||||
Some(&mut *(1 as *mut _))
|
||||
} else {
|
||||
Some(transmute(self.ptr.offset(index as isize)))
|
||||
}
|
||||
Some(slice_ref!(self.ptr.offset(index as isize)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -860,14 +841,14 @@ impl<'a, T> IterMut<'a, T> {
|
|||
/// restricted lifetimes that do not consume the iterator.
|
||||
#[unstable(feature = "core")]
|
||||
pub fn into_slice(self) -> &'a mut [T] {
|
||||
make_mut_slice!(T => &'a mut [T]: self.ptr, self.end)
|
||||
make_mut_slice!(self.ptr, self.end)
|
||||
}
|
||||
|
||||
// Helper function for IterMut::nth
|
||||
fn iter_nth(&mut self, n: usize) -> Option<&'a mut T> {
|
||||
match make_mut_slice!(T => &'a mut [T]: self.ptr, self.end).get_mut(n) {
|
||||
match make_mut_slice!(self.ptr, self.end).get_mut(n) {
|
||||
Some(elem_ref) => unsafe {
|
||||
self.ptr = slice_add_offset!(elem_ref as *mut _, 1);
|
||||
self.ptr = slice_offset!(self.ptr, (n as isize).wrapping_add(1));
|
||||
Some(slice_ref!(elem_ref))
|
||||
},
|
||||
None => {
|
||||
|
|
|
|||
|
|
@ -44,8 +44,11 @@ pub trait FromStr {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
type Err;
|
||||
|
||||
/// Parses a string `s` to return an optional value of this type. If the
|
||||
/// string is ill-formatted, the None is returned.
|
||||
/// Parses a string `s` to return a value of this type.
|
||||
///
|
||||
/// If parsing succeeds, return the value inside `Ok`, otherwise
|
||||
/// when the string is ill-formatted return an error specific to the
|
||||
/// inside `Err`. The error type is specific to implementation of the trait.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5722,6 +5722,9 @@ pub mod funcs {
|
|||
pub fn tcgetpgrp(fd: c_int) -> pid_t;
|
||||
pub fn ttyname(fd: c_int) -> *mut c_char;
|
||||
pub fn unlink(c: *const c_char) -> c_int;
|
||||
pub fn wait(status: *const c_int) -> pid_t;
|
||||
pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int)
|
||||
-> pid_t;
|
||||
pub fn write(fd: c_int, buf: *const c_void, count: size_t)
|
||||
-> ssize_t;
|
||||
pub fn pread(fd: c_int, buf: *mut c_void, count: size_t,
|
||||
|
|
@ -5773,6 +5776,9 @@ pub mod funcs {
|
|||
pub fn sysconf(name: c_int) -> c_long;
|
||||
pub fn ttyname(fd: c_int) -> *mut c_char;
|
||||
pub fn unlink(c: *const c_char) -> c_int;
|
||||
pub fn wait(status: *const c_int) -> pid_t;
|
||||
pub fn waitpid(pid: pid_t, status: *const c_int, options: c_int)
|
||||
-> pid_t;
|
||||
pub fn write(fd: c_int, buf: *const c_void, count: size_t)
|
||||
-> ssize_t;
|
||||
pub fn pread(fd: c_int, buf: *mut c_void, count: size_t,
|
||||
|
|
|
|||
|
|
@ -273,8 +273,8 @@ See also http://doc.rust-lang.org/book/unsafe.html
|
|||
|
||||
E0137: r##"
|
||||
This error indicates that the compiler found multiple functions with the
|
||||
#[main] attribute. This is an error because there must be a unique entry point
|
||||
into a Rust program.
|
||||
`#[main]` attribute. This is an error because there must be a unique entry
|
||||
point into a Rust program.
|
||||
"##,
|
||||
|
||||
E0152: r##"
|
||||
|
|
@ -745,6 +745,7 @@ variable.
|
|||
|
||||
For example:
|
||||
|
||||
```
|
||||
let x: i32 = "I am not a number!";
|
||||
// ~~~ ~~~~~~~~~~~~~~~~~~~~
|
||||
// | |
|
||||
|
|
@ -752,6 +753,7 @@ let x: i32 = "I am not a number!";
|
|||
// | compiler infers type `&str`
|
||||
// |
|
||||
// type `i32` assigned to variable `x`
|
||||
```
|
||||
"##,
|
||||
|
||||
E0309: r##"
|
||||
|
|
@ -760,6 +762,7 @@ how long the data stored within them is guaranteed to be live. This lifetime
|
|||
must be as long as the data needs to be alive, and missing the constraint that
|
||||
denotes this will cause this error.
|
||||
|
||||
```
|
||||
// This won't compile because T is not constrained, meaning the data
|
||||
// stored in it is not guaranteed to last as long as the reference
|
||||
struct Foo<'a, T> {
|
||||
|
|
@ -770,6 +773,7 @@ struct Foo<'a, T> {
|
|||
struct Foo<'a, T: 'a> {
|
||||
foo: &'a T
|
||||
}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0310: r##"
|
||||
|
|
@ -778,6 +782,7 @@ how long the data stored within them is guaranteed to be live. This lifetime
|
|||
must be as long as the data needs to be alive, and missing the constraint that
|
||||
denotes this will cause this error.
|
||||
|
||||
```
|
||||
// This won't compile because T is not constrained to the static lifetime
|
||||
// the reference needs
|
||||
struct Foo<T> {
|
||||
|
|
@ -788,6 +793,7 @@ struct Foo<T> {
|
|||
struct Foo<T: 'static> {
|
||||
foo: &'static T
|
||||
}
|
||||
```
|
||||
"##
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ pub const tag_item_impl_vtables: usize = 0x7e;
|
|||
|
||||
pub const tag_impls: usize = 0x109; // top-level only
|
||||
pub const tag_impls_impl: usize = 0x7f;
|
||||
pub const tag_impls_impl_trait_def_id: usize = 0x8d;
|
||||
|
||||
pub const tag_items_data_item_inherent_impl: usize = 0x80;
|
||||
pub const tag_items_data_item_extension_impl: usize = 0x81;
|
||||
|
|
|
|||
|
|
@ -304,31 +304,23 @@ pub fn get_native_libraries(cstore: &cstore::CStore, crate_num: ast::CrateNum)
|
|||
decoder::get_native_libraries(&*cdata)
|
||||
}
|
||||
|
||||
pub fn each_impl<F>(cstore: &cstore::CStore,
|
||||
crate_num: ast::CrateNum,
|
||||
callback: F) where
|
||||
F: FnMut(ast::DefId),
|
||||
{
|
||||
let cdata = cstore.get_crate_data(crate_num);
|
||||
decoder::each_impl(&*cdata, callback)
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_type<F>(cstore: &cstore::CStore,
|
||||
def_id: ast::DefId,
|
||||
callback: F) where
|
||||
pub fn each_inherent_implementation_for_type<F>(cstore: &cstore::CStore,
|
||||
def_id: ast::DefId,
|
||||
callback: F) where
|
||||
F: FnMut(ast::DefId),
|
||||
{
|
||||
let cdata = cstore.get_crate_data(def_id.krate);
|
||||
decoder::each_implementation_for_type(&*cdata, def_id.node, callback)
|
||||
decoder::each_inherent_implementation_for_type(&*cdata, def_id.node, callback)
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_trait<F>(cstore: &cstore::CStore,
|
||||
def_id: ast::DefId,
|
||||
callback: F) where
|
||||
mut callback: F) where
|
||||
F: FnMut(ast::DefId),
|
||||
{
|
||||
let cdata = cstore.get_crate_data(def_id.krate);
|
||||
decoder::each_implementation_for_trait(&*cdata, def_id.node, callback)
|
||||
cstore.iter_crate_data(|_, cdata| {
|
||||
decoder::each_implementation_for_trait(cdata, def_id, &mut callback)
|
||||
})
|
||||
}
|
||||
|
||||
/// If the given def ID describes an item belonging to a trait (either a
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ use metadata::common::*;
|
|||
use metadata::csearch::MethodInfo;
|
||||
use metadata::csearch;
|
||||
use metadata::cstore;
|
||||
use metadata::tydecode::{parse_ty_data, parse_region_data, parse_def_id,
|
||||
use metadata::encoder::def_to_u64;
|
||||
use metadata::tydecode::{parse_ty_data, parse_region_data,
|
||||
parse_type_param_def_data, parse_bare_fn_ty_data,
|
||||
parse_trait_ref_data, parse_predicate_data};
|
||||
use middle::def;
|
||||
|
|
@ -190,29 +191,32 @@ fn item_symbol(item: rbml::Doc) -> String {
|
|||
reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string()
|
||||
}
|
||||
|
||||
fn item_parent_item(d: rbml::Doc) -> Option<ast::DefId> {
|
||||
fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> ast::DefId {
|
||||
let id = reader::doc_as_u64(d);
|
||||
let def_id = ast::DefId { krate: (id >> 32) as u32, node: id as u32 };
|
||||
translate_def_id(cdata, def_id)
|
||||
}
|
||||
|
||||
fn item_parent_item(cdata: Cmd, d: rbml::Doc) -> Option<ast::DefId> {
|
||||
let mut ret = None;
|
||||
reader::tagged_docs(d, tag_items_data_parent_item, |did| {
|
||||
ret = Some(reader::with_doc_data(did, parse_def_id));
|
||||
ret = Some(translated_def_id(cdata, did));
|
||||
false
|
||||
});
|
||||
ret
|
||||
}
|
||||
|
||||
fn item_reqd_and_translated_parent_item(cnum: ast::CrateNum,
|
||||
d: rbml::Doc) -> ast::DefId {
|
||||
let trait_did = item_parent_item(d).expect("item without parent");
|
||||
ast::DefId { krate: cnum, node: trait_did.node }
|
||||
fn item_require_parent_item(cdata: Cmd, d: rbml::Doc) -> ast::DefId {
|
||||
translated_def_id(cdata, reader::get_doc(d, tag_items_data_parent_item))
|
||||
}
|
||||
|
||||
fn item_def_id(d: rbml::Doc, cdata: Cmd) -> ast::DefId {
|
||||
let tagdoc = reader::get_doc(d, tag_def_id);
|
||||
return translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id));
|
||||
translated_def_id(cdata, reader::get_doc(d, tag_def_id))
|
||||
}
|
||||
|
||||
fn get_provided_source(d: rbml::Doc, cdata: Cmd) -> Option<ast::DefId> {
|
||||
reader::maybe_get_doc(d, tag_item_method_provided_source).map(|doc| {
|
||||
translate_def_id(cdata, reader::with_doc_data(doc, parse_def_id))
|
||||
translated_def_id(cdata, doc)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -261,14 +265,12 @@ fn item_trait_ref<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd)
|
|||
}
|
||||
|
||||
fn enum_variant_ids(item: rbml::Doc, cdata: Cmd) -> Vec<ast::DefId> {
|
||||
let mut ids: Vec<ast::DefId> = Vec::new();
|
||||
let v = tag_items_data_item_variant;
|
||||
reader::tagged_docs(item, v, |p| {
|
||||
let ext = reader::with_doc_data(p, parse_def_id);
|
||||
ids.push(ast::DefId { krate: cdata.cnum, node: ext.node });
|
||||
let mut ids = vec![];
|
||||
reader::tagged_docs(item, tag_items_data_item_variant, |p| {
|
||||
ids.push(translated_def_id(cdata, p));
|
||||
true
|
||||
});
|
||||
return ids;
|
||||
ids
|
||||
}
|
||||
|
||||
fn item_path(item_doc: rbml::Doc) -> Vec<ast_map::PathElem> {
|
||||
|
|
@ -303,8 +305,7 @@ fn item_name(intr: &IdentInterner, item: rbml::Doc) -> ast::Name {
|
|||
}
|
||||
}
|
||||
|
||||
fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
|
||||
-> DefLike {
|
||||
fn item_to_def_like(cdata: Cmd, item: rbml::Doc, did: ast::DefId) -> DefLike {
|
||||
let fam = item_family(item);
|
||||
match fam {
|
||||
Constant => {
|
||||
|
|
@ -314,11 +315,9 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
|
|||
// See the comment for methods below.
|
||||
let provenance = if reader::maybe_get_doc(
|
||||
item, tag_item_trait_parent_sort).is_some() {
|
||||
def::FromTrait(item_reqd_and_translated_parent_item(cnum,
|
||||
item))
|
||||
def::FromTrait(item_require_parent_item(cdata, item))
|
||||
} else {
|
||||
def::FromImpl(item_reqd_and_translated_parent_item(cnum,
|
||||
item))
|
||||
def::FromImpl(item_require_parent_item(cdata, item))
|
||||
};
|
||||
DlDef(def::DefAssociatedConst(did, provenance))
|
||||
} else {
|
||||
|
|
@ -339,17 +338,15 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
|
|||
// a trait_parent_sort.
|
||||
let provenance = if reader::maybe_get_doc(
|
||||
item, tag_item_trait_parent_sort).is_some() {
|
||||
def::FromTrait(item_reqd_and_translated_parent_item(cnum,
|
||||
item))
|
||||
def::FromTrait(item_require_parent_item(cdata, item))
|
||||
} else {
|
||||
def::FromImpl(item_reqd_and_translated_parent_item(cnum,
|
||||
item))
|
||||
def::FromImpl(item_require_parent_item(cdata, item))
|
||||
};
|
||||
DlDef(def::DefMethod(did, provenance))
|
||||
}
|
||||
Type => {
|
||||
if item_sort(item) == Some('t') {
|
||||
let trait_did = item_reqd_and_translated_parent_item(cnum, item);
|
||||
let trait_did = item_require_parent_item(cdata, item);
|
||||
DlDef(def::DefAssociatedTy(trait_did, did))
|
||||
} else {
|
||||
DlDef(def::DefTy(did, false))
|
||||
|
|
@ -358,11 +355,11 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
|
|||
Mod => DlDef(def::DefMod(did)),
|
||||
ForeignMod => DlDef(def::DefForeignMod(did)),
|
||||
StructVariant => {
|
||||
let enum_did = item_reqd_and_translated_parent_item(cnum, item);
|
||||
let enum_did = item_require_parent_item(cdata, item);
|
||||
DlDef(def::DefVariant(enum_did, did, true))
|
||||
}
|
||||
TupleVariant => {
|
||||
let enum_did = item_reqd_and_translated_parent_item(cnum, item);
|
||||
let enum_did = item_require_parent_item(cdata, item);
|
||||
DlDef(def::DefVariant(enum_did, did, false))
|
||||
}
|
||||
Trait => DlDef(def::DefTrait(did)),
|
||||
|
|
@ -560,9 +557,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
|
|||
{
|
||||
// Iterate over all children.
|
||||
let _ = reader::tagged_docs(item_doc, tag_mod_child, |child_info_doc| {
|
||||
let child_def_id = reader::with_doc_data(child_info_doc,
|
||||
parse_def_id);
|
||||
let child_def_id = translate_def_id(cdata, child_def_id);
|
||||
let child_def_id = translated_def_id(cdata, child_info_doc);
|
||||
|
||||
// This item may be in yet another crate if it was the child of a
|
||||
// reexport.
|
||||
|
|
@ -584,9 +579,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
|
|||
Some(child_item_doc) => {
|
||||
// Hand off the item to the callback.
|
||||
let child_name = item_name(&*intr, child_item_doc);
|
||||
let def_like = item_to_def_like(child_item_doc,
|
||||
child_def_id,
|
||||
cdata.cnum);
|
||||
let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
|
||||
let visibility = item_visibility(child_item_doc);
|
||||
callback(def_like, child_name, visibility);
|
||||
|
||||
|
|
@ -615,9 +608,8 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
|
|||
if let StaticMethod = item_family(impl_method_doc) {
|
||||
// Hand off the static method to the callback.
|
||||
let static_method_name = item_name(&*intr, impl_method_doc);
|
||||
let static_method_def_like = item_to_def_like(impl_method_doc,
|
||||
impl_item_def_id,
|
||||
cdata.cnum);
|
||||
let static_method_def_like = item_to_def_like(cdata, impl_method_doc,
|
||||
impl_item_def_id);
|
||||
callback(static_method_def_like,
|
||||
static_method_name,
|
||||
item_visibility(impl_method_doc));
|
||||
|
|
@ -633,9 +625,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
|
|||
let _ = each_reexport(item_doc, |reexport_doc| {
|
||||
let def_id_doc = reader::get_doc(reexport_doc,
|
||||
tag_items_data_item_reexport_def_id);
|
||||
let child_def_id = reader::with_doc_data(def_id_doc,
|
||||
parse_def_id);
|
||||
let child_def_id = translate_def_id(cdata, child_def_id);
|
||||
let child_def_id = translated_def_id(cdata, def_id_doc);
|
||||
|
||||
let name_doc = reader::get_doc(reexport_doc,
|
||||
tag_items_data_item_reexport_name);
|
||||
|
|
@ -657,9 +647,7 @@ fn each_child_of_item_or_crate<F, G>(intr: Rc<IdentInterner>,
|
|||
// Get the item.
|
||||
if let Some(child_item_doc) = maybe_find_item(child_def_id.node, other_crates_items) {
|
||||
// Hand off the item to the callback.
|
||||
let def_like = item_to_def_like(child_item_doc,
|
||||
child_def_id,
|
||||
child_def_id.krate);
|
||||
let def_like = item_to_def_like(crate_data, child_item_doc, child_def_id);
|
||||
// These items have a public visibility because they're part of
|
||||
// a public re-export.
|
||||
callback(def_like, token::intern(name), ast::Public);
|
||||
|
|
@ -733,9 +721,8 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &ty::ctxt<'tcx>, id: ast::NodeI
|
|||
match decode_inlined_item(cdata, tcx, path, item_doc) {
|
||||
Ok(ii) => csearch::FoundAst::Found(ii),
|
||||
Err(path) => {
|
||||
match item_parent_item(item_doc) {
|
||||
match item_parent_item(cdata, item_doc) {
|
||||
Some(did) => {
|
||||
let did = translate_def_id(cdata, did);
|
||||
let parent_item = lookup_item(did.node, cdata.data());
|
||||
match decode_inlined_item(cdata, tcx, path, parent_item) {
|
||||
Ok(ii) => csearch::FoundAst::FoundParent(did, ii),
|
||||
|
|
@ -759,7 +746,7 @@ pub fn get_enum_variant_defs(intr: &IdentInterner,
|
|||
let item = find_item(did.node, items);
|
||||
let name = item_name(intr, item);
|
||||
let visibility = item_visibility(item);
|
||||
match item_to_def_like(item, *did, cdata.cnum) {
|
||||
match item_to_def_like(cdata, item, *did) {
|
||||
DlDef(def @ def::DefVariant(..)) => (def, name, visibility),
|
||||
_ => unreachable!()
|
||||
}
|
||||
|
|
@ -889,8 +876,7 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
|
|||
|
||||
let def_id = item_def_id(method_doc, cdata);
|
||||
|
||||
let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
|
||||
method_doc);
|
||||
let container_id = item_require_parent_item(cdata, method_doc);
|
||||
let container_doc = lookup_item(container_id.node, cdata.data());
|
||||
let container = match item_family(container_doc) {
|
||||
Trait => TraitContainer(container_id),
|
||||
|
|
@ -1094,7 +1080,7 @@ pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
|
|||
let item = lookup_item(node_id, cdata.data());
|
||||
let mut ret = None;
|
||||
reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor, |_| {
|
||||
ret = Some(item_reqd_and_translated_parent_item(cdata.cnum, item));
|
||||
ret = Some(item_require_parent_item(cdata, item));
|
||||
false
|
||||
});
|
||||
ret
|
||||
|
|
@ -1144,7 +1130,7 @@ pub fn get_struct_fields(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId)
|
|||
let name = item_name(&*intr, an_item);
|
||||
let did = item_def_id(an_item, cdata);
|
||||
let tagdoc = reader::get_doc(an_item, tag_item_field_origin);
|
||||
let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id));
|
||||
let origin_id = translated_def_id(cdata, tagdoc);
|
||||
result.push(ty::field_ty {
|
||||
name: name,
|
||||
id: did,
|
||||
|
|
@ -1158,7 +1144,7 @@ pub fn get_struct_fields(intr: Rc<IdentInterner>, cdata: Cmd, id: ast::NodeId)
|
|||
let did = item_def_id(an_item, cdata);
|
||||
let tagdoc = reader::get_doc(an_item, tag_item_field_origin);
|
||||
let f = item_family(an_item);
|
||||
let origin_id = translate_def_id(cdata, reader::with_doc_data(tagdoc, parse_def_id));
|
||||
let origin_id = translated_def_id(cdata, tagdoc);
|
||||
result.push(ty::field_ty {
|
||||
name: special_idents::unnamed_field.name,
|
||||
id: did,
|
||||
|
|
@ -1342,55 +1328,77 @@ pub fn translate_def_id(cdata: Cmd, did: ast::DefId) -> ast::DefId {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn each_impl<F>(cdata: Cmd, mut callback: F) where
|
||||
F: FnMut(ast::DefId),
|
||||
{
|
||||
let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls);
|
||||
let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| {
|
||||
callback(item_def_id(impl_doc, cdata));
|
||||
true
|
||||
});
|
||||
// Translate a DefId from the current compilation environment to a DefId
|
||||
// for an external crate.
|
||||
fn reverse_translate_def_id(cdata: Cmd, did: ast::DefId) -> Option<ast::DefId> {
|
||||
if did.krate == cdata.cnum {
|
||||
return Some(ast::DefId { krate: ast::LOCAL_CRATE, node: did.node });
|
||||
}
|
||||
|
||||
for (&local, &global) in &cdata.cnum_map {
|
||||
if global == did.krate {
|
||||
return Some(ast::DefId { krate: local, node: did.node });
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_type<F>(cdata: Cmd,
|
||||
id: ast::NodeId,
|
||||
mut callback: F)
|
||||
pub fn each_inherent_implementation_for_type<F>(cdata: Cmd,
|
||||
id: ast::NodeId,
|
||||
mut callback: F)
|
||||
where F: FnMut(ast::DefId),
|
||||
{
|
||||
let item_doc = lookup_item(id, cdata.data());
|
||||
reader::tagged_docs(item_doc,
|
||||
tag_items_data_item_inherent_impl,
|
||||
|impl_doc| {
|
||||
let implementation_def_id = item_def_id(impl_doc, cdata);
|
||||
callback(implementation_def_id);
|
||||
if reader::maybe_get_doc(impl_doc, tag_item_trait_ref).is_none() {
|
||||
callback(item_def_id(impl_doc, cdata));
|
||||
}
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
pub fn each_implementation_for_trait<F>(cdata: Cmd,
|
||||
id: ast::NodeId,
|
||||
def_id: ast::DefId,
|
||||
mut callback: F) where
|
||||
F: FnMut(ast::DefId),
|
||||
{
|
||||
let item_doc = lookup_item(id, cdata.data());
|
||||
if cdata.cnum == def_id.krate {
|
||||
let item_doc = lookup_item(def_id.node, cdata.data());
|
||||
let _ = reader::tagged_docs(item_doc,
|
||||
tag_items_data_item_extension_impl,
|
||||
|impl_doc| {
|
||||
callback(item_def_id(impl_doc, cdata));
|
||||
true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = reader::tagged_docs(item_doc,
|
||||
tag_items_data_item_extension_impl,
|
||||
|impl_doc| {
|
||||
let implementation_def_id = item_def_id(impl_doc, cdata);
|
||||
callback(implementation_def_id);
|
||||
true
|
||||
});
|
||||
// Do a reverse lookup beforehand to avoid touching the crate_num
|
||||
// hash map in the loop below.
|
||||
if let Some(crate_local_did) = reverse_translate_def_id(cdata, def_id) {
|
||||
let def_id_u64 = def_to_u64(crate_local_did);
|
||||
|
||||
let impls_doc = reader::get_doc(rbml::Doc::new(cdata.data()), tag_impls);
|
||||
let _ = reader::tagged_docs(impls_doc, tag_impls_impl, |impl_doc| {
|
||||
let impl_trait = reader::get_doc(impl_doc, tag_impls_impl_trait_def_id);
|
||||
if reader::doc_as_u64(impl_trait) == def_id_u64 {
|
||||
callback(item_def_id(impl_doc, cdata));
|
||||
}
|
||||
true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_trait_of_item(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt)
|
||||
-> Option<ast::DefId> {
|
||||
let item_doc = lookup_item(id, cdata.data());
|
||||
let parent_item_id = match item_parent_item(item_doc) {
|
||||
let parent_item_id = match item_parent_item(cdata, item_doc) {
|
||||
None => return None,
|
||||
Some(item_id) => item_id,
|
||||
};
|
||||
let parent_item_id = translate_def_id(cdata, parent_item_id);
|
||||
let parent_item_doc = lookup_item(parent_item_id.node, cdata.data());
|
||||
match item_family(parent_item_doc) {
|
||||
Trait => Some(item_def_id(parent_item_doc, cdata)),
|
||||
|
|
@ -1538,8 +1546,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc,
|
|||
let name = item_name(&*token::get_ident_interner(), ident_str_doc);
|
||||
let def_id_doc = reader::get_doc(rp_doc,
|
||||
tag_region_param_def_def_id);
|
||||
let def_id = reader::with_doc_data(def_id_doc, parse_def_id);
|
||||
let def_id = translate_def_id(cdata, def_id);
|
||||
let def_id = translated_def_id(cdata, def_id_doc);
|
||||
|
||||
let doc = reader::get_doc(rp_doc, tag_region_param_def_space);
|
||||
let space = subst::ParamSpace::from_uint(reader::doc_as_u64(doc) as usize);
|
||||
|
|
|
|||
|
|
@ -91,8 +91,8 @@ fn encode_impl_type_basename(rbml_w: &mut Encoder, name: ast::Name) {
|
|||
rbml_w.wr_tagged_str(tag_item_impl_type_basename, &token::get_name(name));
|
||||
}
|
||||
|
||||
pub fn encode_def_id(rbml_w: &mut Encoder, id: DefId) {
|
||||
rbml_w.wr_tagged_str(tag_def_id, &def_to_string(id));
|
||||
fn encode_def_id(rbml_w: &mut Encoder, id: DefId) {
|
||||
rbml_w.wr_tagged_u64(tag_def_id, def_to_u64(id));
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -122,6 +122,10 @@ fn encode_family(rbml_w: &mut Encoder, c: char) {
|
|||
rbml_w.wr_tagged_u8(tag_items_data_item_family, c as u8);
|
||||
}
|
||||
|
||||
pub fn def_to_u64(did: DefId) -> u64 {
|
||||
(did.krate as u64) << 32 | (did.node as u64)
|
||||
}
|
||||
|
||||
pub fn def_to_string(did: DefId) -> String {
|
||||
format!("{}:{}", did.krate, did.node)
|
||||
}
|
||||
|
|
@ -153,9 +157,9 @@ fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
|
|||
}
|
||||
|
||||
fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) {
|
||||
let s = def_to_string(vid);
|
||||
rbml_w.wr_tagged_str(tag_items_data_item_variant, &s[..]);
|
||||
rbml_w.wr_tagged_str(tag_mod_child, &s[..]);
|
||||
let id = def_to_u64(vid);
|
||||
rbml_w.wr_tagged_u64(tag_items_data_item_variant, id);
|
||||
rbml_w.wr_tagged_u64(tag_mod_child, id);
|
||||
}
|
||||
|
||||
pub fn write_closure_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
||||
|
|
@ -260,7 +264,7 @@ fn encode_disr_val(_: &EncodeContext,
|
|||
}
|
||||
|
||||
fn encode_parent_item(rbml_w: &mut Encoder, id: DefId) {
|
||||
rbml_w.wr_tagged_str(tag_items_data_parent_item, &def_to_string(id));
|
||||
rbml_w.wr_tagged_u64(tag_items_data_parent_item, def_to_u64(id));
|
||||
}
|
||||
|
||||
fn encode_struct_fields(rbml_w: &mut Encoder,
|
||||
|
|
@ -275,7 +279,7 @@ fn encode_struct_fields(rbml_w: &mut Encoder,
|
|||
}
|
||||
encode_struct_field_family(rbml_w, f.vis);
|
||||
encode_def_id(rbml_w, f.id);
|
||||
rbml_w.wr_tagged_str(tag_item_field_origin, &def_to_string(origin));
|
||||
rbml_w.wr_tagged_u64(tag_item_field_origin, def_to_u64(origin));
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
}
|
||||
|
|
@ -358,8 +362,8 @@ fn encode_reexported_static_method(rbml_w: &mut Encoder,
|
|||
debug!("(encode reexported static method) {}::{}",
|
||||
exp.name, token::get_name(method_name));
|
||||
rbml_w.start_tag(tag_items_data_item_reexport);
|
||||
rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id,
|
||||
&def_to_string(method_def_id));
|
||||
rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
|
||||
def_to_u64(method_def_id));
|
||||
rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
|
||||
&format!("{}::{}", exp.name,
|
||||
token::get_name(method_name)));
|
||||
|
|
@ -495,8 +499,8 @@ fn encode_reexports(ecx: &EncodeContext,
|
|||
exp.def_id.node,
|
||||
id);
|
||||
rbml_w.start_tag(tag_items_data_item_reexport);
|
||||
rbml_w.wr_tagged_str(tag_items_data_item_reexport_def_id,
|
||||
&def_to_string(exp.def_id));
|
||||
rbml_w.wr_tagged_u64(tag_items_data_item_reexport_def_id,
|
||||
def_to_u64(exp.def_id));
|
||||
rbml_w.wr_tagged_str(tag_items_data_item_reexport_name,
|
||||
exp.name.as_str());
|
||||
rbml_w.end_tag();
|
||||
|
|
@ -526,12 +530,12 @@ fn encode_info_for_mod(ecx: &EncodeContext,
|
|||
|
||||
// Encode info about all the module children.
|
||||
for item in &md.items {
|
||||
rbml_w.wr_tagged_str(tag_mod_child,
|
||||
&def_to_string(local_def(item.id)));
|
||||
rbml_w.wr_tagged_u64(tag_mod_child,
|
||||
def_to_u64(local_def(item.id)));
|
||||
|
||||
each_auxiliary_node_id(&**item, |auxiliary_node_id| {
|
||||
rbml_w.wr_tagged_str(tag_mod_child,
|
||||
&def_to_string(local_def(auxiliary_node_id)));
|
||||
rbml_w.wr_tagged_u64(tag_mod_child,
|
||||
def_to_u64(local_def(auxiliary_node_id)));
|
||||
true
|
||||
});
|
||||
|
||||
|
|
@ -541,8 +545,7 @@ fn encode_info_for_mod(ecx: &EncodeContext,
|
|||
token::get_ident(ident),
|
||||
did, ecx.tcx.map.node_to_string(did));
|
||||
|
||||
rbml_w.wr_tagged_str(tag_mod_impl,
|
||||
&def_to_string(local_def(did)));
|
||||
rbml_w.wr_tagged_u64(tag_mod_impl, def_to_u64(local_def(did)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -619,8 +622,7 @@ fn encode_parent_sort(rbml_w: &mut Encoder, sort: char) {
|
|||
fn encode_provided_source(rbml_w: &mut Encoder,
|
||||
source_opt: Option<DefId>) {
|
||||
if let Some(source) = source_opt {
|
||||
rbml_w.wr_tagged_str(tag_item_method_provided_source,
|
||||
&def_to_string(source));
|
||||
rbml_w.wr_tagged_u64(tag_item_method_provided_source, def_to_u64(source));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -725,8 +727,8 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
|
|||
encode_name(rbml_w, param.name);
|
||||
rbml_w.end_tag();
|
||||
|
||||
rbml_w.wr_tagged_str(tag_region_param_def_def_id,
|
||||
&def_to_string(param.def_id));
|
||||
rbml_w.wr_tagged_u64(tag_region_param_def_def_id,
|
||||
def_to_u64(param.def_id));
|
||||
|
||||
rbml_w.wr_tagged_u64(tag_region_param_def_space,
|
||||
param.space.to_uint() as u64);
|
||||
|
|
@ -1089,8 +1091,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
|
||||
// Encode all the items in this module.
|
||||
for foreign_item in &fm.items {
|
||||
rbml_w.wr_tagged_str(tag_mod_child,
|
||||
&def_to_string(local_def(foreign_item.id)));
|
||||
rbml_w.wr_tagged_u64(tag_mod_child,
|
||||
def_to_u64(local_def(foreign_item.id)));
|
||||
}
|
||||
encode_visibility(rbml_w, vis);
|
||||
encode_stability(rbml_w, stab);
|
||||
|
|
@ -1335,8 +1337,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
}
|
||||
rbml_w.end_tag();
|
||||
|
||||
rbml_w.wr_tagged_str(tag_mod_child,
|
||||
&def_to_string(method_def_id.def_id()));
|
||||
rbml_w.wr_tagged_u64(tag_mod_child,
|
||||
def_to_u64(method_def_id.def_id()));
|
||||
}
|
||||
encode_path(rbml_w, path.clone());
|
||||
|
||||
|
|
@ -1893,6 +1895,7 @@ impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for ImplVisitor<'a, 'b, 'c, 'tcx> {
|
|||
def_id.krate != ast::LOCAL_CRATE {
|
||||
self.rbml_w.start_tag(tag_impls_impl);
|
||||
encode_def_id(self.rbml_w, local_def(item.id));
|
||||
self.rbml_w.wr_tagged_u64(tag_impls_impl_trait_def_id, def_to_u64(def_id));
|
||||
self.rbml_w.end_tag();
|
||||
}
|
||||
}
|
||||
|
|
@ -1932,12 +1935,12 @@ fn encode_misc_info(ecx: &EncodeContext,
|
|||
rbml_w.start_tag(tag_misc_info);
|
||||
rbml_w.start_tag(tag_misc_info_crate_items);
|
||||
for item in &krate.module.items {
|
||||
rbml_w.wr_tagged_str(tag_mod_child,
|
||||
&def_to_string(local_def(item.id)));
|
||||
rbml_w.wr_tagged_u64(tag_mod_child,
|
||||
def_to_u64(local_def(item.id)));
|
||||
|
||||
each_auxiliary_node_id(&**item, |auxiliary_node_id| {
|
||||
rbml_w.wr_tagged_str(tag_mod_child,
|
||||
&def_to_string(local_def(auxiliary_node_id)));
|
||||
rbml_w.wr_tagged_u64(tag_mod_child,
|
||||
def_to_u64(local_def(auxiliary_node_id)));
|
||||
true
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1125,7 +1125,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
// that case we can adjust the length of the
|
||||
// original vec accordingly, but we'd have to
|
||||
// make trans do the right thing, and it would
|
||||
// only work for `~` vectors. It seems simpler
|
||||
// only work for `Box<[T]>`s. It seems simpler
|
||||
// to just require that people call
|
||||
// `vec.pop()` or `vec.unshift()`.
|
||||
let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
def_id.krate == ast::LOCAL_CRATE
|
||||
}
|
||||
|
||||
ty::ty_uniq(_) => { // treat ~T like Box<T>
|
||||
ty::ty_uniq(_) => { // Box<T>
|
||||
let krate = tcx.lang_items.owned_box().map(|d| d.krate);
|
||||
krate == Some(ast::LOCAL_CRATE)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,23 +117,71 @@ pub enum MethodMatchedData {
|
|||
/// obligation is for `int`. In that case, we drop the impl out of the
|
||||
/// list. But the other cases are considered *candidates*.
|
||||
///
|
||||
/// Candidates can either be definitive or ambiguous. An ambiguous
|
||||
/// candidate is one that might match or might not, depending on how
|
||||
/// type variables wind up being resolved. This only occurs during inference.
|
||||
/// For selection to succeed, there must be exactly one matching
|
||||
/// candidate. If the obligation is fully known, this is guaranteed
|
||||
/// by coherence. However, if the obligation contains type parameters
|
||||
/// or variables, there may be multiple such impls.
|
||||
///
|
||||
/// For selection to succeed, there must be exactly one non-ambiguous
|
||||
/// candidate. Usually, it is not possible to have more than one
|
||||
/// definitive candidate, due to the coherence rules. However, there is
|
||||
/// one case where it could occur: if there is a blanket impl for a
|
||||
/// trait (that is, an impl applied to all T), and a type parameter
|
||||
/// with a where clause. In that case, we can have a candidate from the
|
||||
/// where clause and a second candidate from the impl. This is not a
|
||||
/// problem because coherence guarantees us that the impl which would
|
||||
/// be used to satisfy the where clause is the same one that we see
|
||||
/// now. To resolve this issue, therefore, we ignore impls if we find a
|
||||
/// matching where clause. Part of the reason for this is that where
|
||||
/// clauses can give additional information (like, the types of output
|
||||
/// parameters) that would have to be inferred from the impl.
|
||||
/// It is not a real problem if multiple matching impls exist because
|
||||
/// of type variables - it just means the obligation isn't sufficiently
|
||||
/// elaborated. In that case we report an ambiguity, and the caller can
|
||||
/// try again after more type information has been gathered or report a
|
||||
/// "type annotations required" error.
|
||||
///
|
||||
/// However, with type parameters, this can be a real problem - type
|
||||
/// parameters don't unify with regular types, but they *can* unify
|
||||
/// with variables from blanket impls, and (unless we know its bounds
|
||||
/// will always be satisfied) picking the blanket impl will be wrong
|
||||
/// for at least *some* substitutions. To make this concrete, if we have
|
||||
///
|
||||
/// trait AsDebug { type Out : fmt::Debug; fn debug(self) -> Self::Out; }
|
||||
/// impl<T: fmt::Debug> AsDebug for T {
|
||||
/// type Out = T;
|
||||
/// fn debug(self) -> fmt::Debug { self }
|
||||
/// }
|
||||
/// fn foo<T: AsDebug>(t: T) { println!("{:?}", <T as AsDebug>::debug(t)); }
|
||||
///
|
||||
/// we can't just use the impl to resolve the <T as AsDebug> obligation
|
||||
/// - a type from another crate (that doesn't implement fmt::Debug) could
|
||||
/// implement AsDebug.
|
||||
///
|
||||
/// Because where-clauses match the type exactly, multiple clauses can
|
||||
/// only match if there are unresolved variables, and we can mostly just
|
||||
/// report this ambiguity in that case. This is still a problem - we can't
|
||||
/// *do anything* with ambiguities that involve only regions. This is issue
|
||||
/// #21974.
|
||||
///
|
||||
/// If a single where-clause matches and there are no inference
|
||||
/// variables left, then it definitely matches and we can just select
|
||||
/// it.
|
||||
///
|
||||
/// In fact, we even select the where-clause when the obligation contains
|
||||
/// inference variables. The can lead to inference making "leaps of logic",
|
||||
/// for example in this situation:
|
||||
///
|
||||
/// pub trait Foo<T> { fn foo(&self) -> T; }
|
||||
/// impl<T> Foo<()> for T { fn foo(&self) { } }
|
||||
/// impl Foo<bool> for bool { fn foo(&self) -> bool { *self } }
|
||||
///
|
||||
/// pub fn foo<T>(t: T) where T: Foo<bool> {
|
||||
/// println!("{:?}", <T as Foo<_>>::foo(&t));
|
||||
/// }
|
||||
/// fn main() { foo(false); }
|
||||
///
|
||||
/// Here the obligation <T as Foo<$0>> can be matched by both the blanket
|
||||
/// impl and the where-clause. We select the where-clause and unify $0=bool,
|
||||
/// so the program prints "false". However, if the where-clause is omitted,
|
||||
/// the blanket impl is selected, we unify $0=(), and the program prints
|
||||
/// "()".
|
||||
///
|
||||
/// Exactly the same issues apply to projection and object candidates, except
|
||||
/// that we can have both a projection candidate and a where-clause candidate
|
||||
/// for the same obligation. In that case either would do (except that
|
||||
/// different "leaps of logic" would occur if inference variables are
|
||||
/// present), and we just pick the projection. This is, for example,
|
||||
/// required for associated types to work in default impls, as the bounds
|
||||
/// are visible both as projection bounds and as where-clauses from the
|
||||
/// parameter environment.
|
||||
#[derive(PartialEq,Eq,Debug,Clone)]
|
||||
enum SelectionCandidate<'tcx> {
|
||||
PhantomFnCandidate,
|
||||
|
|
@ -1350,63 +1398,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// Returns true if `candidate_i` should be dropped in favor of
|
||||
/// `candidate_j`. Generally speaking we will drop duplicate
|
||||
/// candidates and prefer where-clause candidates.
|
||||
/// Returns true if `victim` should be dropped in favor of
|
||||
/// `other`. Generally speaking we will drop duplicate
|
||||
/// candidates and prefer where-clause candidates.
|
||||
///
|
||||
/// See the comment for "SelectionCandidate" for more details.
|
||||
fn candidate_should_be_dropped_in_favor_of<'o>(&mut self,
|
||||
candidate_i: &SelectionCandidate<'tcx>,
|
||||
candidate_j: &SelectionCandidate<'tcx>)
|
||||
victim: &SelectionCandidate<'tcx>,
|
||||
other: &SelectionCandidate<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
if candidate_i == candidate_j {
|
||||
if victim == other {
|
||||
return true;
|
||||
}
|
||||
|
||||
match (candidate_i, candidate_j) {
|
||||
(&ImplCandidate(..), &ParamCandidate(..)) |
|
||||
(&ClosureCandidate(..), &ParamCandidate(..)) |
|
||||
(&FnPointerCandidate(..), &ParamCandidate(..)) |
|
||||
(&BuiltinObjectCandidate(..), &ParamCandidate(_)) |
|
||||
(&BuiltinCandidate(..), &ParamCandidate(..)) => {
|
||||
// We basically prefer always prefer to use a
|
||||
// where-clause over another option. Where clauses
|
||||
// impose the burden of finding the exact match onto
|
||||
// the caller. Using an impl in preference of a where
|
||||
// clause can also lead us to "overspecialize", as in
|
||||
// #18453.
|
||||
true
|
||||
}
|
||||
(&ImplCandidate(..), &ObjectCandidate(..)) => {
|
||||
// This means that we are matching an object of type
|
||||
// `Trait` against the trait `Trait`. In that case, we
|
||||
// always prefer to use the object vtable over the
|
||||
// impl. Like a where clause, the impl may or may not
|
||||
// be the one that is used by the object (because the
|
||||
// impl may have additional where-clauses that the
|
||||
// object's source might not meet) -- if it is, using
|
||||
// the vtable is fine. If it is not, using the vtable
|
||||
// is good. A win win!
|
||||
true
|
||||
}
|
||||
(&DefaultImplCandidate(_), _) => {
|
||||
// Prefer other candidates over default implementations.
|
||||
self.tcx().sess.bug(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates");
|
||||
}
|
||||
(&ProjectionCandidate, &ParamCandidate(_)) => {
|
||||
// FIXME(#20297) -- this gives where clauses precedent
|
||||
// over projections. Really these are just two means
|
||||
// of deducing information (one based on the where
|
||||
// clauses on the trait definition; one based on those
|
||||
// on the enclosing scope), and it'd be better to
|
||||
// integrate them more intelligently. But for now this
|
||||
// seems ok. If we DON'T give where clauses
|
||||
// precedence, we run into trouble in default methods,
|
||||
// where both the projection bounds for `Self::A` and
|
||||
// the where clauses are in scope.
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
false
|
||||
}
|
||||
match other {
|
||||
&ObjectCandidate(..) |
|
||||
&ParamCandidate(_) | &ProjectionCandidate => match victim {
|
||||
&DefaultImplCandidate(..) => {
|
||||
self.tcx().sess.bug(
|
||||
"default implementations shouldn't be recorded \
|
||||
when there are other valid candidates");
|
||||
}
|
||||
&PhantomFnCandidate => {
|
||||
self.tcx().sess.bug("PhantomFn didn't short-circuit selection");
|
||||
}
|
||||
&ImplCandidate(..) |
|
||||
&ClosureCandidate(..) |
|
||||
&FnPointerCandidate(..) |
|
||||
&BuiltinObjectCandidate(..) |
|
||||
&DefaultImplObjectCandidate(..) |
|
||||
&BuiltinCandidate(..) => {
|
||||
// We have a where-clause so don't go around looking
|
||||
// for impls.
|
||||
true
|
||||
}
|
||||
&ObjectCandidate(..) |
|
||||
&ProjectionCandidate => {
|
||||
// Arbitrarily give param candidates priority
|
||||
// over projection and object candidates.
|
||||
true
|
||||
},
|
||||
&ParamCandidate(..) => false,
|
||||
&ErrorCandidate => false // propagate errors
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2441,10 +2477,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
/// `match_impl()`. For example, if `impl_def_id` is declared
|
||||
/// as:
|
||||
///
|
||||
/// impl<T:Copy> Foo for ~T { ... }
|
||||
/// impl<T:Copy> Foo for Box<T> { ... }
|
||||
///
|
||||
/// and `obligation_self_ty` is `int`, we'd back an `Err(_)`
|
||||
/// result. But if `obligation_self_ty` were `~int`, we'd get
|
||||
/// and `obligation_self_ty` is `int`, we'd get back an `Err(_)`
|
||||
/// result. But if `obligation_self_ty` were `Box<int>`, we'd get
|
||||
/// back `Ok(T=int)`.
|
||||
fn match_inherent_impl(&mut self,
|
||||
impl_def_id: ast::DefId,
|
||||
|
|
|
|||
|
|
@ -2564,9 +2564,11 @@ impl<'tcx> TraitDef<'tcx> {
|
|||
tcx: &ctxt<'tcx>,
|
||||
impl_def_id: DefId,
|
||||
impl_trait_ref: TraitRef<'tcx>) {
|
||||
debug!("TraitDef::record_impl for {}, from {}",
|
||||
self.repr(tcx), impl_trait_ref.repr(tcx));
|
||||
|
||||
// We don't want to borrow_mut after we already populated all impls,
|
||||
// so check if an impl is present with an immutable borrow first.
|
||||
|
||||
if let Some(sty) = fast_reject::simplify_type(tcx,
|
||||
impl_trait_ref.self_ty(), false) {
|
||||
if let Some(is) = self.nonblanket_impls.borrow().get(&sty) {
|
||||
|
|
@ -6336,10 +6338,10 @@ pub fn populate_implementations_for_primitive_if_necessary(tcx: &ctxt,
|
|||
tcx.populated_external_primitive_impls.borrow_mut().insert(primitive_def_id);
|
||||
}
|
||||
|
||||
/// Populates the type context with all the implementations for the given type
|
||||
/// if necessary.
|
||||
pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
|
||||
type_id: ast::DefId) {
|
||||
/// Populates the type context with all the inherent implementations for
|
||||
/// the given type if necessary.
|
||||
pub fn populate_inherent_implementations_for_type_if_necessary(tcx: &ctxt,
|
||||
type_id: ast::DefId) {
|
||||
if type_id.krate == LOCAL_CRATE {
|
||||
return
|
||||
}
|
||||
|
|
@ -6348,37 +6350,15 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
|
|||
return
|
||||
}
|
||||
|
||||
debug!("populate_implementations_for_type_if_necessary: searching for {:?}", type_id);
|
||||
debug!("populate_inherent_implementations_for_type_if_necessary: searching for {:?}", type_id);
|
||||
|
||||
let mut inherent_impls = Vec::new();
|
||||
csearch::each_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| {
|
||||
let impl_items = csearch::get_impl_items(&tcx.sess.cstore, impl_def_id);
|
||||
|
||||
// Record the implementation, if needed
|
||||
if let Some(trait_ref) = csearch::get_impl_trait(tcx, impl_def_id) {
|
||||
let trait_def = lookup_trait_def(tcx, trait_ref.def_id);
|
||||
trait_def.record_impl(tcx, impl_def_id, trait_ref);
|
||||
} else {
|
||||
inherent_impls.push(impl_def_id);
|
||||
}
|
||||
|
||||
// For any methods that use a default implementation, add them to
|
||||
// the map. This is a bit unfortunate.
|
||||
for impl_item_def_id in &impl_items {
|
||||
let method_def_id = impl_item_def_id.def_id();
|
||||
match impl_or_trait_item(tcx, method_def_id) {
|
||||
MethodTraitItem(method) => {
|
||||
if let Some(source) = method.provided_source {
|
||||
tcx.provided_method_sources
|
||||
.borrow_mut()
|
||||
.insert(method_def_id, source);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
csearch::each_inherent_implementation_for_type(&tcx.sess.cstore, type_id, |impl_def_id| {
|
||||
// Record the implementation.
|
||||
inherent_impls.push(impl_def_id);
|
||||
|
||||
// Store the implementation info.
|
||||
let impl_items = csearch::get_impl_items(&tcx.sess.cstore, impl_def_id);
|
||||
tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items);
|
||||
});
|
||||
|
||||
|
|
@ -6388,18 +6368,18 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
|
|||
|
||||
/// Populates the type context with all the implementations for the given
|
||||
/// trait if necessary.
|
||||
pub fn populate_implementations_for_trait_if_necessary(
|
||||
tcx: &ctxt,
|
||||
trait_id: ast::DefId) {
|
||||
pub fn populate_implementations_for_trait_if_necessary(tcx: &ctxt, trait_id: ast::DefId) {
|
||||
if trait_id.krate == LOCAL_CRATE {
|
||||
return
|
||||
}
|
||||
|
||||
let def = lookup_trait_def(tcx, trait_id);
|
||||
if def.flags.get().intersects(TraitFlags::IMPLS_VALID) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
debug!("populate_implementations_for_trait_if_necessary: searching for {}", def.repr(tcx));
|
||||
|
||||
if csearch::is_defaulted_trait(&tcx.sess.cstore, trait_id) {
|
||||
record_trait_has_default_impl(tcx, trait_id);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -637,7 +637,7 @@ impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for OwnedSlice<T> {
|
|||
}
|
||||
}
|
||||
|
||||
// This is necessary to handle types like Option<~[T]>, for which
|
||||
// This is necessary to handle types like Option<Vec<T>>, for which
|
||||
// autoderef cannot convert the &[T] handler
|
||||
impl<'tcx, T:Repr<'tcx>> Repr<'tcx> for Vec<T> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
|
|
|
|||
|
|
@ -732,7 +732,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
|
|||
/// let p: Point;
|
||||
/// p.x = 22; // ok, even though `p` is uninitialized
|
||||
///
|
||||
/// let p: ~Point;
|
||||
/// let p: Box<Point>;
|
||||
/// (*p).x = 22; // not ok, p is uninitialized, can't deref
|
||||
/// ```
|
||||
fn check_if_assigned_path_is_moved(&self,
|
||||
|
|
|
|||
|
|
@ -1314,7 +1314,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||
// `impl [... for] Private` is never visible.
|
||||
let self_contains_private;
|
||||
// impl [... for] Public<...>, but not `impl [... for]
|
||||
// ~[Public]` or `(Public,)` etc.
|
||||
// Vec<Public>` or `(Public,)` etc.
|
||||
let self_is_public_path;
|
||||
|
||||
// check the properties of the Self type:
|
||||
|
|
|
|||
|
|
@ -10,8 +10,111 @@
|
|||
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
// Error messages for EXXXX errors.
|
||||
// Each message should start and end with a new line, and be wrapped to 80 characters.
|
||||
// In vim you can `:set tw=80` and use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
|
||||
register_long_diagnostics! {
|
||||
|
||||
E0154: r##"
|
||||
Imports (`use` statements) are not allowed after non-item statements, such as
|
||||
variable declarations and expression statements.
|
||||
|
||||
Here is an example that demonstrates the error:
|
||||
```
|
||||
fn f() {
|
||||
// Variable declaration before import
|
||||
let x = 0;
|
||||
use std::io::Read;
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The solution is to declare the imports at the top of the block, function, or
|
||||
file.
|
||||
|
||||
Here is the previous example again, with the correct order:
|
||||
```
|
||||
fn f() {
|
||||
use std::io::Read;
|
||||
let x = 0;
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
See the Declaration Statements section of the reference for more information
|
||||
about what constitutes an Item declaration and what does not:
|
||||
|
||||
http://doc.rust-lang.org/reference.html#statements
|
||||
"##,
|
||||
|
||||
E0259: r##"
|
||||
The name chosen for an external crate conflicts with another external crate that
|
||||
has been imported into the current module.
|
||||
|
||||
Wrong example:
|
||||
```
|
||||
extern crate a;
|
||||
extern crate crate_a as a;
|
||||
```
|
||||
|
||||
The solution is to choose a different name that doesn't conflict with any
|
||||
external crate imported into the current module.
|
||||
|
||||
Correct example:
|
||||
```
|
||||
extern crate a;
|
||||
extern crate crate_a as other_name;
|
||||
```
|
||||
"##,
|
||||
|
||||
E0260: r##"
|
||||
The name for an item declaration conflicts with an external crate's name.
|
||||
|
||||
For instance,
|
||||
```
|
||||
extern crate abc;
|
||||
|
||||
struct abc;
|
||||
```
|
||||
|
||||
There are two possible solutions:
|
||||
|
||||
Solution #1: Rename the item.
|
||||
|
||||
```
|
||||
extern crate abc;
|
||||
|
||||
struct xyz;
|
||||
```
|
||||
|
||||
Solution #2: Import the crate with a different name.
|
||||
|
||||
```
|
||||
extern crate abc as xyz;
|
||||
|
||||
struct abc;
|
||||
```
|
||||
|
||||
See the Declaration Statements section of the reference for more information
|
||||
about what constitutes an Item declaration and what does not:
|
||||
|
||||
http://doc.rust-lang.org/reference.html#statements
|
||||
"##,
|
||||
|
||||
E0317: r##"
|
||||
User-defined types or type parameters cannot shadow the primitive types.
|
||||
This error indicates you tried to define a type, struct or enum with the same
|
||||
name as an existing primitive type.
|
||||
|
||||
See the Types section of the reference for more information about the primitive
|
||||
types:
|
||||
|
||||
http://doc.rust-lang.org/reference.html#types
|
||||
"##
|
||||
|
||||
}
|
||||
|
||||
register_diagnostics! {
|
||||
E0154,
|
||||
E0157,
|
||||
E0153,
|
||||
E0251, // a named type or value has already been imported in this module
|
||||
|
|
@ -22,9 +125,6 @@ register_diagnostics! {
|
|||
E0256, // import conflicts with type in this module
|
||||
E0257, // inherent implementations are only allowed on types defined in the current module
|
||||
E0258, // import conflicts with existing submodule
|
||||
E0259, // an extern crate has already been imported into this module
|
||||
E0260, // name conflicts with an external crate that has been imported into this module
|
||||
E0317, // user-defined types or type parameters cannot shadow the primitive types
|
||||
E0364, // item is private
|
||||
E0365 // item is private
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2688,18 +2688,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
check_ribs: bool)
|
||||
-> AssocItemResolveResult
|
||||
{
|
||||
let max_assoc_types;
|
||||
|
||||
match maybe_qself {
|
||||
Some(&ast::QSelf { position: 0, .. }) =>
|
||||
return TypecheckRequired,
|
||||
_ => {}
|
||||
Some(qself) => {
|
||||
if qself.position == 0 {
|
||||
return TypecheckRequired;
|
||||
}
|
||||
max_assoc_types = path.segments.len() - qself.position;
|
||||
// Make sure the trait is valid.
|
||||
let _ = self.resolve_trait_reference(id, path, max_assoc_types);
|
||||
}
|
||||
None => {
|
||||
max_assoc_types = path.segments.len();
|
||||
}
|
||||
}
|
||||
let max_assoc_types = if let Some(qself) = maybe_qself {
|
||||
// Make sure the trait is valid.
|
||||
let _ = self.resolve_trait_reference(id, path, 1);
|
||||
path.segments.len() - qself.position
|
||||
} else {
|
||||
path.segments.len()
|
||||
};
|
||||
|
||||
let mut resolution = self.with_no_errors(|this| {
|
||||
this.resolve_path(id, path, 0, namespace, check_ribs)
|
||||
|
|
|
|||
|
|
@ -618,7 +618,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
namespace_name,
|
||||
name_bindings.def_for_namespace(namespace));
|
||||
self.check_for_conflicting_import(
|
||||
&import_resolution.target_for_namespace(namespace),
|
||||
&import_resolution,
|
||||
directive.span,
|
||||
target,
|
||||
namespace);
|
||||
|
|
@ -755,7 +755,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
// Continue.
|
||||
}
|
||||
Some(ref value_target) => {
|
||||
self.check_for_conflicting_import(&dest_import_resolution.value_target,
|
||||
self.check_for_conflicting_import(&dest_import_resolution,
|
||||
import_directive.span,
|
||||
*ident,
|
||||
ValueNS);
|
||||
|
|
@ -767,7 +767,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
// Continue.
|
||||
}
|
||||
Some(ref type_target) => {
|
||||
self.check_for_conflicting_import(&dest_import_resolution.type_target,
|
||||
self.check_for_conflicting_import(&dest_import_resolution,
|
||||
import_directive.span,
|
||||
*ident,
|
||||
TypeNS);
|
||||
|
|
@ -887,24 +887,31 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> {
|
|||
|
||||
/// Checks that imported names and items don't have the same name.
|
||||
fn check_for_conflicting_import(&mut self,
|
||||
target: &Option<Target>,
|
||||
import_resolution: &ImportResolution,
|
||||
import_span: Span,
|
||||
name: Name,
|
||||
namespace: Namespace) {
|
||||
let target = import_resolution.target_for_namespace(namespace);
|
||||
debug!("check_for_conflicting_import: {}; target exists: {}",
|
||||
&token::get_name(name),
|
||||
target.is_some());
|
||||
|
||||
match *target {
|
||||
match target {
|
||||
Some(ref target) if target.shadowable != Shadowable::Always => {
|
||||
let msg = format!("a {} named `{}` has already been imported \
|
||||
in this module",
|
||||
match namespace {
|
||||
TypeNS => "type",
|
||||
ValueNS => "value",
|
||||
},
|
||||
let ns_word = match namespace {
|
||||
TypeNS => "type",
|
||||
ValueNS => "value",
|
||||
};
|
||||
span_err!(self.resolver.session, import_span, E0252,
|
||||
"a {} named `{}` has already been imported \
|
||||
in this module", ns_word,
|
||||
&token::get_name(name));
|
||||
span_err!(self.resolver.session, import_span, E0252, "{}", &msg[..]);
|
||||
let use_id = import_resolution.id(namespace);
|
||||
let item = self.resolver.ast_map.expect_item(use_id);
|
||||
// item is syntax::ast::Item;
|
||||
span_note!(self.resolver.session, item.span,
|
||||
"previous import of `{}` here",
|
||||
token::get_name(name));
|
||||
}
|
||||
Some(_) | None => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -289,7 +289,7 @@ pub fn mangle<PI: Iterator<Item=PathElem>>(path: PI,
|
|||
// when using unix's linker. Perhaps one day when we just use a linker from LLVM
|
||||
// we won't need to do this name mangling. The problem with name mangling is
|
||||
// that it seriously limits the available characters. For example we can't
|
||||
// have things like &T or ~[T] in symbol names when one would theoretically
|
||||
// have things like &T in symbol names when one would theoretically
|
||||
// want them for things like impls of traits on that type.
|
||||
//
|
||||
// To be able to work on all platforms and get *some* reasonable output, we
|
||||
|
|
|
|||
|
|
@ -230,8 +230,8 @@ impl<'a> SpanUtils<'a> {
|
|||
// Reparse span and return an owned vector of sub spans of the first limit
|
||||
// identifier tokens in the given nesting level.
|
||||
// example with Foo<Bar<T,V>, Bar<T,V>>
|
||||
// Nesting = 0: all idents outside of brackets: ~[Foo]
|
||||
// Nesting = 1: idents within one level of brackets: ~[Bar, Bar]
|
||||
// Nesting = 0: all idents outside of brackets: Vec<Foo>
|
||||
// Nesting = 1: idents within one level of brackets: Vec<Bar, Bar>
|
||||
pub fn spans_with_brackets(&self, span: Span, nesting: isize, limit: isize) -> Vec<Span> {
|
||||
let mut result: Vec<Span> = vec!();
|
||||
|
||||
|
|
@ -352,7 +352,7 @@ impl<'a> SpanUtils<'a> {
|
|||
return vec!();
|
||||
}
|
||||
// Type params are nested within one level of brackets:
|
||||
// i.e. we want ~[A, B] from Foo<A, B<T,U>>
|
||||
// i.e. we want Vec<A, B> from Foo<A, B<T,U>>
|
||||
self.spans_with_brackets(span, 1, number)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
|
|||
// The `noalias` attribute on the return value is useful to a
|
||||
// function ptr caller.
|
||||
match ret_ty.sty {
|
||||
// `~` pointer return values never alias because ownership
|
||||
// `Box` pointer return values never alias because ownership
|
||||
// is transferred
|
||||
ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => {
|
||||
attrs.ret(llvm::Attribute::NoAlias);
|
||||
|
|
@ -239,7 +239,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
|
|||
attrs.arg(idx, llvm::Attribute::ZExt);
|
||||
}
|
||||
|
||||
// `~` pointer parameters never alias because ownership is transferred
|
||||
// `Box` pointer parameters never alias because ownership is transferred
|
||||
ty::ty_uniq(inner) => {
|
||||
let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner));
|
||||
|
||||
|
|
|
|||
|
|
@ -142,26 +142,24 @@ 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:),* <,_...>| -> \
|
||||
// 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 (box) -> {box :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:)* <,_...> ) -> \
|
||||
// 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,
|
||||
|
|
@ -202,7 +200,7 @@ impl<'tcx> TypeMap<'tcx> {
|
|||
}
|
||||
},
|
||||
ty::ty_uniq(inner_type) => {
|
||||
unique_type_id.push('~');
|
||||
unique_type_id.push_str("box ");
|
||||
let inner_type_id = self.get_unique_type_id_of_type(cx, inner_type);
|
||||
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
|
||||
unique_type_id.push_str(&inner_type_id[..]);
|
||||
|
|
|
|||
|
|
@ -1603,7 +1603,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>,
|
|||
Some(i as usize)),
|
||||
_ => {
|
||||
span_err!(tcx.sess, ast_ty.span, E0249,
|
||||
"expected constant expr for array length");
|
||||
"expected constant integer expression \
|
||||
for array length");
|
||||
this.tcx().types.err
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -371,7 +371,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: ast::DefId) {
|
||||
// Read the inherent implementation candidates for this type from the
|
||||
// metadata if necessary.
|
||||
ty::populate_implementations_for_type_if_necessary(self.tcx(), def_id);
|
||||
ty::populate_inherent_implementations_for_type_if_necessary(self.tcx(), def_id);
|
||||
|
||||
if let Some(impl_infos) = self.tcx().inherent_impls.borrow().get(&def_id) {
|
||||
for &impl_def_id in &***impl_infos {
|
||||
|
|
|
|||
|
|
@ -2458,7 +2458,7 @@ fn check_expr_with_lvalue_pref<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>, expr: &'tcx ast::
|
|||
}
|
||||
|
||||
// determine the `self` type, using fresh variables for all variables
|
||||
// declared on the impl declaration e.g., `impl<A,B> for ~[(A,B)]`
|
||||
// declared on the impl declaration e.g., `impl<A,B> for Vec<(A,B)>`
|
||||
// would return ($0, $1) where $0 and $1 are freshly instantiated type
|
||||
// variables.
|
||||
pub fn impl_self_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
|
|
|||
|
|
@ -16,13 +16,10 @@
|
|||
// mappings. That mapping code resides here.
|
||||
|
||||
|
||||
use metadata::csearch::{each_impl, get_impl_trait};
|
||||
use metadata::csearch;
|
||||
use middle::subst::{self, Subst};
|
||||
use middle::ty::RegionEscape;
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
|
||||
use middle::ty::{MethodTraitItemId, TypeTraitItemId};
|
||||
use middle::ty::{ParameterEnvironment, lookup_item_type};
|
||||
use middle::ty::{MethodTraitItemId, TypeTraitItemId, ParameterEnvironment};
|
||||
use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err};
|
||||
use middle::ty::{ty_param, TypeScheme, ty_ptr};
|
||||
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
|
||||
|
|
@ -33,7 +30,6 @@ use middle::ty;
|
|||
use CrateCtxt;
|
||||
use middle::infer::InferCtxt;
|
||||
use middle::infer::new_infer_ctxt;
|
||||
use std::collections::HashSet;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::{Crate, DefId};
|
||||
|
|
@ -130,11 +126,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
Rc::new((*v.borrow()).clone()));
|
||||
}
|
||||
|
||||
// Bring in external crates. It's fine for this to happen after the
|
||||
// coherence checks, because we ensure by construction that no errors
|
||||
// can happen at link time.
|
||||
self.add_external_crates();
|
||||
|
||||
// Populate the table of destructors. It might seem a bit strange to
|
||||
// do this here, but it's actually the most convenient place, since
|
||||
// the coherence tables contain the trait -> type mappings.
|
||||
|
|
@ -267,11 +258,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
trait_def.record_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
|
||||
}
|
||||
|
||||
fn get_self_type_for_implementation(&self, impl_did: DefId)
|
||||
-> TypeScheme<'tcx> {
|
||||
self.crate_context.tcx.tcache.borrow().get(&impl_did).unwrap().clone()
|
||||
}
|
||||
|
||||
// Converts an implementation in the AST to a vector of items.
|
||||
fn create_impl_from_item(&self, item: &Item) -> Vec<ImplOrTraitItemId> {
|
||||
match item.node {
|
||||
|
|
@ -313,66 +299,6 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// External crate handling
|
||||
|
||||
fn add_external_impl(&self,
|
||||
impls_seen: &mut HashSet<DefId>,
|
||||
impl_def_id: DefId) {
|
||||
let tcx = self.crate_context.tcx;
|
||||
let impl_items = csearch::get_impl_items(&tcx.sess.cstore,
|
||||
impl_def_id);
|
||||
|
||||
// Make sure we don't visit the same implementation multiple times.
|
||||
if !impls_seen.insert(impl_def_id) {
|
||||
// Skip this one.
|
||||
return
|
||||
}
|
||||
// Good. Continue.
|
||||
|
||||
let _ = lookup_item_type(tcx, impl_def_id);
|
||||
let associated_traits = get_impl_trait(tcx, impl_def_id);
|
||||
|
||||
// Do a sanity check.
|
||||
assert!(associated_traits.is_some());
|
||||
|
||||
// Record all the trait items.
|
||||
if let Some(trait_ref) = associated_traits {
|
||||
self.add_trait_impl(trait_ref, impl_def_id);
|
||||
}
|
||||
|
||||
// For any methods that use a default implementation, add them to
|
||||
// the map. This is a bit unfortunate.
|
||||
for item_def_id in &impl_items {
|
||||
let impl_item = ty::impl_or_trait_item(tcx, item_def_id.def_id());
|
||||
match impl_item {
|
||||
ty::MethodTraitItem(ref method) => {
|
||||
if let Some(source) = method.provided_source {
|
||||
tcx.provided_method_sources
|
||||
.borrow_mut()
|
||||
.insert(item_def_id.def_id(), source);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
tcx.impl_items.borrow_mut().insert(impl_def_id, impl_items);
|
||||
}
|
||||
|
||||
// Adds implementations and traits from external crates to the coherence
|
||||
// info.
|
||||
fn add_external_crates(&self) {
|
||||
let mut impls_seen = HashSet::new();
|
||||
|
||||
let crate_store = &self.crate_context.tcx.sess.cstore;
|
||||
crate_store.iter_crate_data(|crate_number, _crate_metadata| {
|
||||
each_impl(crate_store, crate_number, |def_id| {
|
||||
assert_eq!(crate_number, def_id.krate);
|
||||
self.add_external_impl(&mut impls_seen, def_id)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
// Destructors
|
||||
//
|
||||
|
|
@ -395,7 +321,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
}
|
||||
let method_def_id = items[0];
|
||||
|
||||
let self_type = self.get_self_type_for_implementation(impl_did);
|
||||
let self_type = ty::lookup_item_type(tcx, impl_did);
|
||||
match self_type.ty.sty {
|
||||
ty::ty_enum(type_def_id, _) |
|
||||
ty::ty_struct(type_def_id, _) |
|
||||
|
|
@ -451,7 +377,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
return
|
||||
}
|
||||
|
||||
let self_type = self.get_self_type_for_implementation(impl_did);
|
||||
let self_type = ty::lookup_item_type(tcx, impl_did);
|
||||
debug!("check_implementations_of_copy: self_type={} (bound)",
|
||||
self_type.repr(tcx));
|
||||
|
||||
|
|
|
|||
|
|
@ -48,14 +48,9 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
|
|||
// check_for_overlapping_impls_of_trait() check, since that
|
||||
// check can populate this table further with impls from other
|
||||
// crates.
|
||||
let trait_defs : Vec<&ty::TraitDef> = {
|
||||
let d = self.tcx.trait_defs.borrow();
|
||||
d.values().map(|&v|v).collect()
|
||||
};
|
||||
let trait_defs: Vec<_> = self.tcx.trait_defs.borrow().values().cloned().collect();
|
||||
|
||||
for trait_def in trait_defs {
|
||||
// FIXME -- it seems like this method actually pushes
|
||||
// duplicate impls onto the list
|
||||
ty::populate_implementations_for_trait_if_necessary(
|
||||
self.tcx,
|
||||
trait_def.trait_ref.def_id);
|
||||
|
|
|
|||
|
|
@ -46,6 +46,23 @@ enum variant, one of the fields was not provided. Each field should be specified
|
|||
exactly once.
|
||||
"##,
|
||||
|
||||
E0067: r##"
|
||||
The left-hand side of an assignment operator must be an lvalue expression. An
|
||||
lvalue expression represents a memory location and includes item paths (ie,
|
||||
namespaced variables), dereferences, indexing expressions, and field references.
|
||||
|
||||
```
|
||||
use std::collections::LinkedList;
|
||||
|
||||
// Good
|
||||
let mut list = LinkedList::new();
|
||||
|
||||
|
||||
// Bad: assignment to non-lvalue expression
|
||||
LinkedList::new() += 1;
|
||||
```
|
||||
"##,
|
||||
|
||||
E0081: r##"
|
||||
Enum discriminants are used to differentiate enum variants stored in memory.
|
||||
This error indicates that the same value was used for two or more variants,
|
||||
|
|
@ -119,6 +136,162 @@ construct an instance of the following type using only safe code:
|
|||
```
|
||||
enum Empty {}
|
||||
```
|
||||
"##,
|
||||
|
||||
E0131: r##"
|
||||
It is not possible to define `main` with type parameters, or even with function
|
||||
parameters. When `main` is present, it must take no arguments and return `()`.
|
||||
"##,
|
||||
|
||||
E0132: r##"
|
||||
It is not possible to declare type parameters on a function that has the `start`
|
||||
attribute. Such a function must have the following type signature:
|
||||
|
||||
```
|
||||
fn(isize, *const *const u8) -> isize
|
||||
```
|
||||
"##,
|
||||
|
||||
E0184: r##"
|
||||
Explicitly implementing both Drop and Copy for a type is currently disallowed.
|
||||
This feature can make some sense in theory, but the current implementation is
|
||||
incorrect and can lead to memory unsafety (see [issue #20126][iss20126]), so
|
||||
it has been disabled for now.
|
||||
|
||||
[iss20126]: https://github.com/rust-lang/rust/issues/20126
|
||||
"##,
|
||||
|
||||
E0204: r##"
|
||||
An attempt to implement the `Copy` trait for a struct failed because one of the
|
||||
fields does not implement `Copy`. To fix this, you must implement `Copy` for the
|
||||
mentioned field. Note that this may not be possible, as in the example of
|
||||
|
||||
```
|
||||
struct Foo {
|
||||
foo : Vec<u32>,
|
||||
}
|
||||
|
||||
impl Copy for Foo { }
|
||||
```
|
||||
|
||||
This fails because `Vec<T>` does not implement `Copy` for any `T`.
|
||||
|
||||
Here's another example that will fail:
|
||||
|
||||
```
|
||||
#[derive(Copy)]
|
||||
struct Foo<'a> {
|
||||
ty: &'a mut bool,
|
||||
}
|
||||
```
|
||||
|
||||
This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
|
||||
differs from the behavior for `&T`, which is always `Copy`).
|
||||
"##,
|
||||
|
||||
E0205: r##"
|
||||
An attempt to implement the `Copy` trait for an enum failed because one of the
|
||||
variants does not implement `Copy`. To fix this, you must implement `Copy` for
|
||||
the mentioned variant. Note that this may not be possible, as in the example of
|
||||
|
||||
```
|
||||
enum Foo {
|
||||
Bar(Vec<u32>),
|
||||
Baz,
|
||||
}
|
||||
|
||||
impl Copy for Foo { }
|
||||
```
|
||||
|
||||
This fails because `Vec<T>` does not implement `Copy` for any `T`.
|
||||
|
||||
Here's another example that will fail:
|
||||
|
||||
```
|
||||
#[derive(Copy)]
|
||||
enum Foo<'a> {
|
||||
Bar(&'a mut bool),
|
||||
Baz
|
||||
}
|
||||
```
|
||||
|
||||
This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
|
||||
differs from the behavior for `&T`, which is always `Copy`).
|
||||
"##,
|
||||
|
||||
E0206: r##"
|
||||
You can only implement `Copy` for a struct or enum. Both of the following
|
||||
examples will fail, because neither `i32` (primitive type) nor `&'static Bar`
|
||||
(reference to `Bar`) is a struct or enum:
|
||||
|
||||
```
|
||||
type Foo = i32;
|
||||
impl Copy for Foo { } // error
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Bar;
|
||||
impl Copy for &'static Bar { } // error
|
||||
```
|
||||
"##,
|
||||
|
||||
E0243: r##"
|
||||
This error indicates that not enough type parameters were found in a type or
|
||||
trait.
|
||||
|
||||
For example, the `Foo` struct below is defined to be generic in `T`, but the
|
||||
type parameter is missing in the definition of `Bar`:
|
||||
|
||||
```
|
||||
struct Foo<T> { x: T }
|
||||
|
||||
struct Bar { x: Foo }
|
||||
```
|
||||
"##,
|
||||
|
||||
E0244: r##"
|
||||
This error indicates that too many type parameters were found in a type or
|
||||
trait.
|
||||
|
||||
For example, the `Foo` struct below has no type parameters, but is supplied
|
||||
with two in the definition of `Bar`:
|
||||
|
||||
```
|
||||
struct Foo { x: bool }
|
||||
|
||||
struct Bar<S, T> { x: Foo<S, T> }
|
||||
```
|
||||
"##,
|
||||
|
||||
E0249: r##"
|
||||
This error indicates a constant expression for the array length was found, but
|
||||
it was not an integer (signed or unsigned) expression.
|
||||
|
||||
Some examples of code that produces this error are:
|
||||
|
||||
```
|
||||
const A: [u32; "hello"] = []; // error
|
||||
const B: [u32; true] = []; // error
|
||||
const C: [u32; 0.0] = []; // error
|
||||
"##,
|
||||
|
||||
E0250: r##"
|
||||
This means there was an error while evaluating the expression for the length of
|
||||
a fixed-size array type.
|
||||
|
||||
Some examples of code that produces this error are:
|
||||
|
||||
```
|
||||
// divide by zero in the length expression
|
||||
const A: [u32; 1/0] = [];
|
||||
|
||||
// Rust currently will not evaluate the function `foo` at compile time
|
||||
fn foo() -> usize { 12 }
|
||||
const B: [u32; foo()] = [];
|
||||
|
||||
// it is an error to try to add `u8` and `f64`
|
||||
use std::{f64, u8};
|
||||
const C: [u32; u8::MAX + f64::EPSILON] = [];
|
||||
```
|
||||
"##
|
||||
|
||||
}
|
||||
|
|
@ -133,23 +306,22 @@ register_diagnostics! {
|
|||
E0030,
|
||||
E0031,
|
||||
E0033,
|
||||
E0034,
|
||||
E0035,
|
||||
E0036,
|
||||
E0038,
|
||||
E0034, // multiple applicable methods in scope
|
||||
E0035, // does not take type parameters
|
||||
E0036, // incorrect number of type parameters given for this method
|
||||
E0038, // cannot convert to a trait object because trait is not object-safe
|
||||
E0040, // explicit use of destructor method
|
||||
E0044,
|
||||
E0045,
|
||||
E0044, // foreign items may not have type parameters
|
||||
E0045, // variadic function must have C calling convention
|
||||
E0049,
|
||||
E0050,
|
||||
E0053,
|
||||
E0055,
|
||||
E0057,
|
||||
E0055, // method has an incompatible type for trait
|
||||
E0057, // method has an incompatible type for trait
|
||||
E0059,
|
||||
E0060,
|
||||
E0061,
|
||||
E0066,
|
||||
E0067,
|
||||
E0068,
|
||||
E0069,
|
||||
E0070,
|
||||
|
|
@ -189,8 +361,6 @@ register_diagnostics! {
|
|||
E0128,
|
||||
E0129,
|
||||
E0130,
|
||||
E0131,
|
||||
E0132,
|
||||
E0141,
|
||||
E0159,
|
||||
E0163,
|
||||
|
|
@ -204,7 +374,6 @@ register_diagnostics! {
|
|||
E0178,
|
||||
E0182,
|
||||
E0183,
|
||||
E0184,
|
||||
E0185,
|
||||
E0186,
|
||||
E0187, // can't infer the kind of the closure
|
||||
|
|
@ -226,12 +395,6 @@ register_diagnostics! {
|
|||
E0202, // associated items are not allowed in inherent impls
|
||||
E0203, // type parameter has more than one relaxed default bound,
|
||||
// and only one is supported
|
||||
E0204, // trait `Copy` may not be implemented for this type; field
|
||||
// does not implement `Copy`
|
||||
E0205, // trait `Copy` may not be implemented for this type; variant
|
||||
// does not implement `copy`
|
||||
E0206, // trait `Copy` may not be implemented for this type; type is
|
||||
// not a structure or enumeration
|
||||
E0207, // type parameter is not constrained by the impl trait, self type, or predicate
|
||||
E0208,
|
||||
E0209, // builtin traits can only be implemented on structs or enums
|
||||
|
|
@ -268,14 +431,10 @@ register_diagnostics! {
|
|||
E0240,
|
||||
E0241,
|
||||
E0242, // internal error looking up a definition
|
||||
E0243, // wrong number of type arguments
|
||||
E0244, // wrong number of type arguments
|
||||
E0245, // not a trait
|
||||
E0246, // illegal recursive type
|
||||
E0247, // found module name used as a type
|
||||
E0248, // found value name used as a type
|
||||
E0249, // expected constant expr for array length
|
||||
E0250, // expected constant expr for array length
|
||||
E0318, // can't create default impls for traits outside their crates
|
||||
E0319, // trait impls for defaulted traits allowed just for structs/enums
|
||||
E0320, // recursive overflow during dropck
|
||||
|
|
|
|||
|
|
@ -178,8 +178,8 @@
|
|||
//! further that for whatever reason I specifically supply the value of
|
||||
//! `String` for the type parameter `T`:
|
||||
//!
|
||||
//! let mut vector = ~["string", ...];
|
||||
//! convertAll::<int, String>(v);
|
||||
//! let mut vector = vec!["string", ...];
|
||||
//! convertAll::<int, String>(vector);
|
||||
//!
|
||||
//! Is this legal? To put another way, can we apply the `impl` for
|
||||
//! `Object` to the type `String`? The answer is yes, but to see why
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn
|
|||
|
||||
pub fn build_impls(cx: &DocContext, tcx: &ty::ctxt,
|
||||
did: ast::DefId) -> Vec<clean::Item> {
|
||||
ty::populate_implementations_for_type_if_necessary(tcx, did);
|
||||
ty::populate_inherent_implementations_for_type_if_necessary(tcx, did);
|
||||
let mut impls = Vec::new();
|
||||
|
||||
match tcx.inherent_impls.borrow().get(&did) {
|
||||
|
|
|
|||
|
|
@ -897,7 +897,7 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// maybe use a Generic enum and use ~[Generic]?
|
||||
// maybe use a Generic enum and use Vec<Generic>?
|
||||
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
|
||||
pub struct Generics {
|
||||
pub lifetimes: Vec<Lifetime>,
|
||||
|
|
|
|||
|
|
@ -905,6 +905,8 @@ impl DocFolder for Cache {
|
|||
// Index this method for searching later on
|
||||
if let Some(ref s) = item.name {
|
||||
let (parent, is_method) = match item.inner {
|
||||
clean::AssociatedTypeItem(..) |
|
||||
clean::AssociatedConstItem(..) |
|
||||
clean::TyMethodItem(..) |
|
||||
clean::StructFieldItem(..) |
|
||||
clean::VariantItem(..) => {
|
||||
|
|
@ -1862,6 +1864,17 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
try!(write!(w, "</div>"));
|
||||
}
|
||||
|
||||
if !consts.is_empty() {
|
||||
try!(write!(w, "
|
||||
<h2 id='associated-const'>Associated Constants</h2>
|
||||
<div class='methods'>
|
||||
"));
|
||||
for t in &consts {
|
||||
try!(trait_item(w, *t));
|
||||
}
|
||||
try!(write!(w, "</div>"));
|
||||
}
|
||||
|
||||
// Output the documentation for each function individually
|
||||
if !required.is_empty() {
|
||||
try!(write!(w, "
|
||||
|
|
|
|||
|
|
@ -34,7 +34,8 @@
|
|||
"macro",
|
||||
"primitive",
|
||||
"associatedtype",
|
||||
"constant"];
|
||||
"constant",
|
||||
"associatedconstant"];
|
||||
|
||||
$('.js-only').removeClass('js-only');
|
||||
|
||||
|
|
|
|||
|
|
@ -916,6 +916,24 @@ impl<K, V, S> HashMap<K, V, S>
|
|||
}
|
||||
|
||||
/// Gets the given key's corresponding entry in the map for in-place manipulation.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// let mut letters = HashMap::new();
|
||||
///
|
||||
/// for ch in "a short treatise on fungi".chars() {
|
||||
/// let counter = letters.entry(ch).or_insert(0);
|
||||
/// *counter += 1;
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(letters[&'s'], 2);
|
||||
/// assert_eq!(letters[&'t'], 3);
|
||||
/// assert_eq!(letters[&'u'], 1);
|
||||
/// assert_eq!(letters.get(&'y'), None);
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn entry(&mut self, key: K) -> Entry<K, V> {
|
||||
// Gotta resize now.
|
||||
|
|
|
|||
|
|
@ -844,7 +844,7 @@ impl fmt::Display for CharsError {
|
|||
/// An iterator over the contents of an instance of `BufRead` split on a
|
||||
/// particular byte.
|
||||
///
|
||||
/// See `BufReadExt::split` for more information.
|
||||
/// See `BufRead::split` for more information.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Split<B> {
|
||||
buf: B,
|
||||
|
|
@ -873,7 +873,7 @@ impl<B: BufRead> Iterator for Split<B> {
|
|||
/// An iterator over the lines of an instance of `BufRead` split on a newline
|
||||
/// byte.
|
||||
///
|
||||
/// See `BufReadExt::lines` for more information.
|
||||
/// See `BufRead::lines` for more information.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Lines<B> {
|
||||
buf: B,
|
||||
|
|
|
|||
|
|
@ -1199,7 +1199,7 @@ impl Into<OsString> for PathBuf {
|
|||
/// absolute, and so on. More details about the overall approach can be found in
|
||||
/// the module documentation.
|
||||
///
|
||||
/// This is an *unsized* type, meaning that it must always be used with behind a
|
||||
/// This is an *unsized* type, meaning that it must always be used behind a
|
||||
/// pointer like `&` or `Box`.
|
||||
///
|
||||
/// # Examples
|
||||
|
|
@ -1449,6 +1449,8 @@ impl Path {
|
|||
|
||||
/// Determines whether `base` is a prefix of `self`.
|
||||
///
|
||||
/// Only considers whole path components to match.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
@ -1457,6 +1459,8 @@ impl Path {
|
|||
/// let path = Path::new("/etc/passwd");
|
||||
///
|
||||
/// assert!(path.starts_with("/etc"));
|
||||
///
|
||||
/// assert!(!path.starts_with("/e"));
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
|
||||
|
|
@ -1465,6 +1469,8 @@ impl Path {
|
|||
|
||||
/// Determines whether `child` is a suffix of `self`.
|
||||
///
|
||||
/// Only considers whole path components to match.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
|
|
|
|||
|
|
@ -85,6 +85,8 @@ pub struct LocalKey<T> {
|
|||
}
|
||||
|
||||
/// Declare a new thread local storage key of type `std::thread::LocalKey`.
|
||||
///
|
||||
/// See [LocalKey documentation](thread/struct.LocalKey.html) for more information.
|
||||
#[macro_export]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[allow_internal_unstable]
|
||||
|
|
|
|||
|
|
@ -66,6 +66,8 @@ pub struct ScopedKey<T> { #[doc(hidden)] pub inner: __impl::KeyInner<T> }
|
|||
///
|
||||
/// This macro declares a `static` item on which methods are used to get and
|
||||
/// set the value stored within.
|
||||
///
|
||||
/// See [ScopedKey documentation](thread/struct.ScopedKey.html) for more information.
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable]
|
||||
macro_rules! scoped_thread_local {
|
||||
|
|
|
|||
|
|
@ -904,8 +904,8 @@ impl<'a> MethodDef<'a> {
|
|||
nonself_args: &[P<Expr>])
|
||||
-> P<Expr> {
|
||||
|
||||
let mut raw_fields = Vec::new(); // ~[[fields of self],
|
||||
// [fields of next Self arg], [etc]]
|
||||
let mut raw_fields = Vec::new(); // Vec<[fields of self],
|
||||
// [fields of next Self arg], [etc]>
|
||||
let mut patterns = Vec::new();
|
||||
for i in 0..self_args.len() {
|
||||
let struct_path= cx.path(DUMMY_SP, vec!( type_ident ));
|
||||
|
|
|
|||
|
|
@ -1719,7 +1719,7 @@ mod tests {
|
|||
// induced by visit. Each of these arrays contains a list of indexes,
|
||||
// interpreted as the varrefs in the varref traversal that this binding
|
||||
// should match. So, for instance, in a program with two bindings and
|
||||
// three varrefs, the array ~[~[1,2],~[0]] would indicate that the first
|
||||
// three varrefs, the array [[1, 2], [0]] would indicate that the first
|
||||
// binding should match the second two varrefs, and the second binding
|
||||
// should match the first varref.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -109,15 +109,6 @@ pub enum PathParsingMode {
|
|||
LifetimeAndTypesWithColons,
|
||||
}
|
||||
|
||||
/// How to parse a qualified path, whether to allow trailing parameters.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum QPathParsingMode {
|
||||
/// No trailing parameters, e.g. `<T as Trait>::Item`
|
||||
NoParameters,
|
||||
/// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
|
||||
MaybeParameters,
|
||||
}
|
||||
|
||||
/// How to parse a bound, whether to allow bound modifiers such as `?`.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum BoundParsingMode {
|
||||
|
|
@ -1359,7 +1350,7 @@ impl<'a> Parser<'a> {
|
|||
} else if try!(self.eat_lt()) {
|
||||
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||
try!(self.parse_qualified_path(NoTypesAllowed));
|
||||
|
||||
TyPath(Some(qself), path)
|
||||
} else if self.check(&token::ModSep) ||
|
||||
|
|
@ -1578,7 +1569,7 @@ impl<'a> Parser<'a> {
|
|||
|
||||
// QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
|
||||
// Assumes that the leading `<` has been parsed already.
|
||||
pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
|
||||
pub fn parse_qualified_path(&mut self, mode: PathParsingMode)
|
||||
-> PResult<(QSelf, ast::Path)> {
|
||||
let self_type = try!(self.parse_ty_sum());
|
||||
let mut path = if try!(self.eat_keyword(keywords::As)) {
|
||||
|
|
@ -1599,29 +1590,18 @@ impl<'a> Parser<'a> {
|
|||
try!(self.expect(&token::Gt));
|
||||
try!(self.expect(&token::ModSep));
|
||||
|
||||
let item_name = try!(self.parse_ident());
|
||||
let parameters = match mode {
|
||||
QPathParsingMode::NoParameters => ast::PathParameters::none(),
|
||||
QPathParsingMode::MaybeParameters => {
|
||||
if try!(self.eat(&token::ModSep)) {
|
||||
try!(self.expect_lt());
|
||||
// Consumed `item::<`, go look for types
|
||||
let (lifetimes, types, bindings) =
|
||||
try!(self.parse_generic_values_after_lt());
|
||||
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
|
||||
lifetimes: lifetimes,
|
||||
types: OwnedSlice::from_vec(types),
|
||||
bindings: OwnedSlice::from_vec(bindings),
|
||||
})
|
||||
} else {
|
||||
ast::PathParameters::none()
|
||||
}
|
||||
let segments = match mode {
|
||||
LifetimeAndTypesWithoutColons => {
|
||||
try!(self.parse_path_segments_without_colons())
|
||||
}
|
||||
LifetimeAndTypesWithColons => {
|
||||
try!(self.parse_path_segments_with_colons())
|
||||
}
|
||||
NoTypesAllowed => {
|
||||
try!(self.parse_path_segments_without_types())
|
||||
}
|
||||
};
|
||||
path.segments.push(ast::PathSegment {
|
||||
identifier: item_name,
|
||||
parameters: parameters
|
||||
});
|
||||
path.segments.extend(segments);
|
||||
|
||||
if path.segments.len() == 1 {
|
||||
path.span.lo = self.last_span.lo;
|
||||
|
|
@ -2096,7 +2076,7 @@ impl<'a> Parser<'a> {
|
|||
if try!(self.eat_lt()){
|
||||
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
|
||||
try!(self.parse_qualified_path(LifetimeAndTypesWithColons));
|
||||
|
||||
return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
|
||||
}
|
||||
|
|
@ -3176,7 +3156,7 @@ impl<'a> Parser<'a> {
|
|||
let (qself, path) = if try!(self.eat_lt()) {
|
||||
// Parse a qualified path
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||
try!(self.parse_qualified_path(NoTypesAllowed));
|
||||
(Some(qself), path)
|
||||
} else {
|
||||
// Parse an unqualified path
|
||||
|
|
@ -3270,7 +3250,7 @@ impl<'a> Parser<'a> {
|
|||
let (qself, path) = if try!(self.eat_lt()) {
|
||||
// Parse a qualified path
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||
try!(self.parse_qualified_path(NoTypesAllowed));
|
||||
(Some(qself), path)
|
||||
} else {
|
||||
// Parse an unqualified path
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ impl<'a> Printer<'a> {
|
|||
self.token[self.right] = t;
|
||||
}
|
||||
pub fn pretty_print(&mut self, token: Token) -> io::Result<()> {
|
||||
debug!("pp ~[{},{}]", self.left, self.right);
|
||||
debug!("pp Vec<{},{}>", self.left, self.right);
|
||||
match token {
|
||||
Token::Eof => {
|
||||
if !self.scan_stack_empty {
|
||||
|
|
@ -329,7 +329,7 @@ impl<'a> Printer<'a> {
|
|||
self.left = 0;
|
||||
self.right = 0;
|
||||
} else { self.advance_right(); }
|
||||
debug!("pp Begin({})/buffer ~[{},{}]",
|
||||
debug!("pp Begin({})/buffer Vec<{},{}>",
|
||||
b.offset, self.left, self.right);
|
||||
self.token[self.right] = token;
|
||||
self.size[self.right] = -self.right_total;
|
||||
|
|
@ -339,10 +339,10 @@ impl<'a> Printer<'a> {
|
|||
}
|
||||
Token::End => {
|
||||
if self.scan_stack_empty {
|
||||
debug!("pp End/print ~[{},{}]", self.left, self.right);
|
||||
debug!("pp End/print Vec<{},{}>", self.left, self.right);
|
||||
self.print(token, 0)
|
||||
} else {
|
||||
debug!("pp End/buffer ~[{},{}]", self.left, self.right);
|
||||
debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
|
||||
self.advance_right();
|
||||
self.token[self.right] = token;
|
||||
self.size[self.right] = -1;
|
||||
|
|
@ -358,7 +358,7 @@ impl<'a> Printer<'a> {
|
|||
self.left = 0;
|
||||
self.right = 0;
|
||||
} else { self.advance_right(); }
|
||||
debug!("pp Break({})/buffer ~[{},{}]",
|
||||
debug!("pp Break({})/buffer Vec<{},{}>",
|
||||
b.offset, self.left, self.right);
|
||||
self.check_stack(0);
|
||||
let right = self.right;
|
||||
|
|
@ -370,11 +370,11 @@ impl<'a> Printer<'a> {
|
|||
}
|
||||
Token::String(s, len) => {
|
||||
if self.scan_stack_empty {
|
||||
debug!("pp String('{}')/print ~[{},{}]",
|
||||
debug!("pp String('{}')/print Vec<{},{}>",
|
||||
s, self.left, self.right);
|
||||
self.print(Token::String(s, len), len)
|
||||
} else {
|
||||
debug!("pp String('{}')/buffer ~[{},{}]",
|
||||
debug!("pp String('{}')/buffer Vec<{},{}>",
|
||||
s, self.left, self.right);
|
||||
self.advance_right();
|
||||
self.token[self.right] = Token::String(s, len);
|
||||
|
|
@ -386,7 +386,7 @@ impl<'a> Printer<'a> {
|
|||
}
|
||||
}
|
||||
pub fn check_stream(&mut self) -> io::Result<()> {
|
||||
debug!("check_stream ~[{}, {}] with left_total={}, right_total={}",
|
||||
debug!("check_stream Vec<{}, {}> with left_total={}, right_total={}",
|
||||
self.left, self.right, self.left_total, self.right_total);
|
||||
if self.right_total - self.left_total > self.space {
|
||||
debug!("scan window is {}, longer than space on line ({})",
|
||||
|
|
@ -446,7 +446,7 @@ impl<'a> Printer<'a> {
|
|||
assert!((self.right != self.left));
|
||||
}
|
||||
pub fn advance_left(&mut self) -> io::Result<()> {
|
||||
debug!("advance_left ~[{},{}], sizeof({})={}", self.left, self.right,
|
||||
debug!("advance_left Vec<{},{}>, sizeof({})={}", self.left, self.right,
|
||||
self.left, self.size[self.left]);
|
||||
|
||||
let mut left_size = self.size[self.left];
|
||||
|
|
|
|||
|
|
@ -259,8 +259,8 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn> ) {
|
|||
// This will panic (intentionally) when fed any dynamic tests, because
|
||||
// it is copying the static values out into a dynamic vector and cannot
|
||||
// copy dynamic values. It is doing this because from this point on
|
||||
// a ~[TestDescAndFn] is used in order to effect ownership-transfer
|
||||
// semantics into parallel test runners, which in turn requires a ~[]
|
||||
// a Vec<TestDescAndFn> is used in order to effect ownership-transfer
|
||||
// semantics into parallel test runners, which in turn requires a Vec<>
|
||||
// rather than a &[].
|
||||
pub fn test_main_static(args: env::Args, tests: &[TestDescAndFn]) {
|
||||
let args = args.collect::<Vec<_>>();
|
||||
|
|
|
|||
27
src/test/compile-fail/double-import.rs
Normal file
27
src/test/compile-fail/double-import.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// 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.
|
||||
#![feature(no_std)]
|
||||
#![no_std]
|
||||
|
||||
// This tests that conflicting imports shows both `use` lines
|
||||
// when reporting the error.
|
||||
|
||||
mod sub1 {
|
||||
fn foo() {} // implementation 1
|
||||
}
|
||||
|
||||
mod sub2 {
|
||||
fn foo() {} // implementation 2
|
||||
}
|
||||
|
||||
use sub1::foo; //~ NOTE previous import of `foo` here
|
||||
use sub2::foo; //~ ERROR a value named `foo` has already been imported in this module [E0252]
|
||||
|
||||
fn main() {}
|
||||
25
src/test/compile-fail/issue-20413.rs
Normal file
25
src/test/compile-fail/issue-20413.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
// 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.
|
||||
|
||||
trait Foo {
|
||||
fn answer(self);
|
||||
}
|
||||
|
||||
struct NoData<T>;
|
||||
//~^ ERROR: parameter `T` is never used
|
||||
|
||||
impl<T> Foo for T where NoData<T>: Foo {
|
||||
//~^ ERROR: overflow evaluating the requirement
|
||||
fn answer(self) {
|
||||
let val: NoData<T> = NoData;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -37,7 +37,7 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
|
|||
assert_copy::<&'static mut isize>(); //~ ERROR `core::marker::Copy` is not implemented
|
||||
assert_copy::<&'a mut isize>(); //~ ERROR `core::marker::Copy` is not implemented
|
||||
|
||||
// ~ pointers are not ok
|
||||
// owned pointers are not ok
|
||||
assert_copy::<Box<isize>>(); //~ ERROR `core::marker::Copy` is not implemented
|
||||
assert_copy::<String>(); //~ ERROR `core::marker::Copy` is not implemented
|
||||
assert_copy::<Vec<isize> >(); //~ ERROR `core::marker::Copy` is not implemented
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
// ignore-test
|
||||
|
||||
fn main() {
|
||||
let args : ~[String] = ::std::os::args();
|
||||
let args : Vec<String> = ::std::os::args();
|
||||
::std::io::println(args[0]);
|
||||
}
|
||||
|
||||
|
|
@ -25,6 +25,6 @@ fn main() {
|
|||
// compile-flags:-g
|
||||
// gdb-command:list
|
||||
// gdb-check:1[...]fn main() {
|
||||
// gdb-check:2[...]let args : ~[String] = ::std::os::args();
|
||||
// gdb-check:2[...]let args : Vec<String> = ::std::os::args();
|
||||
// gdb-check:3[...]::std::io::println(args[0]);
|
||||
// gdb-check:4[...]}
|
||||
|
|
|
|||
55
src/test/run-pass/associated-item-long-paths.rs
Normal file
55
src/test/run-pass/associated-item-long-paths.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// 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::mem::size_of;
|
||||
|
||||
// The main point of this test is to ensure that we can parse and resolve
|
||||
// associated items on associated types.
|
||||
|
||||
trait Foo {
|
||||
type U;
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
// Note 1: Chains of associated items in a path won't type-check.
|
||||
// Note 2: Associated consts can't depend on type parameters or `Self`,
|
||||
// which are the only types that an associated type can be referenced on for
|
||||
// now, so we can only test methods.
|
||||
fn method() -> u32;
|
||||
fn generic_method<T>() -> usize;
|
||||
}
|
||||
|
||||
struct MyFoo;
|
||||
struct MyBar;
|
||||
|
||||
impl Foo for MyFoo {
|
||||
type U = MyBar;
|
||||
}
|
||||
|
||||
impl Bar for MyBar {
|
||||
fn method() -> u32 {
|
||||
2u32
|
||||
}
|
||||
fn generic_method<T>() -> usize {
|
||||
size_of::<T>()
|
||||
}
|
||||
}
|
||||
|
||||
fn foo<T>()
|
||||
where T: Foo,
|
||||
T::U: Bar,
|
||||
{
|
||||
assert_eq!(2u32, <T as Foo>::U::method());
|
||||
assert_eq!(8usize, <T as Foo>::U::generic_method::<f64>());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
foo::<MyFoo>();
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ struct F { field: isize }
|
|||
pub fn main() {
|
||||
/*foo(1);
|
||||
foo("hi".to_string());
|
||||
foo(~[1, 2, 3]);
|
||||
foo(vec![1, 2, 3]);
|
||||
foo(F{field: 42});
|
||||
foo((1, 2));
|
||||
foo(@1);*/
|
||||
|
|
|
|||
16
src/test/run-pass/issue-18075.rs
Normal file
16
src/test/run-pass/issue-18075.rs
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
// 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.
|
||||
|
||||
// exec-env:RUST_LOG=rustc::middle=debug
|
||||
|
||||
fn main() {
|
||||
let b = 1isize;
|
||||
println!("{}", b);
|
||||
}
|
||||
20
src/test/run-pass/issue-23336.rs
Normal file
20
src/test/run-pass/issue-23336.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// 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.
|
||||
|
||||
pub trait Data { fn doit(&self) {} }
|
||||
impl<T> Data for T {}
|
||||
pub trait UnaryLogic { type D: Data; }
|
||||
impl UnaryLogic for () { type D = i32; }
|
||||
|
||||
pub fn crashes<T: UnaryLogic>(t: T::D) {
|
||||
t.doit();
|
||||
}
|
||||
|
||||
fn main() { crashes::<()>(0); }
|
||||
|
|
@ -32,10 +32,6 @@ fn check_strs(actual: &str, expected: &str) -> bool
|
|||
|
||||
pub fn main()
|
||||
{
|
||||
// assert!(check_strs(fmt!("%?", Text(@"foo".to_string())), "Text(@~\"foo\")"));
|
||||
// assert!(check_strs(fmt!("%?", ETag(@~["foo".to_string()], @"bar".to_string())),
|
||||
// "ETag(@~[ ~\"foo\" ], @~\"bar\")"));
|
||||
|
||||
let t = Token::Text("foo".to_string());
|
||||
let u = Token::Section(vec!["alpha".to_string()],
|
||||
true,
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ use std::io::{ReaderUtil,WriterUtil};
|
|||
enum Result {
|
||||
Nil,
|
||||
Int(isize),
|
||||
Data(~[u8]),
|
||||
List(~[Result]),
|
||||
Data(Vec<u8>),
|
||||
List(Vec<Result>),
|
||||
Error(String),
|
||||
Status(String)
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ fn parse_data(len: usize, io: @io::Reader) -> Result {
|
|||
assert_eq!(bytes.len(), len);
|
||||
Data(bytes)
|
||||
} else {
|
||||
Data(~[])
|
||||
Data(vec![])
|
||||
};
|
||||
assert_eq!(io.read_char(), '\r');
|
||||
assert_eq!(io.read_char(), '\n');
|
||||
|
|
@ -43,7 +43,7 @@ fn parse_data(len: usize, io: @io::Reader) -> Result {
|
|||
}
|
||||
|
||||
fn parse_list(len: usize, io: @io::Reader) -> Result {
|
||||
let mut list: ~[Result] = ~[];
|
||||
let mut list: Vec<Result> = vec![];
|
||||
for _ in 0..len {
|
||||
let v = match io.read_char() {
|
||||
'$' => parse_bulk(io),
|
||||
|
|
@ -72,7 +72,7 @@ fn parse_multi(io: @io::Reader) -> Result {
|
|||
match from_str::<isize>(chop(io.read_line())) {
|
||||
None => panic!(),
|
||||
Some(-1) => Nil,
|
||||
Some(0) => List(~[]),
|
||||
Some(0) => List(vec![]),
|
||||
Some(len) if len >= 0 => parse_list(len as usize, io),
|
||||
Some(_) => panic!()
|
||||
}
|
||||
|
|
@ -96,7 +96,7 @@ fn parse_response(io: @io::Reader) -> Result {
|
|||
}
|
||||
}
|
||||
|
||||
fn cmd_to_string(cmd: ~[String]) -> String {
|
||||
fn cmd_to_string(cmd: Vec<String>) -> String {
|
||||
let mut res = "*".to_string();
|
||||
res.push_str(cmd.len().to_string());
|
||||
res.push_str("\r\n");
|
||||
|
|
@ -107,7 +107,7 @@ fn cmd_to_string(cmd: ~[String]) -> String {
|
|||
res
|
||||
}
|
||||
|
||||
fn query(cmd: ~[String], sb: TcpSocketBuf) -> Result {
|
||||
fn query(cmd: Vec<String>, sb: TcpSocketBuf) -> Result {
|
||||
let cmd = cmd_to_string(cmd);
|
||||
//println!("{}", cmd);
|
||||
sb.write_str(cmd);
|
||||
|
|
@ -115,7 +115,7 @@ fn query(cmd: ~[String], sb: TcpSocketBuf) -> Result {
|
|||
res
|
||||
}
|
||||
|
||||
fn query2(cmd: ~[String]) -> Result {
|
||||
fn query2(cmd: Vec<String>) -> Result {
|
||||
let _cmd = cmd_to_string(cmd);
|
||||
io::with_str_reader("$3\r\nXXX\r\n".to_string())(|sb| {
|
||||
let res = parse_response(@sb as @io::Reader);
|
||||
|
|
|
|||
60
src/test/run-pass/slice-of-zero-size-elements.rs
Normal file
60
src/test/run-pass/slice-of-zero-size-elements.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// 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.
|
||||
|
||||
// compile-flags: -C debug-assertions
|
||||
|
||||
#![feature(core)]
|
||||
|
||||
use std::slice;
|
||||
|
||||
fn foo<T>(v: &[T]) -> Option<&[T]> {
|
||||
let mut it = v.iter();
|
||||
for _ in 0..5 {
|
||||
let _ = it.next();
|
||||
}
|
||||
Some(it.as_slice())
|
||||
}
|
||||
|
||||
fn foo_mut<T>(v: &mut [T]) -> Option<&mut [T]> {
|
||||
let mut it = v.iter_mut();
|
||||
for _ in 0..5 {
|
||||
let _ = it.next();
|
||||
}
|
||||
Some(it.into_slice())
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
// In a slice of zero-size elements the pointer is meaningless.
|
||||
// Ensure iteration still works even if the pointer is at the end of the address space.
|
||||
let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) };
|
||||
assert_eq!(slice.len(), 10);
|
||||
assert_eq!(slice.iter().count(), 10);
|
||||
|
||||
// .nth() on the iterator should also behave correctly
|
||||
let mut it = slice.iter();
|
||||
assert!(it.nth(5).is_some());
|
||||
assert_eq!(it.count(), 4);
|
||||
|
||||
// Converting Iter to a slice should never have a null pointer
|
||||
assert!(foo(slice).is_some());
|
||||
|
||||
// Test mutable iterators as well
|
||||
let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) };
|
||||
assert_eq!(slice.len(), 10);
|
||||
assert_eq!(slice.iter_mut().count(), 10);
|
||||
|
||||
{
|
||||
let mut it = slice.iter_mut();
|
||||
assert!(it.nth(5).is_some());
|
||||
assert_eq!(it.count(), 4);
|
||||
}
|
||||
|
||||
assert!(foo_mut(slice).is_some())
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
pub trait Foo {
|
||||
// @has assoc_consts/trait.Foo.html '//*[@class="rust trait"]' \
|
||||
// 'const FOO: usize;'
|
||||
// @has - '//*[@id="associatedconstant.FOO"]' 'const FOO'
|
||||
const FOO: usize;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue