D := $(S)src/doc
-DOC_TARGETS := book nomicon style error-index
+DOC_TARGETS := book nomicon error-index
COMPILER_DOC_TARGETS :=
DOC_L10N_TARGETS :=
$(Q)rm -rf doc/nomicon
$(Q)$(RUSTBOOK) build $(S)src/doc/nomicon doc/nomicon
-style: doc/style/index.html
-
-doc/style/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/style/*.md) | doc/
- @$(call E, rustbook: $@)
- $(Q)rm -rf doc/style
- $(Q)$(RUSTBOOK) build $(S)src/doc/style doc/style
-
error-index: doc/error-index.html
# Metadata used to generate the index is created as a side effect of
doc::rustbook(self, stage, target.target, "nomicon",
&doc_out);
}
- DocStyle { stage } => {
- doc::rustbook(self, stage, target.target, "style",
- &doc_out);
- }
DocStandalone { stage } => {
doc::standalone(self, stage, target.target, &doc_out);
}
(doc, Doc { stage: u32 }),
(doc_book, DocBook { stage: u32 }),
(doc_nomicon, DocNomicon { stage: u32 }),
- (doc_style, DocStyle { stage: u32 }),
(doc_standalone, DocStandalone { stage: u32 }),
(doc_std, DocStd { stage: u32 }),
(doc_test, DocTest { stage: u32 }),
vec![self.libtest(compiler)]
}
Source::DocBook { stage } |
- Source::DocNomicon { stage } |
- Source::DocStyle { stage } => {
+ Source::DocNomicon { stage } => {
vec![self.target(&build.config.build).tool_rustbook(stage)]
}
Source::DocErrorIndex { stage } => {
Source::Doc { stage } => {
let mut deps = vec![
self.doc_book(stage), self.doc_nomicon(stage),
- self.doc_style(stage), self.doc_standalone(stage),
- self.doc_std(stage),
+ self.doc_standalone(stage), self.doc_std(stage),
self.doc_error_index(stage),
];
+++ /dev/null
-% Style Guidelines
-
-This document collects the emerging principles, conventions, abstractions, and
-best practices for writing Rust code.
-
-Since Rust is evolving at a rapid pace, these guidelines are
-preliminary. The hope is that writing them down explicitly will help
-drive discussion, consensus and adoption.
-
-Whenever feasible, guidelines provide specific examples from Rust's standard
-libraries.
-
-### Guideline statuses
-
-Every guideline has a status:
-
-* **[FIXME]**: Marks places where there is more work to be done. In
- some cases, that just means going through the RFC process.
-
-* **[FIXME #NNNNN]**: Like **[FIXME]**, but links to the issue tracker.
-
-* **[RFC #NNNN]**: Marks accepted guidelines, linking to the rust-lang
- RFC establishing them.
-
-### Guideline stabilization
-
-One purpose of these guidelines is to reach decisions on a number of
-cross-cutting API and stylistic choices. Discussion and development of
-the guidelines will happen primarily on https://internals.rust-lang.org/,
-using the Guidelines category. Discussion can also occur on the
-[guidelines issue tracker](https://github.com/rust-lang/rust-guidelines).
-
-Guidelines that are under development or discussion will be marked with the
-status **[FIXME]**, with a link to the issue tracker when appropriate.
-
-Once a concrete guideline is ready to be proposed, it should be filed
-as an [FIXME: needs RFC](https://github.com/rust-lang/rfcs). If the RFC is
-accepted, the official guidelines will be updated to match, and will
-include the tag **[RFC #NNNN]** linking to the RFC document.
-
-### What's in this document
-
-This document is broken into four parts:
-
-* **[Style](style/README.md)** provides a set of rules governing naming conventions,
- whitespace, and other stylistic issues.
-
-* **[Guidelines by Rust feature](features/README.md)** places the focus on each of
- Rust's features, starting from expressions and working the way out toward
- crates, dispensing guidelines relevant to each.
-
-* **Topical guidelines and patterns**. The rest of the document proceeds by
- cross-cutting topic, starting with
- [Ownership and resources](ownership/README.md).
-
-* **APIs for a changing Rust**
- discusses the forward-compatibility hazards, especially those that interact
- with the pre-1.0 library stabilization process.
-
-> **[FIXME]** Add cross-references throughout this document to the tutorial,
-> reference manual, and other guides.
-
-> **[FIXME]** What are some _non_-goals, _non_-principles, or _anti_-patterns that
-> we should document?
+++ /dev/null
-# Summary
-
-* [Style](style/README.md)
- * [Whitespace](style/whitespace.md)
- * [Comments](style/comments.md)
- * [Braces, semicolons, commas](style/braces.md)
- * [Naming](style/naming/README.md)
- * [Ownership variants](style/naming/ownership.md)
- * [Containers/wrappers](style/naming/containers.md)
- * [Conversions](style/naming/conversions.md)
- * [Iterators](style/naming/iterators.md)
- * [Imports](style/imports.md)
- * [Organization](style/organization.md)
-* [Guidelines by Rust feature](features/README.md)
- * [Let binding](features/let.md)
- * [Pattern matching](features/match.md)
- * [Loops](features/loops.md)
- * [Functions and methods](features/functions-and-methods/README.md)
- * [Input](features/functions-and-methods/input.md)
- * [Output](features/functions-and-methods/output.md)
- * [For convenience](features/functions-and-methods/convenience.md)
- * [Types](features/types/README.md)
- * [Conversions](features/types/conversions.md)
- * [The newtype pattern](features/types/newtype.md)
- * [Traits](features/traits/README.md)
- * [For generics](features/traits/generics.md)
- * [For objects](features/traits/objects.md)
- * [For overloading](features/traits/overloading.md)
- * [For extensions](features/traits/extensions.md)
- * [For reuse](features/traits/reuse.md)
- * [Common traits](features/traits/common.md)
- * [Modules](features/modules.md)
- * [Crates](features/crates.md)
-* [Ownership and resources](ownership/README.md)
- * [Constructors](ownership/constructors.md)
- * [Builders](ownership/builders.md)
- * [Destructors](ownership/destructors.md)
- * [RAII](ownership/raii.md)
- * [Cells and smart pointers](ownership/cell-smart.md)
-* [Errors](errors/README.md)
- * [Signaling](errors/signaling.md)
- * [Handling](errors/handling.md)
- * [Propagation](errors/propagation.md)
- * [Ergonomics](errors/ergonomics.md)
-* [Safety and guarantees](safety/README.md)
- * [Using unsafe](safety/unsafe.md)
- * [Library guarantees](safety/lib-guarantees.md)
-* [Testing](testing/README.md)
- * [Unit testing](testing/unit.md)
-* [FFI, platform-specific code](platform.md)
+++ /dev/null
-% Errors
-
-> **[FIXME]** Add some general text here.
+++ /dev/null
-% Ergonomic error handling
-
-Error propagation with raw `Result`s can require tedious matching and
-repackaging. This tedium is largely alleviated by the `try!` macro,
-and can be completely removed (in some cases) by the "`Result`-`impl`"
-pattern.
-
-### The `try!` macro
-
-Prefer
-
-```rust,ignore
-use std::io::{File, Open, Write, IoError};
-
-struct Info {
- name: String,
- age: i32,
- rating: i32
-}
-
-fn write_info(info: &Info) -> Result<(), IoError> {
- let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
- Open, Write);
- // Early return on error
- try!(file.write_line(&format!("name: {}", info.name)));
- try!(file.write_line(&format!("age: {}", info.age)));
- try!(file.write_line(&format!("rating: {}", info.rating)));
- return Ok(());
-}
-```
-
-over
-
-```rust,ignore
-use std::io::{File, Open, Write, IoError};
-
-struct Info {
- name: String,
- age: i32,
- rating: i32
-}
-
-fn write_info(info: &Info) -> Result<(), IoError> {
- let mut file = File::open_mode(&Path::new("my_best_friends.txt"),
- Open, Write);
- // Early return on error
- match file.write_line(&format!("name: {}", info.name)) {
- Ok(_) => (),
- Err(e) => return Err(e)
- }
- match file.write_line(&format!("age: {}", info.age)) {
- Ok(_) => (),
- Err(e) => return Err(e)
- }
- return file.write_line(&format!("rating: {}", info.rating));
-}
-```
-
-See
-[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try-macro)
-for more details.
-
-### The `Result`-`impl` pattern [FIXME]
-
-> **[FIXME]** Document the way that the `io` module uses trait impls
-> on `std::io::Result` to painlessly propagate errors.
+++ /dev/null
-% Handling errors
-
-### Use thread isolation to cope with failure. [FIXME]
-
-> **[FIXME]** Explain how to isolate threads and detect thread failure for recovery.
-
-### Consuming `Result` [FIXME]
+++ /dev/null
-% Propagation
-
-> **[FIXME]** We need guidelines on how to layer error information up a stack of
-> abstractions.
-
-### Error interoperation [FIXME]
-
-> **[FIXME]** Document the `FromError` infrastructure.
+++ /dev/null
-% Signaling errors [RFC #236]
-
-> The guidelines below were approved by [RFC #236](https://github.com/rust-lang/rfcs/pull/236).
-
-Errors fall into one of three categories:
-
-* Catastrophic errors, e.g. out-of-memory.
-* Contract violations, e.g. wrong input encoding, index out of bounds.
-* Obstructions, e.g. file not found, parse error.
-
-The basic principle of the convention is that:
-
-* Catastrophic errors and programming errors (bugs) can and should only be
-recovered at a *coarse grain*, i.e. a thread boundary.
-* Obstructions preventing an operation should be reported at a maximally *fine
-grain* -- to the immediate invoker of the operation.
-
-## Catastrophic errors
-
-An error is _catastrophic_ if there is no meaningful way for the current thread to
-continue after the error occurs.
-
-Catastrophic errors are _extremely_ rare, especially outside of `libstd`.
-
-**Canonical examples**: out of memory, stack overflow.
-
-### For catastrophic errors, panic
-
-For errors like stack overflow, Rust currently aborts the process, but
-could in principle panic, which (in the best case) would allow
-reporting and recovery from a supervisory thread.
-
-## Contract violations
-
-An API may define a contract that goes beyond the type checking enforced by the
-compiler. For example, slices support an indexing operation, with the contract
-that the supplied index must be in bounds.
-
-Contracts can be complex and involve more than a single function invocation. For
-example, the `RefCell` type requires that `borrow_mut` not be called until all
-existing borrows have been relinquished.
-
-### For contract violations, panic
-
-A contract violation is always a bug, and for bugs we follow the Erlang
-philosophy of "let it crash": we assume that software *will* have bugs, and we
-design coarse-grained thread boundaries to report, and perhaps recover, from these
-bugs.
-
-### Contract design
-
-One subtle aspect of these guidelines is that the contract for a function is
-chosen by an API designer -- and so the designer also determines what counts as
-a violation.
-
-This RFC does not attempt to give hard-and-fast rules for designing
-contracts. However, here are some rough guidelines:
-
-* Prefer expressing contracts through static types whenever possible.
-
-* It *must* be possible to write code that uses the API without violating the
- contract.
-
-* Contracts are most justified when violations are *inarguably* bugs -- but this
- is surprisingly rare.
-
-* Consider whether the API client could benefit from the contract-checking
- logic. The checks may be expensive. Or there may be useful programming
- patterns where the client does not want to check inputs before hand, but would
- rather attempt the operation and then find out whether the inputs were invalid.
-
-* When a contract violation is the *only* kind of error a function may encounter
- -- i.e., there are no obstructions to its success other than "bad" inputs --
- using `Result` or `Option` instead is especially warranted. Clients can then use
- `unwrap` to assert that they have passed valid input, or re-use the error
- checking done by the API for their own purposes.
-
-* When in doubt, use loose contracts and instead return a `Result` or `Option`.
-
-## Obstructions
-
-An operation is *obstructed* if it cannot be completed for some reason, even
-though the operation's contract has been satisfied. Obstructed operations may
-have (documented!) side effects -- they are not required to roll back after
-encountering an obstruction. However, they should leave the data structures in
-a "coherent" state (satisfying their invariants, continuing to guarantee safety,
-etc.).
-
-Obstructions may involve external conditions (e.g., I/O), or they may involve
-aspects of the input that are not covered by the contract.
-
-**Canonical examples**: file not found, parse error.
-
-### For obstructions, use `Result`
-
-The
-[`Result<T,E>` type](https://doc.rust-lang.org/stable/std/result/index.html)
-represents either a success (yielding `T`) or failure (yielding `E`). By
-returning a `Result`, a function allows its clients to discover and react to
-obstructions in a fine-grained way.
-
-#### What about `Option`?
-
-The `Option` type should not be used for "obstructed" operations; it
-should only be used when a `None` return value could be considered a
-"successful" execution of the operation.
-
-This is of course a somewhat subjective question, but a good litmus
-test is: would a reasonable client ever ignore the result? The
-`Result` type provides a lint that ensures the result is actually
-inspected, while `Option` does not, and this difference of behavior
-can help when deciding between the two types.
-
-Another litmus test: can the operation be understood as asking a
-question (possibly with sideeffects)? Operations like `pop` on a
-vector can be viewed as asking for the contents of the first element,
-with the side effect of removing it if it exists -- with an `Option`
-return value.
-
-## Do not provide both `Result` and `panic!` variants.
-
-An API should not provide both `Result`-producing and `panic`king versions of an
-operation. It should provide just the `Result` version, allowing clients to use
-`try!` or `unwrap` instead as needed. This is part of the general pattern of
-cutting down on redundant variants by instead using method chaining.
+++ /dev/null
-% Guidelines by language feature
-
-Rust provides a unique combination of language features, some new and some
-old. This section gives guidance on when and how to use Rust's features, and
-brings attention to some of the tradeoffs between different features.
-
-Notably missing from this section is an in-depth discussion of Rust's pointer
-types (both built-in and in the library). The topic of pointers is discussed at
-length in a [separate section on ownership](../ownership/README.md).
+++ /dev/null
-% Crates
-
-> **[FIXME]** What general guidelines should we provide for crate design?
-
-> Possible topics: facades; per-crate preludes (to be imported as globs);
-> "lib.rs"
+++ /dev/null
-% Functions and methods
-
-### Prefer methods to functions if there is a clear receiver. **[FIXME: needs RFC]**
-
-Prefer
-
-```rust,ignore
-impl Foo {
- pub fn frob(&self, w: widget) { ... }
-}
-```
-
-over
-
-```rust,ignore
-pub fn frob(foo: &Foo, w: widget) { ... }
-```
-
-for any operation that is clearly associated with a particular
-type.
-
-Methods have numerous advantages over functions:
-
-* They do not need to be imported or qualified to be used: all you
- need is a value of the appropriate type.
-* Their invocation performs autoborrowing (including mutable borrows).
-* They make it easy to answer the question "what can I do with a value
- of type `T`" (especially when using rustdoc).
-* They provide `self` notation, which is more concise and often more
- clearly conveys ownership distinctions.
-
-> **[FIXME]** Revisit these guidelines with
-> [UFCS](https://github.com/nick29581/rfcs/blob/ufcs/0000-ufcs.md) and
-> conventions developing around it.
-
-
-
-### Guidelines for inherent methods. **[FIXME]**
-
-> **[FIXME]** We need guidelines for when to provide inherent methods on a type,
-> versus methods through a trait or functions.
-
-> **NOTE**: Rules for method resolution around inherent methods are in flux,
-> which may impact the guidelines.
+++ /dev/null
-% Convenience methods
-
-### Provide small, coherent sets of convenience methods. **[FIXME: needs RFC]**
-
-_Convenience methods_ wrap up existing functionality in a more convenient
-way. The work done by a convenience method varies widely:
-
-* _Re-providing functions as methods_. For example, the `std::path::Path` type
- provides methods like `stat` on `Path`s that simply invoke the corresponding
- function in `std::io::fs`.
-* _Skipping through conversions_. For example, the `str` type provides a
- `.len()` convenience method which is also expressible as `.as_bytes().len()`.
- Sometimes the conversion is more complex: the `str` module also provides
- `from_chars`, which encapsulates a simple use of iterators.
-* _Encapsulating common arguments_. For example, vectors of `&str`s
- provide a `connect` as well as a special case, `concat`, that is expressible
- using `connect` with a fixed separator of `""`.
-* _Providing more efficient special cases_. The `connect` and `concat` example
- also applies here: singling out `concat` as a special case allows for a more
- efficient implementation.
-
- Note, however, that the `connect` method actually detects the special case
- internally and invokes `concat`. Usually, it is not necessary to add a public
- convenience method just for efficiency gains; there should also be a
- _conceptual_ reason to add it, e.g. because it is such a common special case.
-
-It is tempting to add convenience methods in a one-off, haphazard way as
-common use patterns emerge. Avoid this temptation, and instead _design_ small,
-coherent sets of convenience methods that are easy to remember:
-
-* _Small_: Avoid combinatorial explosions of convenience methods. For example,
- instead of adding `_str` variants of methods that provide a `str` output,
- instead ensure that the normal output type of methods is easily convertible to
- `str`.
-* _Coherent_: Look for small groups of convenience methods that make sense to
- include together. For example, the `Path` API mentioned above includes a small
- selection of the most common filesystem operations that take a `Path`
- argument. If one convenience method strongly suggests the existence of others,
- consider adding the whole group.
-* _Memorable_: It is not worth saving a few characters of typing if you have to
- look up the name of a convenience method every time you use it. Add
- convenience methods with names that are obvious and easy to remember, and add
- them for the most common or painful use cases.
+++ /dev/null
-% Input to functions and methods
-
-### Let the client decide when to copy and where to place data. [FIXME: needs RFC]
-
-#### Copying:
-
-Prefer
-
-```rust,ignore
-fn foo(b: Bar) {
- // use b as owned, directly
-}
-```
-
-over
-
-```rust,ignore
-fn foo(b: &Bar) {
- let b = b.clone();
- // use b as owned after cloning
-}
-```
-
-If a function requires ownership of a value of unknown type `T`, but does not
-otherwise need to make copies, the function should take ownership of the
-argument (pass by value `T`) rather than using `.clone()`. That way, the caller
-can decide whether to relinquish ownership or to `clone`.
-
-Similarly, the `Copy` trait bound should only be demanded it when absolutely
-needed, not as a way of signaling that copies should be cheap to make.
-
-#### Placement:
-
-Prefer
-
-```rust,ignore
-fn foo(b: Bar) -> Bar { ... }
-```
-
-over
-
-```rust,ignore
-fn foo(b: Box<Bar>) -> Box<Bar> { ... }
-```
-
-for concrete types `Bar` (as opposed to trait objects). This way, the caller can
-decide whether to place data on the stack or heap. No overhead is imposed by
-letting the caller determine the placement.
-
-### Minimize assumptions about parameters. [FIXME: needs RFC]
-
-The fewer assumptions a function makes about its inputs, the more widely usable
-it becomes.
-
-#### Minimizing assumptions through generics:
-
-Prefer
-
-```rust,ignore
-fn foo<T: Iterator<i32>>(c: T) { ... }
-```
-
-over any of
-
-```rust,ignore
-fn foo(c: &[i32]) { ... }
-fn foo(c: &Vec<i32>) { ... }
-fn foo(c: &SomeOtherCollection<i32>) { ... }
-```
-
-if the function only needs to iterate over the data.
-
-More generally, consider using generics to pinpoint the assumptions a function
-needs to make about its arguments.
-
-On the other hand, generics can make it more difficult to read and understand a
-function's signature. Aim for "natural" parameter types that a neither overly
-concrete nor overly abstract. See the discussion on
-[traits](../traits/README.md) for more guidance.
-
-
-#### Minimizing ownership assumptions:
-
-Prefer either of
-
-```rust,ignore
-fn foo(b: &Bar) { ... }
-fn foo(b: &mut Bar) { ... }
-```
-
-over
-
-```rust,ignore
-fn foo(b: Bar) { ... }
-```
-
-That is, prefer borrowing arguments rather than transferring ownership, unless
-ownership is actually needed.
-
-### Prefer compound return types to out-parameters. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-fn foo() -> (Bar, Bar)
-```
-
-over
-
-```rust,ignore
-fn foo(output: &mut Bar) -> Bar
-```
-
-for returning multiple `Bar` values.
-
-Compound return types like tuples and structs are efficiently compiled
-and do not require heap allocation. If a function needs to return
-multiple values, it should do so via one of these types.
-
-The primary exception: sometimes a function is meant to modify data
-that the caller already owns, for example to re-use a buffer:
-
-```rust,ignore
-fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>
-```
-
-(From the [Read trait](https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read).)
-
-### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
-
-_Note: this material is closely related to
- [library-level guarantees](../../safety/lib-guarantees.md)._
-
-Rust APIs do _not_ generally follow the
-[robustness principle](https://en.wikipedia.org/wiki/Robustness_principle): "be
-conservative in what you send; be liberal in what you accept".
-
-Instead, Rust code should _enforce_ the validity of input whenever practical.
-
-Enforcement can be achieved through the following mechanisms (listed
-in order of preference).
-
-#### Static enforcement:
-
-Choose an argument type that rules out bad inputs.
-
-For example, prefer
-
-```rust,ignore
-enum FooMode {
- Mode1,
- Mode2,
- Mode3,
-}
-fn foo(mode: FooMode) { ... }
-```
-
-over
-
-```rust,ignore
-fn foo(mode2: bool, mode3: bool) {
- assert!(!mode2 || !mode3);
- ...
-}
-```
-
-Static enforcement usually comes at little run-time cost: it pushes the
-costs to the boundaries. It also catches bugs early, during compilation,
-rather than through run-time failures.
-
-On the other hand, some properties are difficult or impossible to
-express using types.
-
-#### Dynamic enforcement:
-
-Validate the input as it is processed (or ahead of time, if necessary). Dynamic
-checking is often easier to implement than static checking, but has several
-downsides:
-
-1. Runtime overhead (unless checking can be done as part of processing the input).
-2. Delayed detection of bugs.
-3. Introduces failure cases, either via `panic!` or `Result`/`Option` types (see
- the [error handling guidelines](../../errors/README.md)), which must then be
- dealt with by client code.
-
-#### Dynamic enforcement with `debug_assert!`:
-
-Same as dynamic enforcement, but with the possibility of easily turning off
-expensive checks for production builds.
-
-#### Dynamic enforcement with opt-out:
-
-Same as dynamic enforcement, but adds sibling functions that opt out of the
-checking.
-
-The convention is to mark these opt-out functions with a suffix like
-`_unchecked` or by placing them in a `raw` submodule.
-
-The unchecked functions can be used judiciously in cases where (1) performance
-dictates avoiding checks and (2) the client is otherwise confident that the
-inputs are valid.
-
-> **[FIXME]** Should opt-out functions be marked `unsafe`?
+++ /dev/null
-% Output from functions and methods
-
-### Don't overpromise. [FIXME]
-
-> **[FIXME]** Add discussion of overly-specific return types,
-> e.g. returning a compound iterator type rather than hiding it behind
-> a use of newtype.
-
-### Let clients choose what to throw away. [FIXME: needs RFC]
-
-#### Return useful intermediate results:
-
-Many functions that answer a question also compute interesting related data. If
-this data is potentially of interest to the client, consider exposing it in the
-API.
-
-Prefer
-
-```rust,ignore
-struct SearchResult {
- found: bool, // item in container?
- expected_index: usize // what would the item's index be?
-}
-
-fn binary_search(&self, k: Key) -> SearchResult
-```
-or
-
-```rust,ignore
-fn binary_search(&self, k: Key) -> (bool, usize)
-```
-
-over
-
-```rust,ignore
-fn binary_search(&self, k: Key) -> bool
-```
-
-#### Yield back ownership:
-
-Prefer
-
-```rust,ignore
-fn from_utf8_owned(vv: Vec<u8>) -> Result<String, Vec<u8>>
-```
-
-over
-
-```rust,ignore
-fn from_utf8_owned(vv: Vec<u8>) -> Option<String>
-```
-
-The `from_utf8_owned` function gains ownership of a vector. In the successful
-case, the function consumes its input, returning an owned string without
-allocating or copying. In the unsuccessful case, however, the function returns
-back ownership of the original slice.
+++ /dev/null
-% Let binding
-
-### Always separately bind RAII guards. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-fn use_mutex(m: sync::mutex::Mutex<i32>) {
- let guard = m.lock();
- do_work(guard);
- drop(guard); // unlock the lock
- // do other work
-}
-```
-
-over
-
-```rust,ignore
-fn use_mutex(m: sync::mutex::Mutex<i32>) {
- do_work(m.lock());
- // do other work
-}
-```
-
-As explained in the [RAII guide](../ownership/raii.md), RAII guards are values
-that represent ownership of some resource and whose destructor releases the
-resource. Because the lifetime of guards are significant, they should always be
-explicitly `let`-bound to make the lifetime clear. Consider using an explicit
-`drop` to release the resource early.
-
-### Prefer conditional expressions to deferred initialization. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-let foo = match bar {
- Baz => 0,
- Quux => 1
-};
-```
-
-over
-
-```rust,ignore
-let foo;
-match bar {
- Baz => {
- foo = 0;
- }
- Quux => {
- foo = 1;
- }
-}
-```
-
-unless the conditions for initialization are too complex to fit into a simple
-conditional expression.
-
-### Use type annotations for clarification; prefer explicit generics when inference fails. [FIXME: needs RFC]
-
-Prefer
-
-```rust,ignore
-let v = s.iter().map(|x| x * 2)
- .collect::<Vec<_>>();
-```
-
-over
-
-```rust,ignore
-let v: Vec<_> = s.iter().map(|x| x * 2)
- .collect();
-```
-
-When the type of a value might be unclear to the _reader_ of the code, consider
-explicitly annotating it in a `let`.
-
-On the other hand, when the type is unclear to the _compiler_, prefer to specify
-the type by explicit generics instantiation, which is usually more clear.
-
-### Shadowing [FIXME]
-
-> **[FIXME]** Repeatedly shadowing a binding is somewhat common in Rust code. We
-> need to articulate a guideline on when it is appropriate/useful and when not.
-
-### Prefer immutable bindings. [FIXME: needs RFC]
-
-Use `mut` bindings to signal the span during which a value is mutated:
-
-```rust,ignore
-let mut v = Vec::new();
-// push things onto v
-let v = v;
-// use v immutably henceforth
-```
-
-### Prefer to bind all `struct` or tuple fields. [FIXME: needs RFC]
-
-When consuming a `struct` or tuple via a `let`, bind all of the fields rather
-than using `..` to elide the ones you don't need. The benefit is that when
-fields are added, the compiler will pinpoint all of the places where that type
-of value was consumed, which will often need to be adjusted to take the new
-field properly into account.
+++ /dev/null
-% Loops
-
-### Prefer `for` to `while`. [FIXME: needs RFC]
-
-A `for` loop is preferable to a `while` loop, unless the loop counts in a
-non-uniform way (making it difficult to express using `for`).
-
-### Guidelines for `loop`. [FIXME]
-
-> **[FIXME]** When is `loop` recommended? Some possibilities:
-> * For optimistic retry algorithms
-> * For servers
-> * To avoid mutating local variables sometimes needed to fit `while`
+++ /dev/null
-% Pattern matching
-
-### Dereference `match` targets when possible. [FIXME: needs RFC]
-
-Prefer
-
-~~~~ignore
-match *foo {
- X(...) => ...
- Y(...) => ...
-}
-~~~~
-
-over
-
-~~~~ignore
-match foo {
- box X(...) => ...
- box Y(...) => ...
-}
-~~~~
-
-<!-- ### Clearly indicate important scopes. **[FIXME: needs RFC]** -->
-
-<!-- If it is important that the destructor for a value be executed at a specific -->
-<!-- time, clearly bind that value using a standalone `let` -->
+++ /dev/null
-% Modules
-
-> **[FIXME]** What general guidelines should we provide for module design?
-
-> We should discuss visibility, nesting, `mod.rs`, and any interesting patterns
-> around modules.
-
-### Headers [FIXME: needs RFC]
-
-Organize module headers as follows:
- 1. [Imports](../style/imports.md).
- 1. `mod` declarations.
- 1. `pub mod` declarations.
-
-### Avoid `path` directives. [FIXME: needs RFC]
-
-Avoid using `#[path="..."]` directives; make the file system and
-module hierarchy match, instead.
-
-### Use the module hierarchy to organize APIs into coherent sections. [FIXME]
-
-> **[FIXME]** Flesh this out with examples; explain what a "coherent
-> section" is with examples.
->
-> The module hierarchy defines both the public and internal API of your module.
-> Breaking related functionality into submodules makes it understandable to both
-> users and contributors to the module.
-
-### Place modules in their own file. [FIXME: needs RFC]
-
-> **[FIXME]**
-> - "<100 lines" is arbitrary, but it's a clearer recommendation
-> than "~1 page" or similar suggestions that vary by screen size, etc.
-
-For all except very short modules (<100 lines) and [tests](../testing/README.md),
-place the module `foo` in a separate file, as in:
-
-```rust,ignore
-pub mod foo;
-
-// in foo.rs or foo/mod.rs
-pub fn bar() { println!("..."); }
-/* ... */
-```
-
-rather than declaring it inline:
-
-```rust,ignore
-pub mod foo {
- pub fn bar() { println!("..."); }
- /* ... */
-}
-```
-
-#### Use subdirectories for modules with children. [FIXME: needs RFC]
-
-For modules that themselves have submodules, place the module in a separate
-directory (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory.
-
-Note the structure of
-[`std::io`](https://doc.rust-lang.org/std/io/). Many of the submodules lack
-children, like
-[`io::fs`](https://doc.rust-lang.org/std/io/fs/)
-and
-[`io::stdio`](https://doc.rust-lang.org/std/io/stdio/).
-On the other hand,
-[`io::net`](https://doc.rust-lang.org/std/io/net/)
-contains submodules, so it lives in a separate directory:
-
-```text
-io/mod.rs
- io/extensions.rs
- io/fs.rs
- io/net/mod.rs
- io/net/addrinfo.rs
- io/net/ip.rs
- io/net/tcp.rs
- io/net/udp.rs
- io/net/unix.rs
- io/pipe.rs
- ...
-```
-
-While it is possible to define all of `io` within a single directory,
-mirroring the module hierarchy in the directory structure makes
-submodules of `io::net` easier to find.
-
-### Consider top-level definitions or reexports. [FIXME: needs RFC]
-
-For modules with submodules,
-define or [reexport](https://doc.rust-lang.org/std/io/#reexports) commonly used
-definitions at the top level:
-
-* Functionality relevant to the module itself or to many of its
- children should be defined in `mod.rs`.
-* Functionality specific to a submodule should live in that
- submodule. Reexport at the top level for the most important or
- common definitions.
-
-For example,
-[`IoError`](https://doc.rust-lang.org/std/io/struct.IoError.html)
-is defined in `io/mod.rs`, since it pertains to the entirety of `io`,
-while
-[`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
-is defined in `io/net/tcp.rs` and reexported in the `io` module.
-
-### Use internal module hierarchies for organization. [FIXME: needs RFC]
-
-> **[FIXME]**
-> - Referencing internal modules from the standard library is subject to
-> becoming outdated.
-
-Internal module hierarchies (i.e., private submodules) may be used to
-hide implementation details that are not part of the module's API.
-
-For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem`
-provides implementations for
-[`BufReader`](https://doc.rust-lang.org/std/io/struct.BufReader.html)
-and
-[`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html),
-but these are re-exported in `io/mod.rs` at the top level of the module:
-
-```rust,ignore
-// libstd/io/mod.rs
-
-pub use self::mem::{MemReader, BufReader, MemWriter, BufWriter};
-/* ... */
-mod mem;
-```
-
-This hides the detail that there even exists a `mod mem` in `io`, and
-helps keep code organized while offering freedom to change the
-implementation.
+++ /dev/null
-% Traits
-
-Traits are probably Rust's most complex feature, supporting a wide range of use
-cases and design tradeoffs. Patterns of trait usage are still emerging.
-
-### Know whether a trait will be used as an object. [FIXME: needs RFC]
-
-Trait objects have some [significant limitations](objects.md): methods
-invoked through a trait object cannot use generics, and cannot use
-`Self` except in receiver position.
-
-When designing a trait, decide early on whether the trait will be used
-as an [object](objects.md) or as a [bound on generics](generics.md);
-the tradeoffs are discussed in each of the linked sections.
-
-If a trait is meant to be used as an object, its methods should take
-and return trait objects rather than use generics.
-
-
-### Default methods [FIXME]
-
-> **[FIXME]** Guidelines for default methods.
+++ /dev/null
-% Common traits
-
-### Eagerly implement common traits. [FIXME: needs RFC]
-
-Rust's trait system does not allow _orphans_: roughly, every `impl` must live
-either in the crate that defines the trait or the implementing
-type. Consequently, crates that define new types should eagerly implement all
-applicable, common traits.
-
-To see why, consider the following situation:
-
-* Crate `std` defines trait `Debug`.
-* Crate `url` defines type `Url`, without implementing `Debug`.
-* Crate `webapp` imports from both `std` and `url`,
-
-There is no way for `webapp` to add `Debug` to `url`, since it defines neither.
-(Note: the newtype pattern can provide an efficient, but inconvenient
-workaround; see [newtype for views](../types/newtype.md))
-
-The most important common traits to implement from `std` are:
-
-```text
-Clone, Debug, Hash, Eq
-```
-
-#### When safe, derive or otherwise implement `Send` and `Share`. [FIXME]
-
-> **[FIXME]**. This guideline is in flux while the "opt-in" nature of
-> built-in traits is being decided. See https://github.com/rust-lang/rfcs/pull/127
-
-### Prefer to derive, rather than implement. [FIXME: needs RFC]
-
-Deriving saves implementation effort, makes correctness trivial, and
-automatically adapts to upstream changes.
-
-### Do not overload operators in surprising ways. [FIXME: needs RFC]
-
-Operators with built in syntax (`*`, `|`, and so on) can be provided for a type
-by implementing the traits in `core::ops`. These operators come with strong
-expectations: implement `Mul` only for an operation that bears some resemblance
-to multiplication (and shares the expected properties, e.g. associativity), and
-so on for the other traits.
-
-### The `Drop` trait
-
-The `Drop` trait is treated specially by the compiler as a way of
-associating destructors with types. See
-[the section on destructors](../../ownership/destructors.md) for
-guidance.
-
-### The `Deref`/`DerefMut` traits
-
-#### Use `Deref`/`DerefMut` only for smart pointers. [FIXME: needs RFC]
-
-The `Deref` traits are used implicitly by the compiler in many circumstances,
-and interact with method resolution. The relevant rules are designed
-specifically to accommodate smart pointers, and so the traits should be used
-only for that purpose.
-
-#### Do not fail within a `Deref`/`DerefMut` implementation. [FIXME: needs RFC]
-
-Because the `Deref` traits are invoked implicitly by the compiler in sometimes
-subtle ways, failure during dereferencing can be extremely confusing. If a
-dereference might not succeed, target the `Deref` trait as a `Result` or
-`Option` type instead.
-
-#### Avoid inherent methods when implementing `Deref`/`DerefMut` [FIXME: needs RFC]
-
-The rules around method resolution and `Deref` are in flux, but inherent methods
-on a type implementing `Deref` are likely to shadow any methods of the referent
-with the same name.
+++ /dev/null
-% Using traits to add extension methods
-
-> **[FIXME]** Elaborate.
-
-### Consider using default methods rather than extension traits **[FIXME]**
-
-> **[FIXME]** Elaborate.
+++ /dev/null
-% Using traits for bounds on generics
-
-The most widespread use of traits is for writing generic functions or types. For
-example, the following signature describes a function for consuming any iterator
-yielding items of type `A` to produce a collection of `A`:
-
-```rust,ignore
-fn from_iter<T: Iterator<A>>(iterator: T) -> SomeCollection<A>
-```
-
-Here, the `Iterator` trait specifies an interface that a type `T` must
-explicitly implement to be used by this generic function.
-
-**Pros**:
-
-* _Reusability_. Generic functions can be applied to an open-ended collection of
- types, while giving a clear contract for the functionality those types must
- provide.
-* _Static dispatch and optimization_. Each use of a generic function is
- specialized ("monomorphized") to the particular types implementing the trait
- bounds, which means that (1) invocations of trait methods are static, direct
- calls to the implementation and (2) the compiler can inline and otherwise
- optimize these calls.
-* _Inline layout_. If a `struct` and `enum` type is generic over some type
- parameter `T`, values of type `T` will be laid out _inline_ in the
- `struct`/`enum`, without any indirection.
-* _Inference_. Since the type parameters to generic functions can usually be
- inferred, generic functions can help cut down on verbosity in code where
- explicit conversions or other method calls would usually be necessary. See the
- overloading/implicits use case below.
-* _Precise types_. Because generics give a _name_ to the specific type
- implementing a trait, it is possible to be precise about places where that
- exact type is required or produced. For example, a function
-
- ```rust,ignore
- fn binary<T: Trait>(x: T, y: T) -> T
- ```
-
- is guaranteed to consume and produce elements of exactly the same type `T`; it
- cannot be invoked with parameters of different types that both implement
- `Trait`.
-
-**Cons**:
-
-* _Code size_. Specializing generic functions means that the function body is
- duplicated. The increase in code size must be weighed against the performance
- benefits of static dispatch.
-* _Homogeneous types_. This is the other side of the "precise types" coin: if
- `T` is a type parameter, it stands for a _single_ actual type. So for example
- a `Vec<T>` contains elements of a single concrete type (and, indeed, the
- vector representation is specialized to lay these out in line). Sometimes
- heterogeneous collections are useful; see
- trait objects below.
-* _Signature verbosity_. Heavy use of generics can bloat function signatures.
- **[Ed. note]** This problem may be mitigated by some language improvements; stay tuned.
-
-### Favor widespread traits. **[FIXME: needs RFC]**
-
-Generic types are a form of abstraction, which entails a mental indirection: if
-a function takes an argument of type `T` bounded by `Trait`, clients must first
-think about the concrete types that implement `Trait` to understand how and when
-the function is callable.
-
-To keep the cost of abstraction low, favor widely-known traits. Whenever
-possible, implement and use traits provided as part of the standard library. Do
-not introduce new traits for generics lightly; wait until there are a wide range
-of types that can implement the type.
+++ /dev/null
-% Using trait objects
-
-> **[FIXME]** What are uses of trait objects other than heterogeneous collections?
-
-Trait objects are useful primarily when _heterogeneous_ collections of objects
-need to be treated uniformly; it is the closest that Rust comes to
-object-oriented programming.
-
-```rust,ignore
-struct Frame { ... }
-struct Button { ... }
-struct Label { ... }
-
-trait Widget { ... }
-
-impl Widget for Frame { ... }
-impl Widget for Button { ... }
-impl Widget for Label { ... }
-
-impl Frame {
- fn new(contents: &[Box<Widget>]) -> Frame {
- ...
- }
-}
-
-fn make_gui() -> Box<Widget> {
- let b: Box<Widget> = box Button::new(...);
- let l: Box<Widget> = box Label::new(...);
-
- box Frame::new([b, l]) as Box<Widget>
-}
-```
-
-By using trait objects, we can set up a GUI framework with a `Frame` widget that
-contains a heterogeneous collection of children widgets.
-
-**Pros**:
-
-* _Heterogeneity_. When you need it, you really need it.
-* _Code size_. Unlike generics, trait objects do not generate specialized
- (monomorphized) versions of code, which can greatly reduce code size.
-
-**Cons**:
-
-* _No generic methods_. Trait objects cannot currently provide generic methods.
-* _Dynamic dispatch and fat pointers_. Trait objects inherently involve
- indirection and vtable dispatch, which can carry a performance penalty.
-* _No Self_. Except for the method receiver argument, methods on trait objects
- cannot use the `Self` type.
+++ /dev/null
-% Using traits for overloading
-
-> **[FIXME]** Elaborate.
-
-> **[FIXME]** We need to decide on guidelines for this use case. There are a few
-> patterns emerging in current Rust code, but it's not clear how widespread they
-> should be.
+++ /dev/null
-% Using traits to share implementations
-
-> **[FIXME]** Elaborate.
-
-> **[FIXME]** We probably want to discourage this, at least when used in a way
-> that is publicly exposed.
-
-Traits that provide default implementations for function can provide code reuse
-across types. For example, a `print` method can be defined across multiple
-types as follows:
-
-``` Rust
-trait Printable {
- // Default method implementation
- fn print(&self) { println!("{:?}", *self) }
-}
-
-impl Printable for i32 {}
-
-impl Printable for String {
- fn print(&self) { println!("{}", *self) }
-}
-
-impl Printable for bool {}
-
-impl Printable for f32 {}
-```
-
-This allows the implementation of `print` to be shared across types, yet
-overridden where needed, as seen in the `impl` for `String`.
+++ /dev/null
-% Data types
-
-### Use custom types to imbue meaning; do not abuse `bool`, `Option` or other core types. **[FIXME: needs RFC]**
-
-Prefer
-
-```rust,ignore
-let w = Widget::new(Small, Round)
-```
-
-over
-
-```rust,ignore
-let w = Widget::new(true, false)
-```
-
-Core types like `bool`, `u8` and `Option` have many possible interpretations.
-
-Use custom types (whether `enum`s, `struct`, or tuples) to convey
-interpretation and invariants. In the above example,
-it is not immediately clear what `true` and `false` are conveying without
-looking up the argument names, but `Small` and `Round` are more suggestive.
-
-Using custom types makes it easier to expand the
-options later on, for example by adding an `ExtraLarge` variant.
-
-See [the newtype pattern](newtype.md) for a no-cost way to wrap
-existing types with a distinguished name.
-
-### Prefer private fields, except for passive data. **[FIXME: needs RFC]**
-
-Making a field public is a strong commitment: it pins down a representation
-choice, _and_ prevents the type from providing any validation or maintaining any
-invariants on the contents of the field, since clients can mutate it arbitrarily.
-
-Public fields are most appropriate for `struct` types in the C spirit: compound,
-passive data structures. Otherwise, consider providing getter/setter methods
-and hiding fields instead.
-
-> **[FIXME]** Cross-reference validation for function arguments.
-
-### Use custom `enum`s for alternatives, `bitflags` for C-style flags. **[FIXME: needs RFC]**
-
-Rust supports `enum` types with "custom discriminants":
-
-~~~~
-enum Color {
- Red = 0xff0000,
- Green = 0x00ff00,
- Blue = 0x0000ff
-}
-~~~~
-
-Custom discriminants are useful when an `enum` type needs to be serialized to an
-integer value compatibly with some other system/language. They support
-"typesafe" APIs: by taking a `Color`, rather than an integer, a function is
-guaranteed to get well-formed inputs, even if it later views those inputs as
-integers.
-
-An `enum` allows an API to request exactly one choice from among many. Sometimes
-an API's input is instead the presence or absence of a set of flags. In C code,
-this is often done by having each flag correspond to a particular bit, allowing
-a single integer to represent, say, 32 or 64 flags. Rust's `std::bitflags`
-module provides a typesafe way for doing so.
-
-### Phantom types. [FIXME]
-
-> **[FIXME]** Add some material on phantom types (https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/)
+++ /dev/null
-% Conversions between types
-
-### Associate conversions with the most specific type involved. **[FIXME: needs RFC]**
-
-When in doubt, prefer `to_`/`as_`/`into_` to `from_`, because they are
-more ergonomic to use (and can be chained with other methods).
-
-For many conversions between two types, one of the types is clearly more
-"specific": it provides some additional invariant or interpretation that is not
-present in the other type. For example, `str` is more specific than `&[u8]`,
-since it is a utf-8 encoded sequence of bytes.
-
-Conversions should live with the more specific of the involved types. Thus,
-`str` provides both the `as_bytes` method and the `from_utf8` constructor for
-converting to and from `&[u8]` values. Besides being intuitive, this convention
-avoids polluting concrete types like `&[u8]` with endless conversion methods.
-
-### Explicitly mark lossy conversions, or do not label them as conversions. **[FIXME: needs RFC]**
-
-If a function's name implies that it is a conversion (prefix `from_`, `as_`,
-`to_` or `into_`), but the function loses information, add a suffix `_lossy` or
-otherwise indicate the lossyness. Consider avoiding the conversion name prefix.
+++ /dev/null
-% The newtype pattern
-
-A "newtype" is a tuple or `struct` with a single field. The terminology is borrowed from Haskell.
-
-Newtypes are a zero-cost abstraction: they introduce a new, distinct name for an
-existing type, with no runtime overhead when converting between the two types.
-
-### Use newtypes to provide static distinctions. [FIXME: needs RFC]
-
-Newtypes can statically distinguish between different interpretations of an
-underlying type.
-
-For example, a `f64` value might be used to represent a quantity in miles or in
-kilometers. Using newtypes, we can keep track of the intended interpretation:
-
-```rust,ignore
-struct Miles(pub f64);
-struct Kilometers(pub f64);
-
-impl Miles {
- fn as_kilometers(&self) -> Kilometers { ... }
-}
-impl Kilometers {
- fn as_miles(&self) -> Miles { ... }
-}
-```
-
-Once we have separated these two types, we can statically ensure that we do not
-confuse them. For example, the function
-
-```rust,ignore
-fn are_we_there_yet(distance_travelled: Miles) -> bool { ... }
-```
-
-cannot accidentally be called with a `Kilometers` value. The compiler will
-remind us to perform the conversion, thus averting certain
-[catastrophic bugs](http://en.wikipedia.org/wiki/Mars_Climate_Orbiter).
-
-### Use newtypes with private fields for hiding. [FIXME: needs RFC]
-
-A newtype can be used to hide representation details while making precise
-promises to the client.
-
-For example, consider a function `my_transform` that returns a compound iterator
-type `Enumerate<Skip<vec::MoveItems<T>>>`. We wish to hide this type from the
-client, so that the client's view of the return type is roughly `Iterator<(usize,
-T)>`. We can do so using the newtype pattern:
-
-```rust,ignore
-struct MyTransformResult<T>(Enumerate<Skip<vec::MoveItems<T>>>);
-impl<T> Iterator<(usize, T)> for MyTransformResult<T> { ... }
-
-fn my_transform<T, Iter: Iterator<T>>(iter: Iter) -> MyTransformResult<T> {
- ...
-}
-```
-
-Aside from simplifying the signature, this use of newtypes allows us to make a
-expose and promise less to the client. The client does not know _how_ the result
-iterator is constructed or represented, which means the representation can
-change in the future without breaking client code.
-
-> **[FIXME]** Interaction with auto-deref.
-
-### Use newtypes to provide cost-free _views_ of another type. **[FIXME]**
-
-> **[FIXME]** Describe the pattern of using newtypes to provide a new set of
-> inherent or trait methods, providing a different perspective on the underlying
-> type.
+++ /dev/null
-% Ownership and resource management
-
-> **[FIXME]** Add general remarks about ownership/resources here.
+++ /dev/null
-% The builder pattern
-
-Some data structures are complicated to construct, due to their construction needing:
-
-* a large number of inputs
-* compound data (e.g. slices)
-* optional configuration data
-* choice between several flavors
-
-which can easily lead to a large number of distinct constructors with
-many arguments each.
-
-If `T` is such a data structure, consider introducing a `T` _builder_:
-
-1. Introduce a separate data type `TBuilder` for incrementally configuring a `T`
- value. When possible, choose a better name: e.g. `Command` is the builder for
- `Process`.
-2. The builder constructor should take as parameters only the data _required_ to
- make a `T`.
-3. The builder should offer a suite of convenient methods for configuration,
- including setting up compound inputs (like slices) incrementally.
- These methods should return `self` to allow chaining.
-4. The builder should provide one or more "_terminal_" methods for actually building a `T`.
-
-The builder pattern is especially appropriate when building a `T` involves side
-effects, such as spawning a thread or launching a process.
-
-In Rust, there are two variants of the builder pattern, differing in the
-treatment of ownership, as described below.
-
-### Non-consuming builders (preferred):
-
-In some cases, constructing the final `T` does not require the builder itself to
-be consumed. The follow variant on
-[`std::process::Command`](https://doc.rust-lang.org/stable/std/process/struct.Command.html)
-is one example:
-
-```rust,ignore
-// NOTE: the actual Command API does not use owned Strings;
-// this is a simplified version.
-
-pub struct Command {
- program: String,
- args: Vec<String>,
- cwd: Option<String>,
- // etc
-}
-
-impl Command {
- pub fn new(program: String) -> Command {
- Command {
- program: program,
- args: Vec::new(),
- cwd: None,
- }
- }
-
- /// Add an argument to pass to the program.
- pub fn arg<'a>(&'a mut self, arg: String) -> &'a mut Command {
- self.args.push(arg);
- self
- }
-
- /// Add multiple arguments to pass to the program.
- pub fn args<'a>(&'a mut self, args: &[String])
- -> &'a mut Command {
- self.args.push_all(args);
- self
- }
-
- /// Set the working directory for the child process.
- pub fn cwd<'a>(&'a mut self, dir: String) -> &'a mut Command {
- self.cwd = Some(dir);
- self
- }
-
- /// Executes the command as a child process, which is returned.
- pub fn spawn(&self) -> std::io::Result<Process> {
- ...
- }
-}
-```
-
-Note that the `spawn` method, which actually uses the builder configuration to
-spawn a process, takes the builder by immutable reference. This is possible
-because spawning the process does not require ownership of the configuration
-data.
-
-Because the terminal `spawn` method only needs a reference, the configuration
-methods take and return a mutable borrow of `self`.
-
-#### The benefit
-
-By using borrows throughout, `Command` can be used conveniently for both
-one-liner and more complex constructions:
-
-```rust,ignore
-// One-liners
-Command::new("/bin/cat").arg("file.txt").spawn();
-
-// Complex configuration
-let mut cmd = Command::new("/bin/ls");
-cmd.arg(".");
-
-if size_sorted {
- cmd.arg("-S");
-}
-
-cmd.spawn();
-```
-
-### Consuming builders:
-
-Sometimes builders must transfer ownership when constructing the final type
-`T`, meaning that the terminal methods must take `self` rather than `&self`:
-
-```rust,ignore
-// A simplified excerpt from std::thread::Builder
-
-impl ThreadBuilder {
- /// Name the thread-to-be. Currently the name is used for identification
- /// only in failure messages.
- pub fn named(mut self, name: String) -> ThreadBuilder {
- self.name = Some(name);
- self
- }
-
- /// Redirect thread-local stdout.
- pub fn stdout(mut self, stdout: Box<Writer + Send>) -> ThreadBuilder {
- self.stdout = Some(stdout);
- // ^~~~~~ this is owned and cannot be cloned/re-used
- self
- }
-
- /// Creates and executes a new child thread.
- pub fn spawn(self, f: proc():Send) {
- // consume self
- ...
- }
-}
-```
-
-Here, the `stdout` configuration involves passing ownership of a `Writer`,
-which must be transferred to the thread upon construction (in `spawn`).
-
-When the terminal methods of the builder require ownership, there is a basic tradeoff:
-
-* If the other builder methods take/return a mutable borrow, the complex
- configuration case will work well, but one-liner configuration becomes
- _impossible_.
-
-* If the other builder methods take/return an owned `self`, one-liners
- continue to work well but complex configuration is less convenient.
-
-Under the rubric of making easy things easy and hard things possible, _all_
-builder methods for a consuming builder should take and returned an owned
-`self`. Then client code works as follows:
-
-```rust,ignore
-// One-liners
-ThreadBuilder::new().named("my_thread").spawn(proc() { ... });
-
-// Complex configuration
-let mut thread = ThreadBuilder::new();
-thread = thread.named("my_thread_2"); // must re-assign to retain ownership
-
-if reroute {
- thread = thread.stdout(mywriter);
-}
-
-thread.spawn(proc() { ... });
-```
-
-One-liners work as before, because ownership is threaded through each of the
-builder methods until being consumed by `spawn`. Complex configuration,
-however, is more verbose: it requires re-assigning the builder at each step.
+++ /dev/null
-% Cells and smart pointers
-
-> **[FIXME]** Add guidelines about when to use Cell, RefCell, Rc and
-> Arc (and how to use them together).
+++ /dev/null
-% Constructors
-
-### Define constructors as static, inherent methods. [FIXME: needs RFC]
-
-In Rust, "constructors" are just a convention:
-
-```rust,ignore
-impl<T> Vec<T> {
- pub fn new() -> Vec<T> { ... }
-}
-```
-
-Constructors are static (no `self`) inherent methods for the type that they
-construct. Combined with the practice of
-[fully importing type names](../style/imports.md), this convention leads to
-informative but concise construction:
-
-```rust,ignore
-use vec::Vec;
-
-// construct a new vector
-let mut v = Vec::new();
-```
-
-This convention also applied to conversion constructors (prefix `from` rather
-than `new`).
-
-### Provide constructors for passive `struct`s with defaults. [FIXME: needs RFC]
-
-Given the `struct`
-
-```rust,ignore
-pub struct Config {
- pub color: Color,
- pub size: Size,
- pub shape: Shape,
-}
-```
-
-provide a constructor if there are sensible defaults:
-
-```rust,ignore
-impl Config {
- pub fn new() -> Config {
- Config {
- color: Brown,
- size: Medium,
- shape: Square,
- }
- }
-}
-```
-
-which then allows clients to concisely override using `struct` update syntax:
-
-```rust,ignore
-Config { color: Red, .. Config::new() };
-```
-
-See the [guideline for field privacy](../features/types/README.md) for
-discussion on when to create such "passive" `struct`s with public
-fields.
+++ /dev/null
-% Destructors
-
-Unlike constructors, destructors in Rust have a special status: they are added
-by implementing `Drop` for a type, and they are automatically invoked as values
-go out of scope.
-
-> **[FIXME]** This section needs to be expanded.
-
-### Destructors should not fail. [FIXME: needs RFC]
-
-Destructors are executed on thread failure, and in that context a failing
-destructor causes the program to abort.
-
-Instead of failing in a destructor, provide a separate method for checking for
-clean teardown, e.g. a `close` method, that returns a `Result` to signal
-problems.
-
-### Destructors should not block. [FIXME: needs RFC]
-
-Similarly, destructors should not invoke blocking operations, which can make
-debugging much more difficult. Again, consider providing a separate method for
-preparing for an infallible, nonblocking teardown.
+++ /dev/null
-% RAII
-
-Resource Acquisition is Initialization
-
-> **[FIXME]** Explain the RAII pattern and give best practices.
-
-### Whenever possible, tie resource access to guard scopes [FIXME]
-
-> **[FIXME]** Example: Mutex guards guarantee that access to the
-> protected resource only happens when the guard is in scope.
-
-`must_use`
+++ /dev/null
-% FFI and platform-specific code **[FIXME]**
-
-> **[FIXME]** Not sure where this should live.
-
-When writing cross-platform code, group platform-specific code into a
-module called `platform`. Avoid `#[cfg]` directives outside this
-`platform` module.
+++ /dev/null
-% Safety and guarantees
-
-> **[FIXME]** Is there a better phrase than "strong guarantees" that encompasses
-> both e.g. memory safety and e.g. data structure invariants?
-
-A _guarantee_ is a property that holds no matter what client code does, unless
-the client explicitly opts out:
-
-* Rust guarantees memory safety and data-race freedom, with `unsafe`
- blocks as an opt-out mechanism.
-
-* APIs in Rust often provide their own guarantees. For example, `std::str`
-guarantees that its underlying buffer is valid utf-8. The `std::path::Path` type
-guarantees no interior nulls. Both strings and paths provide `unsafe` mechanisms
-for opting out of these guarantees (and thereby avoiding runtime checks).
-
-Thinking about guarantees is an essential part of writing good Rust code. The
-rest of this subsection outlines some cross-cutting principles around
-guarantees.
+++ /dev/null
-% Library-level guarantees
-
-Most libraries rely on internal invariants, e.g. about their data, resource
-ownership, or protocol states. In Rust, broken invariants cannot produce
-segfaults, but they can still lead to wrong answers.
-
-### Provide library-level guarantees whenever practical. **[FIXME: needs RFC]**
-
-Library-level invariants should be turned into guarantees whenever
-practical. They should hold no matter what the client does, modulo
-explicit opt-outs. Depending on the kind of invariant, this can be
-achieved through a combination of static and dynamic enforcement, as
-described below.
-
-#### Static enforcement:
-
-Guaranteeing invariants almost always requires _hiding_,
-i.e. preventing the client from directly accessing or modifying
-internal data.
-
-For example, the representation of the `str` type is hidden,
-which means that any value of type `str` must have been produced
-through an API under the control of the `str` module, and these
-APIs in turn ensure valid utf-8 encoding.
-
-Rust's type system makes it possible to provide guarantees even while
-revealing more of the representation than usual. For example, the
-`as_bytes()` method on `&str` gives a _read-only_ view into the
-underlying buffer, which cannot be used to violate the utf-8 property.
-
-#### Dynamic enforcement:
-
-Malformed inputs from the client are hazards to library-level
-guarantees, so library APIs should validate their input.
-
-For example, `std::str::from_utf8_owned` attempts to convert a `u8`
-slice into an owned string, but dynamically checks that the slice is
-valid utf-8 and returns `Err` if not.
-
-See
-[the discussion on input validation](../features/functions-and-methods/input.md)
-for more detail.
-
-
-### Prefer static enforcement of guarantees. **[FIXME: needs RFC]**
-
-Static enforcement provides two strong benefits over dynamic enforcement:
-
-* Bugs are caught at compile time.
-* There is no runtime cost.
-
-Sometimes purely static enforcement is impossible or impractical. In these
-cases, a library should check as much as possible statically, but defer to
-dynamic checks where needed.
-
-For example, the `std::string` module exports a `String` type with the guarantee
-that all instances are valid utf-8:
-
-* Any _consumer_ of a `String` is statically guaranteed utf-8 contents. For example,
- the `append` method can push a `&str` onto the end of a `String` without
- checking anything dynamically, since the existing `String` and `&str` are
- statically guaranteed to be in utf-8.
-
-* Some _producers_ of a `String` must perform dynamic checks. For example, the
- `from_utf8` function attempts to convert a `Vec<u8>` into a `String`, but
- dynamically checks that the contents are utf-8.
-
-### Provide opt-outs with caution; make them explicit. **[FIXME: needs RFC]**
-
-Providing library-level guarantees sometimes entails inconvenience (for static
-checks) or overhead (for dynamic checks). So it is sometimes desirable to allow
-clients to sidestep this checking, while promising to use the API in a way that
-still provides the guarantee. Such escape hatches should only be introduced when
-there is a demonstrated need for them.
-
-It should be trivial for clients to audit their use of the library for
-escape hatches.
-
-See
-[the discussion on input validation](../features/functions-and-methods/input.md)
-for conventions on marking opt-out functions.
+++ /dev/null
-% Using `unsafe`
-
-### Unconditionally guarantee safety, or mark API as `unsafe`. **[FIXME: needs RFC]**
-
-Memory safety, type safety, and data race freedom are basic assumptions for all
-Rust code.
-
-APIs that use `unsafe` blocks internally thus have two choices:
-
-* They can guarantee safety _unconditionally_ (i.e., regardless of client
- behavior or inputs) and be exported as safe code. Any safety violation is then
- the library's fault, not the client's fault.
-
-* They can export potentially unsafe functions with the `unsafe` qualifier. In
- this case, the documentation should make very clear the conditions under which
- safety is guaranteed.
-
-The result is that a client program can never violate safety merely by having a
-bug; it must have explicitly opted out by using an `unsafe` block.
-
-Of the two options for using `unsafe`, creating such safe abstractions (the
-first option above) is strongly preferred.
+++ /dev/null
-% Style
-
-This section gives a set of strict rules for styling Rust code.
-
-> **[FIXME]** General remarks about the style guidelines
+++ /dev/null
-% Braces, semicolons, and commas [FIXME: needs RFC]
-
-### Opening braces always go on the same line.
-
-```rust,ignore
-fn foo() {
- ...
-}
-
-fn frobnicate(a: Bar, b: Bar,
- c: Bar, d: Bar)
- -> Bar {
- ...
-}
-
-trait Bar {
- fn baz(&self);
-}
-
-impl Bar for Baz {
- fn baz(&self) {
- ...
- }
-}
-
-frob(|x| {
- x.transpose()
-})
-```
-
-### `match` arms get braces, except for single-line expressions.
-
-```rust,ignore
-match foo {
- bar => baz,
- quux => {
- do_something();
- do_something_else()
- }
-}
-```
-
-### `return` statements get semicolons.
-
-```rust,ignore
-fn foo() {
- do_something();
-
- if condition() {
- return;
- }
-
- do_something_else();
-}
-```
-
-### Trailing commas
-
-> **[FIXME]** We should have a guideline for when to include trailing
-> commas in `struct`s, `match`es, function calls, etc.
->
-> One possible rule: a trailing comma should be included whenever the
-> closing delimiter appears on a separate line:
-
-```rust,ignore
-Foo { bar: 0, baz: 1 }
-
-Foo {
- bar: 0,
- baz: 1,
-}
-
-match a_thing {
- None => 0,
- Some(x) => 1,
-}
-```
+++ /dev/null
-% Comments [RFC #505]
-
-### Avoid block comments.
-
-Use line comments:
-
-```rust
-// Wait for the main thread to return, and set the process error code
-// appropriately.
-```
-
-Instead of:
-
-``` rust
-/*
- * Wait for the main thread to return, and set the process error code
- * appropriately.
- */
-```
-
-## Doc comments
-
-Doc comments are prefixed by three slashes (`///`) and indicate
-documentation that you would like to be included in Rustdoc's output.
-They support
-[Markdown syntax](https://en.wikipedia.org/wiki/Markdown)
-and are the main way of documenting your public APIs.
-
-The supported markdown syntax includes all of the extensions listed in the
-[GitHub Flavored Markdown]
-(https://help.github.com/articles/github-flavored-markdown) documentation,
-plus superscripts.
-
-### Summary line
-
-The first line in any doc comment should be a single-line short sentence
-providing a summary of the code. This line is used as a short summary
-description throughout Rustdoc's output, so it's a good idea to keep it
-short.
-
-### Sentence structure
-
-All doc comments, including the summary line, should begin with a
-capital letter and end with a period, question mark, or exclamation
-point. Prefer full sentences to fragments.
-
-The summary line should be written in
-[third person singular present indicative form]
-(http://en.wikipedia.org/wiki/English_verbs#Third_person_singular_present).
-Basically, this means write "Returns" instead of "Return".
-
-For example:
-
-```rust,ignore
-/// Sets up a default runtime configuration, given compiler-supplied arguments.
-///
-/// This function will block until the entire pool of M:N schedulers has
-/// exited. This function also requires a local thread to be available.
-///
-/// # Arguments
-///
-/// * `argc` & `argv` - The argument vector. On Unix this information is used
-/// by `os::args`.
-/// * `main` - The initial procedure to run inside of the M:N scheduling pool.
-/// Once this procedure exits, the scheduling pool will begin to shut
-/// down. The entire pool (and this function) will only return once
-/// all child threads have finished executing.
-///
-/// # Return value
-///
-/// The return value is used as the process return code. 0 on success, 101 on
-/// error.
-```
-
-### Code snippets
-
-Only use inner doc comments `//!` to write crate and module-level documentation,
-nothing else. When using `mod` blocks, prefer `///` outside of the block:
-
-```rust
-/// This module contains tests
-mod test {
- // ...
-}
-```
-
-over
-
-```rust
-mod test {
- //! This module contains tests
-
- // ...
-}
-```
-
-### Avoid inner doc comments.
-
-Use inner doc comments _only_ to document crates and file-level modules:
-
-```rust,ignore
-//! The core library.
-//!
-//! The core library is a something something...
-```
-
-### Explain context.
-
-Rust doesn't have special constructors, only functions that return new
-instances. These aren't visible in the automatically generated documentation
-for a type, so you should specifically link to them:
-
-```rust,ignore
-/// An iterator that yields `None` forever after the underlying iterator
-/// yields `None` once.
-///
-/// These can be created through
-/// [`iter.fuse()`](trait.Iterator.html#method.fuse).
-pub struct Fuse<I> {
- // ...
-}
-```
+++ /dev/null
-## `return` [RFC #968]
-
-Terminate `return` statements with semicolons:
-
-``` rust,ignore
-fn foo(bar: i32) -> Option<i32> {
- if some_condition() {
- return None;
- }
-
- ...
-}
-```
+++ /dev/null
-% Imports [FIXME: needs RFC]
-
-The imports of a crate/module should consist of the following
-sections, in order, with a blank space between each:
-
-* `extern crate` directives
-* external `use` imports
-* local `use` imports
-* `pub use` imports
-
-For example:
-
-```rust,ignore
-// Crates.
-extern crate getopts;
-extern crate mylib;
-
-// Standard library imports.
-use getopts::{optopt, getopts};
-use std::os;
-
-// Import from a library that we wrote.
-use mylib::webserver;
-
-// Will be reexported when we import this module.
-pub use self::types::Webdata;
-```
-
-### Avoid `use *`, except in tests.
-
-Glob imports have several downsides:
-* They make it harder to tell where names are bound.
-* They are forwards-incompatible, since new upstream exports can clash
- with existing names.
-
-When writing a [`test` submodule](../testing/README.md), importing `super::*` is appropriate
-as a convenience.
-
-### Prefer fully importing types/traits while module-qualifying functions.
-
-For example:
-
-```rust,ignore
-use option::Option;
-use mem;
-
-let i: isize = mem::transmute(Option(0));
-```
-
-> **[FIXME]** Add rationale.
+++ /dev/null
-% Naming conventions
-
-### General conventions [RFC #430]
-
-> The guidelines below were approved by [RFC #430](https://github.com/rust-lang/rfcs/pull/430).
-
-In general, Rust tends to use `CamelCase` for "type-level" constructs
-(types and traits) and `snake_case` for "value-level" constructs. More
-precisely:
-
-| Item | Convention |
-| ---- | ---------- |
-| Crates | `snake_case` (but prefer single word) |
-| Modules | `snake_case` |
-| Types | `CamelCase` |
-| Traits | `CamelCase` |
-| Enum variants | `CamelCase` |
-| Functions | `snake_case` |
-| Methods | `snake_case` |
-| General constructors | `new` or `with_more_details` |
-| Conversion constructors | `from_some_other_type` |
-| Local variables | `snake_case` |
-| Static variables | `SCREAMING_SNAKE_CASE` |
-| Constant variables | `SCREAMING_SNAKE_CASE` |
-| Type parameters | concise `CamelCase`, usually single uppercase letter: `T` |
-| Lifetimes | short, lowercase: `'a` |
-
-<p>
-In `CamelCase`, acronyms count as one word: use `Uuid` rather than
-`UUID`. In `snake_case`, acronyms are lower-cased: `is_xid_start`.
-
-In `snake_case` or `SCREAMING_SNAKE_CASE`, a "word" should never
-consist of a single letter unless it is the last "word". So, we have
-`btree_map` rather than `b_tree_map`, but `PI_2` rather than `PI2`.
-
-### Referring to types in function/method names [RFC 344]
-
-> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
-
-Function names often involve type names, the most common example being conversions
-like `as_slice`. If the type has a purely textual name (ignoring parameters), it
-is straightforward to convert between type conventions and function conventions:
-
-Type name | Text in methods
---------- | ---------------
-`String` | `string`
-`Vec<T>` | `vec`
-`YourType`| `your_type`
-
-Types that involve notation follow the convention below. There is some
-overlap on these rules; apply the most specific applicable rule:
-
-Type name | Text in methods
---------- | ---------------
-`&str` | `str`
-`&[T]` | `slice`
-`&mut [T]`| `mut_slice`
-`&[u8]` | `bytes`
-`&T` | `ref`
-`&mut T` | `mut`
-`*const T`| `ptr`
-`*mut T` | `mut_ptr`
-
-### Avoid redundant prefixes [RFC 356]
-
-> The guidelines below were approved by [RFC #356](https://github.com/rust-lang/rfcs/pull/356).
-
-Names of items within a module should not be prefixed with that module's name:
-
-Prefer
-
-```rust,ignore
-mod foo {
- pub struct Error { ... }
-}
-```
-
-over
-
-```rust,ignore
-mod foo {
- pub struct FooError { ... }
-}
-```
-
-This convention avoids stuttering (like `io::IoError`). Library clients can
-rename on import to avoid clashes.
-
-### Getter/setter methods [RFC 344]
-
-> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
-
-Some data structures do not wish to provide direct access to their fields, but
-instead offer "getter" and "setter" methods for manipulating the field state
-(often providing checking or other functionality).
-
-The convention for a field `foo: T` is:
-
-* A method `foo(&self) -> &T` for getting the current value of the field.
-* A method `set_foo(&self, val: T)` for setting the field. (The `val` argument
- here may take `&T` or some other type, depending on the context.)
-
-Note that this convention is about getters/setters on ordinary data types, *not*
-on [builder objects](../../ownership/builders.html).
-
-### Escape hatches [FIXME]
-
-> **[FIXME]** Should we standardize a convention for functions that may break API
-> guarantees? e.g. `ToCStr::to_c_str_unchecked`
-
-### Predicates
-
-* Simple boolean predicates should be prefixed with `is_` or another
- short question word, e.g., `is_empty`.
-* Common exceptions: `lt`, `gt`, and other established predicate names.
+++ /dev/null
-% Common container/wrapper methods [FIXME: needs RFC]
-
-Containers, wrappers, and cells all provide ways to access the data
-they enclose. Accessor methods often have variants to access the data
-by value, by reference, and by mutable reference.
-
-In general, the `get` family of methods is used to access contained
-data without any risk of thread failure; they return `Option` as
-appropriate. This name is chosen rather than names like `find` or
-`lookup` because it is appropriate for a wider range of container types.
-
-#### Containers
-
-For a container with keys/indexes of type `K` and elements of type `V`:
-
-```rust,ignore
-// Look up element without failing
-fn get(&self, key: K) -> Option<&V>
-fn get_mut(&mut self, key: K) -> Option<&mut V>
-
-// Convenience for .get(key).map(|elt| elt.clone())
-fn get_clone(&self, key: K) -> Option<V>
-
-// Lookup element, failing if it is not found:
-impl Index<K, V> for Container { ... }
-impl IndexMut<K, V> for Container { ... }
-```
-
-#### Wrappers/Cells
-
-Prefer specific conversion functions like `as_bytes` or `into_vec` whenever
-possible. Otherwise, use:
-
-```rust,ignore
-// Extract contents without failing
-fn get(&self) -> &V
-fn get_mut(&mut self) -> &mut V
-fn unwrap(self) -> V
-```
-
-#### Wrappers/Cells around `Copy` data
-
-```rust,ignore
-// Extract contents without failing
-fn get(&self) -> V
-```
-
-#### `Option`-like types
-
-Finally, we have the cases of types like `Option` and `Result`, which
-play a special role for failure.
-
-For `Option<V>`:
-
-```rust,ignore
-// Extract contents or fail if not available
-fn assert(self) -> V
-fn expect(self, &str) -> V
-```
-
-For `Result<V, E>`:
-
-```rust,ignore
-// Extract the contents of Ok variant; fail if Err
-fn assert(self) -> V
-
-// Extract the contents of Err variant; fail if Ok
-fn assert_err(self) -> E
-```
+++ /dev/null
-% Conversions [Rust issue #7087]
-
-> The guidelines below were approved by [rust issue #7087](https://github.com/rust-lang/rust/issues/7087).
-
-> **[FIXME]** Should we provide standard traits for conversions? Doing
-> so nicely will require
-> [trait reform](https://github.com/rust-lang/rfcs/pull/48) to land.
-
-Conversions should be provided as methods, with names prefixed as follows:
-
-| Prefix | Cost | Consumes convertee |
-| ------ | ---- | ------------------ |
-| `as_` | Free | No |
-| `to_` | Expensive | No |
-| `into_` | Variable | Yes |
-
-<p>
-For example:
-
-* `as_bytes()` gives a `&[u8]` view into a `&str`, which is a no-op.
-* `to_owned()` copies a `&str` to a new `String`.
-* `into_bytes()` consumes a `String` and yields the underlying
- `Vec<u8>`, which is a no-op.
-
-Conversions prefixed `as_` and `into_` typically _decrease abstraction_, either
-exposing a view into the underlying representation (`as`) or deconstructing data
-into its underlying representation (`into`). Conversions prefixed `to_`, on the
-other hand, typically stay at the same level of abstraction but do some work to
-change one representation into another.
-
-> **[FIXME]** The distinctions between conversion methods does not work
-> so well for `from_` conversion constructors. Is that a problem?
+++ /dev/null
-% Iterators
-
-#### Method names [RFC #199]
-
-> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199).
-
-For a container with elements of type `U`, iterator methods should be named:
-
-```rust,ignore
-fn iter(&self) -> T // where T implements Iterator<&U>
-fn iter_mut(&mut self) -> T // where T implements Iterator<&mut U>
-fn into_iter(self) -> T // where T implements Iterator<U>
-```
-
-The default iterator variant yields shared references `&U`.
-
-#### Type names [RFC #344]
-
-> The guidelines below were approved by [RFC #344](https://github.com/rust-lang/rfcs/pull/344).
-
-The name of an iterator type should be the same as the method that
-produces the iterator.
-
-For example:
-
-* `iter` should yield an `Iter`
-* `iter_mut` should yield an `IterMut`
-* `into_iter` should yield an `IntoIter`
-* `keys` should yield `Keys`
-
-These type names make the most sense when prefixed with their owning module,
-e.g. `vec::IntoIter`.
+++ /dev/null
-% Ownership variants [RFC #199]
-
-> The guidelines below were approved by [RFC #199](https://github.com/rust-lang/rfcs/pull/199).
-
-Functions often come in multiple variants: immutably borrowed, mutably
-borrowed, and owned.
-
-The right default depends on the function in question. Variants should
-be marked through suffixes.
-
-#### Immutably borrowed by default
-
-If `foo` uses/produces an immutable borrow by default, use:
-
-* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.
-* The `_move` suffix (e.g. `foo_move`) for the owned variant.
-
-#### Owned by default
-
-If `foo` uses/produces owned data by default, use:
-
-* The `_ref` suffix (e.g. `foo_ref`) for the immutably borrowed variant.
-* The `_mut` suffix (e.g. `foo_mut`) for the mutably borrowed variant.
-
-#### Exceptions
-
-In the case of iterators, the moving variant can also be understood as
-an `into` conversion, `into_iter`, and `for x in v.into_iter()` reads
-arguably better than `for x in v.iter_move()`, so the convention is
-`into_iter`.
-
-For mutably borrowed variants, if the `mut` qualifier is part of a
-type name (e.g. `as_mut_slice`), it should appear as it would appear
-in the type.
+++ /dev/null
-% Organization [FIXME: needs RFC]
-
-> **[FIXME]** What else?
-
-### Reexport the most important types at the crate level.
-
-Crates `pub use` the most common types for convenience, so that clients do not
-have to remember or write the crate's module hierarchy to use these types.
-
-### Define types and operations together.
-
-Type definitions and the functions/methods that operate on them should be
-defined together in a single module, with the type appearing above the
-functions/methods.
+++ /dev/null
-% Whitespace [FIXME: needs RFC]
-
-* Lines must not exceed 99 characters.
-* Use 4 spaces for indentation, _not_ tabs.
-* No trailing whitespace at the end of lines or files.
-
-### Spaces
-
-* Use spaces around binary operators, including the equals sign in attributes:
-
-```rust,ignore
-#[deprecated = "Use `bar` instead."]
-fn foo(a: usize, b: usize) -> usize {
- a + b
-}
-```
-
-* Use a space after colons and commas:
-
-```rust,ignore
-fn foo(a: Bar);
-
-MyStruct { foo: 3, bar: 4 }
-
-foo(bar, baz);
-```
-
-* Use a space after the opening and before the closing brace for
- single line blocks or `struct` expressions:
-
-```rust,ignore
-spawn(proc() { do_something(); })
-
-Point { x: 0.1, y: 0.3 }
-```
-
-### Line wrapping
-
-* For multiline function signatures, each new line should align with the
- first parameter. Multiple parameters per line are permitted:
-
-```rust,ignore
-fn frobnicate(a: Bar, b: Bar,
- c: Bar, d: Bar)
- -> Bar {
- ...
-}
-
-fn foo<T: This,
- U: That>(
- a: Bar,
- b: Bar)
- -> Baz {
- ...
-}
-```
-
-* Multiline function invocations generally follow the same rule as for
- signatures. However, if the final argument begins a new block, the
- contents of the block may begin on a new line, indented one level:
-
-```rust,ignore
-fn foo_bar(a: Bar, b: Bar,
- c: |Bar|) -> Bar {
- ...
-}
-
-// Same line is fine:
-foo_bar(x, y, |z| { z.transpose(y) });
-
-// Indented body on new line is also fine:
-foo_bar(x, y, |z| {
- z.quux();
- z.rotate(x)
-})
-```
-
-> **[FIXME]** Do we also want to allow the following?
->
-> ```rust,ignore
-> frobnicate(
-> arg1,
-> arg2,
-> arg3)
-> ```
->
-> This style could ease the conflict between line length and functions
-> with many parameters (or long method chains).
-
-### Matches
-
-> * **[Deprecated]** If you have multiple patterns in a single `match`
-> arm, write each pattern on a separate line:
->
-> ```rust,ignore
-> match foo {
-> bar(_)
-> | baz => quux,
-> x
-> | y
-> | z => {
-> quuux
-> }
-> }
-> ```
-
-### Alignment
-
-Idiomatic code should not use extra whitespace in the middle of a line
-to provide alignment.
-
-
-```rust,ignore
-// Good
-struct Foo {
- short: f64,
- really_long: f64,
-}
-
-// Bad
-struct Bar {
- short: f64,
- really_long: f64,
-}
-
-// Good
-let a = 0;
-let radius = 7;
-
-// Bad
-let b = 0;
-let diameter = 7;
-```
+++ /dev/null
-% Testing
-
-> **[FIXME]** Add some general remarks about when and how to unit
-> test, versus other kinds of testing. What are our expectations for
-> Rust's core libraries?
+++ /dev/null
-% Unit testing
-
-Unit tests should live in a `tests` submodule at the bottom of the module they
-test. Mark the `tests` submodule with `#[cfg(test)]` so it is only compiled when
-testing.
-
-The `tests` module should contain:
-
-* Imports needed only for testing.
-* Functions marked with `#[test]` striving for full coverage of the parent module's
- definitions.
-* Auxiliary functions needed for writing the tests.
-
-For example:
-
-``` rust
-// Excerpt from std::str
-
-#[cfg(test)]
-mod tests {
- #[test]
- fn test_eq() {
- assert!((eq(&"".to_owned(), &"".to_owned())));
- assert!((eq(&"foo".to_owned(), &"foo".to_owned())));
- assert!((!eq(&"foo".to_owned(), &"bar".to_owned())));
- }
-}
-```
-
-> **[FIXME]** add details about useful macros for testing, e.g. `assert!`
+++ /dev/null
-* [Containers and iteration]()
-* [The visitor pattern]()
-* [Concurrency]()
-* [Documentation]()
-* [Macros]()
use core::ops::{CoerceUnsized, Deref, DerefMut};
use core::ops::{BoxPlace, Boxed, InPlace, Place, Placer};
use core::ptr::{self, Unique};
-use core::raw::TraitObject;
use core::convert::From;
/// A value that represents the heap. This is the default place that the `box`
pub fn downcast<T: Any>(self) -> Result<Box<T>, Box<Any>> {
if self.is::<T>() {
unsafe {
- // Get the raw representation of the trait object
- let raw = Box::into_raw(self);
- let to: TraitObject = mem::transmute::<*mut Any, TraitObject>(raw);
-
- // Extract the data pointer
- Ok(Box::from_raw(to.data as *mut T))
+ let raw: *mut Any = Box::into_raw(self);
+ Ok(Box::from_raw(raw as *mut T))
}
} else {
Err(self)
#![cfg_attr(stage0, feature(unsafe_no_drop_flag))]
#![feature(unsize)]
-#![cfg_attr(not(test), feature(fused, raw, fn_traits, placement_new_protocol))]
+#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol))]
#![cfg_attr(test, feature(test, box_heap))]
// Allow testing this library
#![allow(missing_docs)]
#![stable(feature = "rust1", since = "1.0.0")]
-use core::ops::{Drop, Deref, DerefMut};
+use core::ops::{Deref, DerefMut};
use core::iter::{FromIterator, FusedIterator};
use core::mem::swap;
use core::mem::size_of;
#![stable(feature = "rust1", since = "1.0.0")]
-use core::clone::Clone;
-use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
-use core::convert::AsRef;
-use core::default::Default;
+use core::cmp::Ordering;
use core::hash::{Hash, Hasher};
-use core::marker::Sized;
use core::ops::Deref;
-use core::option::Option;
use fmt;
#[cfg(test)]
mod tests {
- use std::clone::Clone;
- use std::iter::{Iterator, IntoIterator, Extend};
- use std::option::Option::{self, Some, None};
use std::__rand::{thread_rng, Rng};
use std::thread;
use std::vec::Vec;
#[test]
fn test_26021() {
- use std::iter::ExactSizeIterator;
// There was a bug in split_off that failed to null out the RHS's head's prev ptr.
// This caused the RHS's dtor to walk up into the LHS at drop and delete all of
// its nodes.
//! Range syntax.
-use core::option::Option::{self, None, Some};
use core::ops::{RangeFull, Range, RangeTo, RangeFrom};
/// **RangeArgument** is implemented by Rust's built-in range types, produced
#[cfg(test)]
mod tests {
- use core::iter::Iterator;
- use core::option::Option::Some;
-
use test;
use super::VecDeque;
#![stable(feature = "rust1", since = "1.0.0")]
use fmt;
-use marker::Send;
-use mem::transmute;
-use option::Option::{self, Some, None};
-use raw::TraitObject;
use intrinsics;
-use marker::{Reflect, Sized};
+use marker::Reflect;
///////////////////////////////////////////////////////////////////////////////
// Any trait
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe {
- // Get the raw representation of the trait object
- let to: TraitObject = transmute(self);
-
- // Extract the data pointer
- Some(&*(to.data as *const T))
+ Some(&*(self as *const Any as *const T))
}
} else {
None
pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe {
- // Get the raw representation of the trait object
- let to: TraitObject = transmute(self);
-
- // Extract the data pointer
- Some(&mut *(to.data as *const T as *mut T))
+ Some(&mut *(self as *mut Any as *mut T))
}
} else {
None
issue = "27778")]
use borrow::{Borrow, BorrowMut};
-use clone::Clone;
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
-use convert::{AsRef, AsMut};
-use default::Default;
+use cmp::Ordering;
use fmt;
use hash::{Hash, self};
-use iter::IntoIterator;
-use marker::{Copy, Sized, Unsize};
-use option::Option;
-use slice::{Iter, IterMut, SliceExt};
+use marker::Unsize;
+use slice::{Iter, IterMut};
/// Utility trait implemented only on arrays of fixed size
///
#![stable(feature = "rust1", since = "1.0.0")]
-use marker::Sized;
-
/// A trait for borrowing data.
///
/// In general, there may be several ways to "borrow" a piece of data. The
#![stable(feature = "rust1", since = "1.0.0")]
-use clone::Clone;
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
-use convert::From;
-use default::Default;
+use cmp::Ordering;
use fmt::{self, Debug, Display};
-use marker::{Copy, PhantomData, Send, Sync, Sized, Unsize};
-use ops::{Deref, DerefMut, Drop, FnOnce, CoerceUnsized};
-use option::Option;
-use option::Option::{None, Some};
-use result::Result;
-use result::Result::{Ok, Err};
+use marker::{PhantomData, Unsize};
+use ops::{Deref, DerefMut, CoerceUnsized};
/// A mutable memory location that admits only `Copy` data.
///
#![allow(non_snake_case)]
#![stable(feature = "core_char", since = "1.2.0")]
-use prelude::v1::*;
-
use char_private::is_printable;
use iter::FusedIterator;
use mem::transmute;
impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> {
type Item = Result<char, InvalidSequence>;
#[inline]
+
fn next(&mut self) -> Option<Result<char, InvalidSequence>> {
- self.0.next().map(|b| {
- if b & 0x80 == 0 { Ok(b as char) } else {
- let l = (!b).leading_zeros() as usize; // number of bytes in UTF-8 representation
- if l < 2 || l > 6 { return Err(InvalidSequence(())) };
- let mut x = (b as u32) & (0x7F >> l);
- for _ in 0..l-1 {
+ self.0.next().map(|first_byte| {
+ // Emit InvalidSequence according to
+ // Unicode §5.22 Best Practice for U+FFFD Substitution
+ // http://www.unicode.org/versions/Unicode9.0.0/ch05.pdf#G40630
+
+ // Roughly: consume at least one byte,
+ // then validate one byte at a time and stop before the first unexpected byte
+ // (which might be the valid start of the next byte sequence).
+
+ let mut code_point;
+ macro_rules! first_byte {
+ ($mask: expr) => {
+ code_point = u32::from(first_byte & $mask)
+ }
+ }
+ macro_rules! continuation_byte {
+ () => { continuation_byte!(0x80...0xBF) };
+ ($range: pat) => {
match self.0.peek() {
- Some(&b) if b & 0xC0 == 0x80 => {
+ Some(&byte @ $range) => {
+ code_point = (code_point << 6) | u32::from(byte & 0b0011_1111);
self.0.next();
- x = (x << 6) | (b as u32) & 0x3F;
- },
- _ => return Err(InvalidSequence(())),
+ }
+ _ => return Err(InvalidSequence(()))
}
}
- match from_u32(x) {
- Some(x) if l == x.len_utf8() => Ok(x),
- _ => Err(InvalidSequence(())),
+ }
+
+ match first_byte {
+ 0x00...0x7F => {
+ first_byte!(0b1111_1111);
+ }
+ 0xC2...0xDF => {
+ first_byte!(0b0001_1111);
+ continuation_byte!();
}
+ 0xE0 => {
+ first_byte!(0b0000_1111);
+ continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong
+ continuation_byte!();
+ }
+ 0xE1...0xEC | 0xEE...0xEF => {
+ first_byte!(0b0000_1111);
+ continuation_byte!();
+ continuation_byte!();
+ }
+ 0xED => {
+ first_byte!(0b0000_1111);
+ continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates
+ continuation_byte!();
+ }
+ 0xF0 => {
+ first_byte!(0b0000_0111);
+ continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong
+ continuation_byte!();
+ continuation_byte!();
+ }
+ 0xF1...0xF3 => {
+ first_byte!(0b0000_0111);
+ continuation_byte!();
+ continuation_byte!();
+ continuation_byte!();
+ }
+ 0xF4 => {
+ first_byte!(0b0000_0111);
+ continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX
+ continuation_byte!();
+ continuation_byte!();
+ }
+ _ => return Err(InvalidSequence(())) // Illegal first byte, overlong, or beyond MAX
+ }
+ unsafe {
+ Ok(from_u32_unchecked(code_point))
}
})
}
// NOTE: The following code was generated by "src/etc/char_private.py",
// do not edit directly!
-use slice::SliceExt;
-
fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
for &s in singletons {
if x == s {
#![stable(feature = "rust1", since = "1.0.0")]
-use marker::Sized;
-
/// A common trait for the ability to explicitly duplicate an object.
///
/// Differs from `Copy` in that `Copy` is implicit and extremely inexpensive, while
use self::Ordering::*;
-use marker::Sized;
-use option::Option::{self, Some};
-
/// Trait for equality comparisons which are [partial equivalence
/// relations](http://en.wikipedia.org/wiki/Partial_equivalence_relation).
///
// Implementation of PartialEq, Eq, PartialOrd and Ord for primitive types
mod impls {
- use cmp::{PartialOrd, Ord, PartialEq, Eq, Ordering};
- use cmp::Ordering::{Less, Greater, Equal};
- use marker::Sized;
- use option::Option;
- use option::Option::{Some, None};
+ use cmp::Ordering::{self, Less, Greater, Equal};
macro_rules! partial_eq_impl {
($($t:ty)*) => ($(
#![stable(feature = "rust1", since = "1.0.0")]
-use marker::Sized;
-use result::Result;
-
/// A cheap, reference-to-reference conversion.
///
/// `AsRef` is very similar to, but different than, `Borrow`. See
#![stable(feature = "rust1", since = "1.0.0")]
-use marker::Sized;
-
/// A trait for giving a type a useful default value.
///
/// Sometimes, you want to fall back to some kind of default value, and
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use fmt::{self, FlagV1};
struct PadAdapter<'a, 'b: 'a> {
#![stable(feature = "rust1", since = "1.0.0")]
-use prelude::v1::*;
-
use cell::{UnsafeCell, Cell, RefCell, Ref, RefMut, BorrowState};
use marker::PhantomData;
use mem;
prefix: &str,
buf: &str)
-> Result {
- use char::CharExt;
-
let mut width = buf.len();
let mut sign = None;
f: F) -> Result
where F: FnOnce(&mut Formatter) -> Result,
{
- use char::CharExt;
let align = match self.align {
rt::v1::Alignment::Unknown => default,
_ => self.align
// FIXME: #6220 Implement floating point formatting
-use prelude::v1::*;
-
use fmt;
use num::Zero;
use ops::{Div, Rem, Sub};
#![stable(feature = "rust1", since = "1.0.0")]
-use prelude::v1::*;
-
use fmt;
use marker;
use mem;
//////////////////////////////////////////////////////////////////////////////
mod impls {
- use prelude::v1::*;
-
use mem;
use slice;
use super::*;
//! An implementation of SipHash.
-use prelude::v1::*;
-
use marker::PhantomData;
use ptr;
issue = "0")]
#![allow(missing_docs)]
-use marker::Sized;
-
extern "rust-intrinsic" {
// NB: These intrinsics take raw pointers because they mutate aliased
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use clone::Clone;
-use cmp::{Ord, PartialOrd, PartialEq, Ordering};
-use default::Default;
-use ops::FnMut;
-use option::Option::{self, Some, None};
-use marker::Sized;
+use cmp::Ordering;
use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, FlatMap, Fuse};
use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, Take, TakeWhile, Rev};
use super::{Zip, Sum, Product};
-use super::ChainState;
-use super::{DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator};
-use super::{IntoIterator, ZipImpl};
+use super::{ChainState, FromIterator, ZipImpl};
fn _assert_is_object_safe(_: &Iterator<Item=()>) {}
#![stable(feature = "rust1", since = "1.0.0")]
-use clone::Clone;
use cmp;
-use default::Default;
use fmt;
use iter_private::TrustedRandomAccess;
-use ops::FnMut;
-use option::Option::{self, Some, None};
use usize;
#[stable(feature = "rust1", since = "1.0.0")]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use clone::Clone;
-use cmp::PartialOrd;
use mem;
use ops::{self, Add, Sub};
-use option::Option::{self, Some, None};
-use marker::Sized;
use usize;
-use super::{DoubleEndedIterator, ExactSizeIterator, Iterator, FusedIterator};
+use super::FusedIterator;
/// Objects that can be stepped over in both directions.
///
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use clone::Clone;
-use default::Default;
use fmt;
use marker;
-use option::Option::{self, Some, None};
use usize;
-use super::{DoubleEndedIterator, IntoIterator, Iterator, ExactSizeIterator, FusedIterator};
+use super::FusedIterator;
/// An iterator that repeats an element endlessly.
///
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use option::Option::{self, Some};
-use marker::Sized;
-
-use super::Iterator;
-
/// Conversion from an `Iterator`.
///
/// By implementing `FromIterator` for a type, you define how it will be
// except according to those terms.
-use iter::ExactSizeIterator;
-
/// An iterator whose items are random accessible efficiently
///
/// # Safety
#![feature(unboxed_closures)]
#![feature(question_mark)]
#![feature(never_type)]
+#![feature(prelude_import)]
+
+#[prelude_import]
+#[allow(unused)]
+use prelude::v1::*;
#[macro_use]
mod macros;
#![stable(feature = "rust1", since = "1.0.0")]
-use clone::Clone;
use cmp;
-use default::Default;
-use option::Option;
use hash::Hash;
use hash::Hasher;
impls! { PhantomData }
mod impls {
- use super::{Send, Sync, Sized};
-
#[stable(feature = "rust1", since = "1.0.0")]
unsafe impl<'a, T: Sync + ?Sized> Send for &'a T {}
#[stable(feature = "rust1", since = "1.0.0")]
#![stable(feature = "rust1", since = "1.0.0")]
-use marker::Sized;
use intrinsics;
use ptr;
reason = "needs an RFC to flesh out the design",
issue = "27730")]
-use marker::Sized;
use ops::{CoerceUnsized, Deref};
/// Unsafe trait to indicate what types are usable with the NonZero struct
issue = "0")]
#![macro_use]
-use prelude::v1::*;
-
use mem;
use intrinsics;
// this one is used for testing only.
#[doc(hidden)]
pub mod tests {
- use prelude::v1::*;
define_bignum!(Big8x3: type=u8, n=3);
}
//! The various algorithms from the paper.
-use prelude::v1::*;
use cmp::min;
use cmp::Ordering::{Less, Equal, Greater};
use num::diy_float::Fp;
#[cfg(all(target_arch="x86", not(target_feature="sse2")))]
mod fpu_precision {
use mem::size_of;
- use ops::Drop;
/// A structure used to preserve the original value of the FPU control word, so that it can be
/// restored when the structure is dropped.
reason = "internal routines only exposed for testing",
issue = "0")]
-use prelude::v1::*;
use fmt;
use str::FromStr;
// FIXME This module's name is a bit unfortunate, since other modules also import `core::num`.
-use prelude::v1::*;
use cmp::Ordering::{self, Less, Equal, Greater};
pub use num::bignum::Big32x40 as Big;
//! modules rely on to not panic (or overflow) in turn.
//! To make matters worse, all that happens in a single pass over the input.
//! So, be careful when modifying anything, and double-check with the other modules.
-use prelude::v1::*;
use super::num;
use self::ParseResult::{Valid, ShortcutToInf, ShortcutToZero, Invalid};
//! Many functions in this module only handle normal numbers. The dec2flt routines conservatively
//! take the universally-correct slow path (Algorithm M) for very small and very large numbers.
//! That algorithm needs only next_float() which does handle subnormals and zeros.
-use prelude::v1::*;
use u32;
use cmp::Ordering::{Less, Equal, Greater};
use ops::{Mul, Div, Neg};
//! Decodes a floating-point value into individual parts and error ranges.
-use prelude::v1::*;
-
use {f32, f64};
use num::FpCategory;
use num::dec2flt::rawfp::RawFloat;
reason = "internal routines only exposed for testing",
issue = "0")]
-use prelude::v1::*;
use i16;
pub use self::decoder::{decode, DecodableFloat, FullDecoded, Decoded};
quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116.
*/
-use prelude::v1::*;
-
use cmp::Ordering;
use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243.
*/
-use prelude::v1::*;
-
use num::diy_float::Fp;
use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up};
#![stable(feature = "rust1", since = "1.0.0")]
-use char::CharExt;
-use cmp::PartialOrd;
-use convert::{From, TryFrom};
+use convert::TryFrom;
use fmt;
use intrinsics;
-use marker::{Copy, Sized};
use mem::size_of;
-use option::Option::{self, Some, None};
-use result::Result::{self, Ok, Err};
-use str::{FromStr, StrExt};
-use slice::SliceExt;
+use str::FromStr;
/// Provides intentionally-wrapped arithmetic on `T`.
///
#![stable(feature = "rust1", since = "1.0.0")]
-use cmp::PartialOrd;
use fmt;
-use marker::{Sized, Unsize};
-use result::Result::{self, Ok, Err};
+use marker::Unsize;
/// The `Drop` trait is used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
}
mod impls {
- use marker::Sized;
- use super::{Fn, FnMut, FnOnce};
-
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a,A,F:?Sized> Fn<A> for &'a F
where F : Fn<A>
#![stable(feature = "rust1", since = "1.0.0")]
-use self::Option::*;
-
-use clone::Clone;
-use convert::From;
-use default::Default;
-use iter::{Iterator, FromIterator, IntoIterator, ExactSizeIterator, DoubleEndedIterator};
-use iter::FusedIterator;
+use iter::{FromIterator, FusedIterator};
use mem;
-use ops::FnOnce;
-use result::Result::{Ok, Err};
-use result::Result;
// Note that this is not a lang item per se, but it has a hidden dependency on
// `Iterator`, which is one. The compiler assumes that the `next` method of
#![stable(feature = "rust1", since = "1.0.0")]
-use clone::Clone;
use intrinsics;
use ops::{CoerceUnsized, Deref};
use fmt;
use hash;
-use option::Option::{self, Some, None};
-use marker::{Copy, PhantomData, Send, Sized, Sync, Unsize};
+use marker::{PhantomData, Unsize};
use mem;
use nonzero::NonZero;
-use cmp::{PartialEq, Eq, Ord, PartialOrd};
use cmp::Ordering::{self, Less, Equal, Greater};
// FIXME #19649: intrinsic docs don't render, so these have no docs :(
#![stable(feature = "rust1", since = "1.0.0")]
-use self::Result::{Ok, Err};
-
-use clone::Clone;
use fmt;
-use iter::{Iterator, DoubleEndedIterator, FromIterator, ExactSizeIterator, IntoIterator};
-use iter::FusedIterator;
-use ops::FnOnce;
-use option::Option::{self, None, Some};
+use iter::{FromIterator, FusedIterator};
/// `Result` is a type that represents either success (`Ok`) or failure (`Err`).
///
// * The `raw` and `bytes` submodules.
// * Boilerplate trait implementations.
-use clone::Clone;
-use cmp::{Ordering, PartialEq, PartialOrd, Eq, Ord};
-use cmp::Ordering::{Less, Equal, Greater};
+use cmp::Ordering::{self, Less, Equal, Greater};
use cmp;
-use convert::AsRef;
-use default::Default;
use fmt;
use intrinsics::assume;
use iter::*;
-use ops::{FnMut, self};
-use ops::RangeFull;
-use option::Option;
-use option::Option::{None, Some};
-use result::Result;
-use result::Result::{Ok, Err};
+use ops::{self, RangeFull};
use ptr;
use mem;
-use marker::{Copy, Send, Sync, self};
+use marker;
use iter_private::TrustedRandomAccess;
#[repr(C)]
use self::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
use char;
-use clone::Clone;
-use convert::AsRef;
-use default::Default;
use fmt;
-use iter::ExactSizeIterator;
-use iter::{Map, Cloned, Iterator, DoubleEndedIterator, FusedIterator};
-use marker::Sized;
+use iter::{Map, Cloned, FusedIterator};
use mem;
-use ops::{Fn, FnMut, FnOnce};
-use option::Option::{self, None, Some};
-use result::Result::{self, Ok, Err};
-use slice::{self, SliceExt};
+use slice;
pub mod pattern;
*/
mod traits {
- use cmp::{Ord, Ordering, PartialEq, PartialOrd, Eq};
- use option::Option;
- use option::Option::Some;
+ use cmp::Ordering;
use ops;
- use str::{StrExt, eq_slice};
+ use str::eq_slice;
#[stable(feature = "rust1", since = "1.0.0")]
impl Ord for str {
reason = "API not fully fleshed out and ready to be stabilized",
issue = "27721")]
-use prelude::v1::*;
-
use cmp;
use fmt;
use usize;
use self::Ordering::*;
-use marker::{Send, Sync};
-
use intrinsics;
use cell::UnsafeCell;
-
-use result::Result::{self, Ok, Err};
-
-use default::Default;
use fmt;
/// A boolean type which can be safely shared between threads.
// See src/libstd/primitive_docs.rs for documentation.
-use clone::Clone;
use cmp::*;
use cmp::Ordering::*;
-use default::Default;
-use option::Option;
-use option::Option::Some;
// FIXME(#19630) Remove this work-around
macro_rules! e {
#[test]
fn test_decode_utf8() {
- use core::char::*;
- use core::iter::FromIterator;
-
- for &(str, bs) in [("", &[] as &[u8]),
- ("A", &[0x41u8] as &[u8]),
- ("�", &[0xC1u8, 0x81u8] as &[u8]),
- ("♥", &[0xE2u8, 0x99u8, 0xA5u8]),
- ("♥A", &[0xE2u8, 0x99u8, 0xA5u8, 0x41u8] as &[u8]),
- ("�", &[0xE2u8, 0x99u8] as &[u8]),
- ("�A", &[0xE2u8, 0x99u8, 0x41u8] as &[u8]),
- ("�", &[0xC0u8] as &[u8]),
- ("�A", &[0xC0u8, 0x41u8] as &[u8]),
- ("�", &[0x80u8] as &[u8]),
- ("�A", &[0x80u8, 0x41u8] as &[u8]),
- ("�", &[0xFEu8] as &[u8]),
- ("�A", &[0xFEu8, 0x41u8] as &[u8]),
- ("�", &[0xFFu8] as &[u8]),
- ("�A", &[0xFFu8, 0x41u8] as &[u8])].into_iter() {
- assert!(Iterator::eq(str.chars(),
- decode_utf8(bs.into_iter().map(|&b|b))
- .map(|r_b| r_b.unwrap_or('\u{FFFD}'))),
- "chars = {}, bytes = {:?}, decoded = {:?}", str, bs,
- Vec::from_iter(decode_utf8(bs.into_iter().map(|&b|b))
- .map(|r_b| r_b.unwrap_or('\u{FFFD}'))));
+ macro_rules! assert_decode_utf8 {
+ ($input_bytes: expr, $expected_str: expr) => {
+ let input_bytes: &[u8] = &$input_bytes;
+ let s = char::decode_utf8(input_bytes.iter().cloned())
+ .map(|r_b| r_b.unwrap_or('\u{FFFD}'))
+ .collect::<String>();
+ assert_eq!(s, $expected_str,
+ "input bytes: {:?}, expected str: {:?}, result: {:?}",
+ input_bytes, $expected_str, s);
+ assert_eq!(String::from_utf8_lossy(&$input_bytes), $expected_str);
+ }
}
+
+ assert_decode_utf8!([], "");
+ assert_decode_utf8!([0x41], "A");
+ assert_decode_utf8!([0xC1, 0x81], "��");
+ assert_decode_utf8!([0xE2, 0x99, 0xA5], "♥");
+ assert_decode_utf8!([0xE2, 0x99, 0xA5, 0x41], "♥A");
+ assert_decode_utf8!([0xE2, 0x99], "�");
+ assert_decode_utf8!([0xE2, 0x99, 0x41], "�A");
+ assert_decode_utf8!([0xC0], "�");
+ assert_decode_utf8!([0xC0, 0x41], "�A");
+ assert_decode_utf8!([0x80], "�");
+ assert_decode_utf8!([0x80, 0x41], "�A");
+ assert_decode_utf8!([0xFE], "�");
+ assert_decode_utf8!([0xFE, 0x41], "�A");
+ assert_decode_utf8!([0xFF], "�");
+ assert_decode_utf8!([0xFF, 0x41], "�A");
+ assert_decode_utf8!([0xC0, 0x80], "��");
+
+ // Surrogates
+ assert_decode_utf8!([0xED, 0x9F, 0xBF], "\u{D7FF}");
+ assert_decode_utf8!([0xED, 0xA0, 0x80], "���");
+ assert_decode_utf8!([0xED, 0xBF, 0x80], "���");
+ assert_decode_utf8!([0xEE, 0x80, 0x80], "\u{E000}");
+
+ // char::MAX
+ assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0xBF], "\u{10FFFF}");
+ assert_decode_utf8!([0xF4, 0x8F, 0xBF, 0x41], "�A");
+ assert_decode_utf8!([0xF4, 0x90, 0x80, 0x80], "����");
+
+ // 5 and 6 bytes sequence
+ // Part of the original design of UTF-8,
+ // but invalid now that UTF-8 is artificially restricted to match the range of UTF-16.
+ assert_decode_utf8!([0xF8, 0x80, 0x80, 0x80, 0x80], "�����");
+ assert_decode_utf8!([0xFC, 0x80, 0x80, 0x80, 0x80, 0x80], "������");
}
self.start == self.end
}
- pub fn as_str_slice(&self) -> &'doc str {
+ pub fn as_str(&self) -> &'doc str {
str::from_utf8(&self.data[self.start..self.end]).unwrap()
}
- pub fn as_str(&self) -> String {
- self.as_str_slice().to_string()
+ pub fn to_string(&self) -> String {
+ self.as_str().to_string()
}
}
Ok(char::from_u32(doc_as_u32(self.next_doc(EsChar)?)).unwrap())
}
fn read_str(&mut self) -> DecodeResult<String> {
- Ok(self.next_doc(EsStr)?.as_str())
+ Ok(self.next_doc(EsStr)?.to_string())
}
// Compound types:
}
}
- fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ fn regions(&mut self, a: &'tcx ty::Region, _: &'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region> {
Ok(a)
}
}
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
- match r {
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+ match *r {
// Never make variables for regions bound within the type itself,
// nor for erased regions.
ty::ReLateBound(..) |
}
}
- fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region> {
debug!("{}.regions({:?}, {:?})",
self.tag(),
a,
pub fn note_and_explain_region(self,
err: &mut DiagnosticBuilder,
prefix: &str,
- region: ty::Region,
+ region: &'tcx ty::Region,
suffix: &str) {
fn item_scope_tag(item: &hir::Item) -> &'static str {
match item.node {
Some(span))
}
- let (description, span) = match region {
+ let (description, span) = match *region {
ty::ReScope(scope) => {
let new_string;
let unknown_scope = || {
}
fn free_regions_from_same_fn<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- sub: Region,
- sup: Region)
+ sub: &'tcx Region,
+ sup: &'tcx Region)
-> Option<FreeRegionsFromSameFn> {
debug!("free_regions_from_same_fn(sub={:?}, sup={:?})", sub, sup);
let (scope_id, fr1, fr2) = match (sub, sup) {
- (ReFree(fr1), ReFree(fr2)) => {
+ (&ReFree(fr1), &ReFree(fr2)) => {
if fr1.scope != fr2.scope {
return None
}
fn report_generic_bound_failure(&self,
origin: SubregionOrigin<'tcx>,
bound_kind: GenericKind<'tcx>,
- sub: Region)
+ sub: &'tcx Region)
{
// FIXME: it would be better to report the first error message
// with the span of the parameter itself, rather than the span
format!("the associated type `{}`", p),
};
- let mut err = match sub {
+ let mut err = match *sub {
ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
// Does the required lifetime have a nice name we can print?
let mut err = struct_span_err!(self.tcx.sess,
fn report_concrete_failure(&self,
origin: SubregionOrigin<'tcx>,
- sub: Region,
- sup: Region)
+ sub: &'tcx Region,
+ sup: &'tcx Region)
-> DiagnosticBuilder<'tcx> {
match origin {
infer::Subtype(trace) => {
fn report_sub_sup_conflict(&self,
var_origin: RegionVariableOrigin,
sub_origin: SubregionOrigin<'tcx>,
- sub_region: Region,
+ sub_region: &'tcx Region,
sup_origin: SubregionOrigin<'tcx>,
- sup_region: Region) {
+ sup_region: &'tcx Region) {
let mut err = self.report_inference_failure(var_origin);
self.tcx.note_and_explain_region(&mut err,
self.infcx.tcx
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
- match r {
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+ match *r {
ty::ReEarlyBound(..) |
ty::ReLateBound(..) => {
// leave bound regions alone
ty::ReEmpty |
ty::ReErased => {
// replace all free regions with 'erased
- ty::ReErased
+ self.tcx().mk_region(ty::ReErased)
}
}
}
lattice::super_lattice_tys(self, a, b)
}
- fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region> {
debug!("{}.regions({:?}, {:?})",
self.tag(),
a,
.map(|(&skol, &(br, ref regions))| {
let representative =
regions.iter()
- .filter(|r| !skol_resolution_map.contains_key(r))
+ .filter(|&&r| !skol_resolution_map.contains_key(r))
.cloned()
.next()
.unwrap_or_else(|| { // [1]
snapshot: &CombinedSnapshot,
debruijn: ty::DebruijnIndex,
new_vars: &[ty::RegionVid],
- a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
- r0: ty::Region)
- -> ty::Region {
+ a_map: &FnvHashMap<ty::BoundRegion, &'tcx ty::Region>,
+ r0: &'tcx ty::Region)
+ -> &'tcx ty::Region {
// Regions that pre-dated the LUB computation stay as they are.
if !is_var_in_set(new_vars, r0) {
assert!(!r0.is_bound());
debug!("generalize_region(r0={:?}): \
replacing with {:?}, tainted={:?}",
r0, *a_br, tainted);
- return ty::ReLateBound(debruijn, *a_br);
+ return infcx.tcx.mk_region(ty::ReLateBound(debruijn, *a_br));
}
}
snapshot: &CombinedSnapshot,
debruijn: ty::DebruijnIndex,
new_vars: &[ty::RegionVid],
- a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
+ a_map: &FnvHashMap<ty::BoundRegion,
+ &'tcx ty::Region>,
a_vars: &[ty::RegionVid],
b_vars: &[ty::RegionVid],
- r0: ty::Region) -> ty::Region {
+ r0: &'tcx ty::Region)
+ -> &'tcx ty::Region {
if !is_var_in_set(new_vars, r0) {
assert!(!r0.is_bound());
return r0;
if a_r.is_some() && b_r.is_some() && only_new_vars {
// Related to exactly one bound variable from each fn:
- return rev_lookup(span, a_map, a_r.unwrap());
+ return rev_lookup(infcx, span, a_map, a_r.unwrap());
} else if a_r.is_none() && b_r.is_none() {
// Not related to bound variables from either fn:
assert!(!r0.is_bound());
}
}
- fn rev_lookup(span: Span,
- a_map: &FnvHashMap<ty::BoundRegion, ty::Region>,
- r: ty::Region) -> ty::Region
+ fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+ span: Span,
+ a_map: &FnvHashMap<ty::BoundRegion, &'tcx ty::Region>,
+ r: &'tcx ty::Region) -> &'tcx ty::Region
{
for (a_br, a_r) in a_map {
if *a_r == r {
- return ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br);
+ return infcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br));
}
}
span_bug!(
r);
}
- fn fresh_bound_variable(infcx: &InferCtxt, debruijn: ty::DebruijnIndex) -> ty::Region {
+ fn fresh_bound_variable<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
+ debruijn: ty::DebruijnIndex)
+ -> &'tcx ty::Region {
infcx.region_vars.new_bound(debruijn)
}
}
}
fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
- map: &FnvHashMap<ty::BoundRegion, ty::Region>)
+ map: &FnvHashMap<ty::BoundRegion, &'tcx ty::Region>)
-> Vec<ty::RegionVid> {
map.iter()
- .map(|(_, r)| match *r {
+ .map(|(_, &r)| match *r {
ty::ReVar(r) => { r }
- r => {
+ _ => {
span_bug!(
fields.trace.origin.span(),
"found non-region-vid: {:?}",
.collect()
}
-fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool {
- match r {
+fn is_var_in_set(new_vars: &[ty::RegionVid], r: &ty::Region) -> bool {
+ match *r {
ty::ReVar(ref v) => new_vars.iter().any(|x| x == v),
_ => false
}
mut fldr: F)
-> T
where T: TypeFoldable<'tcx>,
- F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region,
+ F: FnMut(&'tcx ty::Region, ty::DebruijnIndex) -> &'tcx ty::Region,
{
tcx.fold_regions(unbound_value, &mut false, |region, current_depth| {
// we should only be encountering "escaping" late-bound regions here,
// because the ones at the current level should have been replaced
// with fresh variables
- assert!(match region {
+ assert!(match *region {
ty::ReLateBound(..) => false,
_ => true
});
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn tainted_regions(&self,
snapshot: &CombinedSnapshot,
- r: ty::Region,
+ r: &'tcx ty::Region,
directions: TaintDirections)
- -> FnvHashSet<ty::Region> {
+ -> FnvHashSet<&'tcx ty::Region> {
self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions)
}
pub fn skolemize_late_bound_regions<T>(&self,
binder: &ty::Binder<T>,
snapshot: &CombinedSnapshot)
- -> (T, SkolemizationMap)
+ -> (T, SkolemizationMap<'tcx>)
where T : TypeFoldable<'tcx>
{
let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| {
pub fn leak_check(&self,
overly_polymorphic: bool,
span: Span,
- skol_map: &SkolemizationMap,
+ skol_map: &SkolemizationMap<'tcx>,
snapshot: &CombinedSnapshot)
-> RelateResult<'tcx, ()>
{
for &tainted_region in &incoming_taints {
// Each skolemized should only be relatable to itself
// or new variables:
- match tainted_region {
+ match *tainted_region {
ty::ReVar(vid) => {
if new_vars.contains(&vid) {
warnings.extend(
/// to the depth of the predicate, in this case 1, so that the final
/// predicate is `for<'a> &'a int : Clone`.
pub fn plug_leaks<T>(&self,
- skol_map: SkolemizationMap,
+ skol_map: SkolemizationMap<'tcx>,
snapshot: &CombinedSnapshot,
value: &T) -> T
where T : TypeFoldable<'tcx>
// region back to the `ty::BoundRegion` that it originally
// represented. Because `leak_check` passed, we know that
// these taint sets are mutually disjoint.
- let inv_skol_map: FnvHashMap<ty::Region, ty::BoundRegion> =
+ let inv_skol_map: FnvHashMap<&'tcx ty::Region, ty::BoundRegion> =
skol_map
.iter()
.flat_map(|(&skol_br, &skol)| {
// (which ought not to escape the snapshot, but we
// don't check that) or itself
assert!(
- match r {
+ match *r {
ty::ReVar(_) => true,
ty::ReSkolemized(_, ref br1) => br == br1,
_ => false,
"leak-check would have us replace {:?} with {:?}",
r, br);
- ty::ReLateBound(ty::DebruijnIndex::new(current_depth - 1), br.clone())
+ self.tcx.mk_region(ty::ReLateBound(
+ ty::DebruijnIndex::new(current_depth - 1), br.clone()))
}
}
});
///
/// Note: popping also occurs implicitly as part of `leak_check`.
pub fn pop_skolemized(&self,
- skol_map: SkolemizationMap,
+ skol_map: SkolemizationMap<'tcx>,
snapshot: &CombinedSnapshot)
{
debug!("pop_skolemized({:?})", skol_map);
lattice::super_lattice_tys(self, a, b)
}
- fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region> {
debug!("{}.regions({:?}, {:?})",
self.tag(),
a,
/// A map returned by `skolemize_late_bound_regions()` indicating the skolemized
/// region that each late-bound region was replaced with.
-pub type SkolemizationMap = FnvHashMap<ty::BoundRegion, ty::Region>;
+pub type SkolemizationMap<'tcx> = FnvHashMap<ty::BoundRegion, &'tcx ty::Region>;
/// Why did we require that the two types be related?
///
pub fn sub_regions(&self,
origin: SubregionOrigin<'tcx>,
- a: ty::Region,
- b: ty::Region) {
+ a: &'tcx ty::Region,
+ b: &'tcx ty::Region) {
debug!("sub_regions({:?} <: {:?})", a, b);
self.region_vars.make_subregion(origin, a, b);
}
pub fn region_outlives_predicate(&self,
span: Span,
- predicate: &ty::PolyRegionOutlivesPredicate)
+ predicate: &ty::PolyRegionOutlivesPredicate<'tcx>)
-> UnitResult<'tcx>
{
self.commit_if_ok(|snapshot| {
.new_key(None)
}
- pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region {
- ty::ReVar(self.region_vars.new_region_var(origin))
+ pub fn next_region_var(&self, origin: RegionVariableOrigin)
+ -> &'tcx ty::Region {
+ self.tcx.mk_region(ty::ReVar(self.region_vars.new_region_var(origin)))
}
/// Create a region inference variable for the given
pub fn region_var_for_def(&self,
span: Span,
def: &ty::RegionParameterDef)
- -> ty::Region {
+ -> &'tcx ty::Region {
self.next_region_var(EarlyBoundRegion(span, def.name))
}
})
}
- pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> ty::Region {
+ pub fn fresh_bound_region(&self, debruijn: ty::DebruijnIndex) -> &'tcx ty::Region {
self.region_vars.new_bound(debruijn)
}
span: Span,
lbrct: LateBoundRegionConversionTime,
value: &ty::Binder<T>)
- -> (T, FnvHashMap<ty::BoundRegion,ty::Region>)
+ -> (T, FnvHashMap<ty::BoundRegion, &'tcx ty::Region>)
where T : TypeFoldable<'tcx>
{
self.tcx.replace_late_bound_regions(
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
- a: ty::Region,
- bound: VerifyBound) {
+ a: &'tcx ty::Region,
+ bound: VerifyBound<'tcx>) {
debug!("verify_generic_bound({:?}, {:?} <: {:?})",
kind,
a,
self.tcx.region_maps.temporary_scope(rvalue_id)
}
- pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
+ pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned()
}
struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
graph_name: String,
- map: &'a FnvHashMap<Constraint, SubregionOrigin<'tcx>>,
+ map: &'a FnvHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>,
node_ids: FnvHashMap<Node, usize>,
}
// type Edge = Constraint;
#[derive(Clone, PartialEq, Eq, Debug, Copy)]
-enum Edge {
- Constraint(Constraint),
+enum Edge<'tcx> {
+ Constraint(Constraint<'tcx>),
EnclScope(CodeExtent, CodeExtent),
}
impl<'a, 'gcx, 'tcx> dot::Labeller<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
type Node = Node;
- type Edge = Edge;
+ type Edge = Edge<'tcx>;
fn graph_id(&self) -> dot::Id {
dot::Id::new(&*self.graph_name).unwrap()
}
Constraint::ConstrainVarSubVar(rv_1, rv_2) =>
(Node::RegionVid(rv_1), Node::RegionVid(rv_2)),
Constraint::ConstrainRegSubVar(r_1, rv_2) =>
- (Node::Region(r_1), Node::RegionVid(rv_2)),
+ (Node::Region(*r_1), Node::RegionVid(rv_2)),
Constraint::ConstrainVarSubReg(rv_1, r_2) =>
- (Node::RegionVid(rv_1), Node::Region(r_2)),
+ (Node::RegionVid(rv_1), Node::Region(*r_2)),
Constraint::ConstrainRegSubReg(r_1, r_2) =>
- (Node::Region(r_1), Node::Region(r_2)),
+ (Node::Region(*r_1), Node::Region(*r_2)),
}
}
impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> {
type Node = Node;
- type Edge = Edge;
+ type Edge = Edge<'tcx>;
fn nodes(&self) -> dot::Nodes<Node> {
let mut set = FnvHashSet();
for node in self.node_ids.keys() {
debug!("constraint graph has {} nodes", set.len());
set.into_iter().collect()
}
- fn edges(&self) -> dot::Edges<Edge> {
+ fn edges(&self) -> dot::Edges<Edge<'tcx>> {
debug!("constraint graph has {} edges", self.map.len());
let mut v: Vec<_> = self.map.keys().map(|e| Edge::Constraint(*e)).collect();
self.tcx.region_maps.each_encl_scope(|sub, sup| v.push(Edge::EnclScope(*sub, *sup)));
debug!("region graph has {} edges", v.len());
Cow::Owned(v)
}
- fn source(&self, edge: &Edge) -> Node {
+ fn source(&self, edge: &Edge<'tcx>) -> Node {
let (n1, _) = edge_to_nodes(edge);
debug!("edge {:?} has source {:?}", edge, n1);
n1
}
- fn target(&self, edge: &Edge) -> Node {
+ fn target(&self, edge: &Edge<'tcx>) -> Node {
let (_, n2) = edge_to_nodes(edge);
debug!("edge {:?} has target {:?}", edge, n2);
n2
}
}
-pub type ConstraintMap<'tcx> = FnvHashMap<Constraint, SubregionOrigin<'tcx>>;
+pub type ConstraintMap<'tcx> = FnvHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>;
fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
map: &ConstraintMap<'tcx>,
// A constraint that influences the inference process.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
-pub enum Constraint {
+pub enum Constraint<'tcx> {
// One region variable is subregion of another
ConstrainVarSubVar(RegionVid, RegionVid),
// Concrete region is subregion of region variable
- ConstrainRegSubVar(Region, RegionVid),
+ ConstrainRegSubVar(&'tcx Region, RegionVid),
// Region variable is subregion of concrete region. This does not
// directly affect inference, but instead is checked after
// inference is complete.
- ConstrainVarSubReg(RegionVid, Region),
+ ConstrainVarSubReg(RegionVid, &'tcx Region),
// A constraint where neither side is a variable. This does not
// directly affect inference, but instead is checked after
// inference is complete.
- ConstrainRegSubReg(Region, Region),
+ ConstrainRegSubReg(&'tcx Region, &'tcx Region),
}
// VerifyGenericBound(T, _, R, RS): The parameter type `T` (or
pub struct Verify<'tcx> {
kind: GenericKind<'tcx>,
origin: SubregionOrigin<'tcx>,
- region: Region,
- bound: VerifyBound,
+ region: &'tcx Region,
+ bound: VerifyBound<'tcx>,
}
#[derive(Copy, Clone, PartialEq, Eq)]
// particular region (let's call it `'min`) meets some bound.
// The bound is described the by the following grammar:
#[derive(Debug)]
-pub enum VerifyBound {
+pub enum VerifyBound<'tcx> {
// B = exists {R} --> some 'r in {R} must outlive 'min
//
// Put another way, the subject value is known to outlive all
// regions in {R}, so if any of those outlives 'min, then the
// bound is met.
- AnyRegion(Vec<Region>),
+ AnyRegion(Vec<&'tcx Region>),
// B = forall {R} --> all 'r in {R} must outlive 'min
//
// Put another way, the subject value is known to outlive some
// region in {R}, so if all of those outlives 'min, then the bound
// is met.
- AllRegions(Vec<Region>),
+ AllRegions(Vec<&'tcx Region>),
// B = exists {B} --> 'min must meet some bound b in {B}
- AnyBound(Vec<VerifyBound>),
+ AnyBound(Vec<VerifyBound<'tcx>>),
// B = forall {B} --> 'min must meet all bounds b in {B}
- AllBounds(Vec<VerifyBound>),
+ AllBounds(Vec<VerifyBound<'tcx>>),
}
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
-pub struct TwoRegions {
- a: Region,
- b: Region,
+pub struct TwoRegions<'tcx> {
+ a: &'tcx Region,
+ b: &'tcx Region,
}
#[derive(Copy, Clone, PartialEq)]
-pub enum UndoLogEntry {
+pub enum UndoLogEntry<'tcx> {
/// Pushed when we start a snapshot.
OpenSnapshot,
AddVar(RegionVid),
/// We added the given `constraint`
- AddConstraint(Constraint),
+ AddConstraint(Constraint<'tcx>),
/// We added the given `verify`
AddVerify(usize),
AddGiven(ty::FreeRegion, ty::RegionVid),
/// We added a GLB/LUB "combinaton variable"
- AddCombination(CombineMapType, TwoRegions),
+ AddCombination(CombineMapType, TwoRegions<'tcx>),
/// During skolemization, we sometimes purge entries from the undo
/// log in a kind of minisnapshot (unlike other snapshots, this
/// `ConcreteFailure(o, a, b)`:
///
/// `o` requires that `a <= b`, but this does not hold
- ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
+ ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region),
/// `GenericBoundFailure(p, s, a)
///
/// The parameter/associated-type `p` must be known to outlive the lifetime
/// `a` (but none of the known bounds are sufficient).
- GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region),
+ GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, &'tcx Region),
/// `SubSupConflict(v, sub_origin, sub_r, sup_origin, sup_r)`:
///
/// `sub_r <= sup_r` does not hold.
SubSupConflict(RegionVariableOrigin,
SubregionOrigin<'tcx>,
- Region,
+ &'tcx Region,
SubregionOrigin<'tcx>,
- Region),
+ &'tcx Region),
/// For subsets of `ConcreteFailure` and `SubSupConflict`, we can derive
/// more specific errors message by suggesting to the user where they
#[derive(Clone, Debug)]
pub enum ProcessedErrorOrigin<'tcx> {
- ConcreteFailure(SubregionOrigin<'tcx>, Region, Region),
+ ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region),
VariableFailure(RegionVariableOrigin),
}
}
}
-pub type CombineMap = FnvHashMap<TwoRegions, RegionVid>;
+pub type CombineMap<'tcx> = FnvHashMap<TwoRegions<'tcx>, RegionVid>;
pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
// Constraints of the form `A <= B` introduced by the region
// checker. Here at least one of `A` and `B` must be a region
// variable.
- constraints: RefCell<FnvHashMap<Constraint, SubregionOrigin<'tcx>>>,
+ constraints: RefCell<FnvHashMap<Constraint<'tcx>, SubregionOrigin<'tcx>>>,
// A "verify" is something that we need to verify after inference is
// done, but which does not directly affect inference in any way.
// a bit of a hack but seems to work.
givens: RefCell<FnvHashSet<(ty::FreeRegion, ty::RegionVid)>>,
- lubs: RefCell<CombineMap>,
- glbs: RefCell<CombineMap>,
+ lubs: RefCell<CombineMap<'tcx>>,
+ glbs: RefCell<CombineMap<'tcx>>,
skolemization_count: Cell<u32>,
bound_count: Cell<u32>,
// otherwise we end up adding entries for things like the lower
// bound on a variable and so forth, which can never be rolled
// back.
- undo_log: RefCell<Vec<UndoLogEntry>>,
+ undo_log: RefCell<Vec<UndoLogEntry<'tcx>>>,
unification_table: RefCell<UnificationTable<ty::RegionVid>>,
// This contains the results of inference. It begins as an empty
// option and only acquires a value after inference is complete.
- values: RefCell<Option<Vec<VarValue>>>,
+ values: RefCell<Option<Vec<VarValue<'tcx>>>>,
}
pub struct RegionSnapshot {
}
}
-struct TaintSet {
+struct TaintSet<'tcx> {
directions: TaintDirections,
- regions: FnvHashSet<ty::Region>
+ regions: FnvHashSet<&'tcx ty::Region>
}
-impl TaintSet {
+impl<'a, 'gcx, 'tcx> TaintSet<'tcx> {
fn new(directions: TaintDirections,
- initial_region: ty::Region)
+ initial_region: &'tcx ty::Region)
-> Self {
let mut regions = FnvHashSet();
regions.insert(initial_region);
}
fn fixed_point(&mut self,
- undo_log: &[UndoLogEntry],
- verifys: &[Verify]) {
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ undo_log: &[UndoLogEntry<'tcx>],
+ verifys: &[Verify<'tcx>]) {
let mut prev_len = 0;
while prev_len < self.len() {
debug!("tainted: prev_len = {:?} new_len = {:?}",
for undo_entry in undo_log {
match undo_entry {
&AddConstraint(ConstrainVarSubVar(a, b)) => {
- self.add_edge(ReVar(a), ReVar(b));
+ self.add_edge(tcx.mk_region(ReVar(a)),
+ tcx.mk_region(ReVar(b)));
}
&AddConstraint(ConstrainRegSubVar(a, b)) => {
- self.add_edge(a, ReVar(b));
+ self.add_edge(a, tcx.mk_region(ReVar(b)));
}
&AddConstraint(ConstrainVarSubReg(a, b)) => {
- self.add_edge(ReVar(a), b);
+ self.add_edge(tcx.mk_region(ReVar(a)), b);
}
&AddConstraint(ConstrainRegSubReg(a, b)) => {
self.add_edge(a, b);
}
&AddGiven(a, b) => {
- self.add_edge(ReFree(a), ReVar(b));
+ self.add_edge(tcx.mk_region(ReFree(a)),
+ tcx.mk_region(ReVar(b)));
}
&AddVerify(i) => {
verifys[i].bound.for_each_region(&mut |b| {
}
}
- fn into_set(self) -> FnvHashSet<ty::Region> {
+ fn into_set(self) -> FnvHashSet<&'tcx ty::Region> {
self.regions
}
}
fn add_edge(&mut self,
- source: ty::Region,
- target: ty::Region) {
+ source: &'tcx ty::Region,
+ target: &'tcx ty::Region) {
if self.directions.incoming {
if self.regions.contains(&target) {
self.regions.insert(source);
.rollback_to(snapshot.region_snapshot);
}
- pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry) {
+ pub fn rollback_undo_entry(&self, undo_entry: UndoLogEntry<'tcx>) {
match undo_entry {
OpenSnapshot => {
panic!("Failure to observe stack discipline");
/// The `snapshot` argument to this function is not really used;
/// it's just there to make it explicit which snapshot bounds the
/// skolemized region that results. It should always be the top-most snapshot.
- pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot) -> Region {
+ pub fn push_skolemized(&self, br: ty::BoundRegion, snapshot: &RegionSnapshot)
+ -> &'tcx Region {
assert!(self.in_snapshot());
assert!(self.undo_log.borrow()[snapshot.length] == OpenSnapshot);
let sc = self.skolemization_count.get();
self.skolemization_count.set(sc + 1);
- ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)
+ self.tcx.mk_region(ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br))
}
/// Removes all the edges to/from the skolemized regions that are
/// completes to remove all trace of the skolemized regions
/// created in that time.
pub fn pop_skolemized(&self,
- skols: &FnvHashSet<ty::Region>,
+ skols: &FnvHashSet<&'tcx ty::Region>,
snapshot: &RegionSnapshot) {
debug!("pop_skolemized_regions(skols={:?})", skols);
skols.len());
debug_assert! {
skols.iter()
- .all(|k| match *k {
+ .all(|&k| match *k {
ty::ReSkolemized(index, _) =>
index.index >= first_to_pop &&
index.index < last_to_pop,
self.skolemization_count.set(snapshot.skolemization_count);
return;
- fn kill_constraint(skols: &FnvHashSet<ty::Region>,
- undo_entry: &UndoLogEntry)
- -> bool {
+ fn kill_constraint<'tcx>(skols: &FnvHashSet<&'tcx ty::Region>,
+ undo_entry: &UndoLogEntry<'tcx>)
+ -> bool {
match undo_entry {
&AddConstraint(ConstrainVarSubVar(_, _)) =>
false,
}
- pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
+ pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> &'tcx Region {
// Creates a fresh bound variable for use in GLB computations.
// See discussion of GLB computation in the large comment at
// the top of this file for more details.
bug!("rollover in RegionInference new_bound()");
}
- ReLateBound(debruijn, BrFresh(sc))
+ self.tcx.mk_region(ReLateBound(debruijn, BrFresh(sc)))
}
fn values_are_none(&self) -> bool {
self.values.borrow().is_none()
}
- fn add_constraint(&self, constraint: Constraint, origin: SubregionOrigin<'tcx>) {
+ fn add_constraint(&self, constraint: Constraint<'tcx>, origin: SubregionOrigin<'tcx>) {
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
}
}
- pub fn make_eqregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) {
+ pub fn make_eqregion(&self,
+ origin: SubregionOrigin<'tcx>,
+ sub: &'tcx Region,
+ sup: &'tcx Region) {
if sub != sup {
// Eventually, it would be nice to add direct support for
// equating regions.
self.make_subregion(origin.clone(), sub, sup);
self.make_subregion(origin, sup, sub);
- if let (ty::ReVar(sub), ty::ReVar(sup)) = (sub, sup) {
+ if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) {
self.unification_table.borrow_mut().union(sub, sup);
}
}
}
- pub fn make_subregion(&self, origin: SubregionOrigin<'tcx>, sub: Region, sup: Region) {
+ pub fn make_subregion(&self,
+ origin: SubregionOrigin<'tcx>,
+ sub: &'tcx Region,
+ sup: &'tcx Region) {
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
origin);
match (sub, sup) {
- (ReEarlyBound(..), _) |
- (ReLateBound(..), _) |
- (_, ReEarlyBound(..)) |
- (_, ReLateBound(..)) => {
+ (&ReEarlyBound(..), _) |
+ (&ReLateBound(..), _) |
+ (_, &ReEarlyBound(..)) |
+ (_, &ReLateBound(..)) => {
span_bug!(origin.span(),
"cannot relate bound region: {:?} <= {:?}",
sub,
sup);
}
- (_, ReStatic) => {
+ (_, &ReStatic) => {
// all regions are subregions of static, so we can ignore this
}
- (ReVar(sub_id), ReVar(sup_id)) => {
+ (&ReVar(sub_id), &ReVar(sup_id)) => {
self.add_constraint(ConstrainVarSubVar(sub_id, sup_id), origin);
}
- (r, ReVar(sup_id)) => {
- self.add_constraint(ConstrainRegSubVar(r, sup_id), origin);
+ (_, &ReVar(sup_id)) => {
+ self.add_constraint(ConstrainRegSubVar(sub, sup_id), origin);
}
- (ReVar(sub_id), r) => {
- self.add_constraint(ConstrainVarSubReg(sub_id, r), origin);
+ (&ReVar(sub_id), _) => {
+ self.add_constraint(ConstrainVarSubReg(sub_id, sup), origin);
}
_ => {
self.add_constraint(ConstrainRegSubReg(sub, sup), origin);
pub fn verify_generic_bound(&self,
origin: SubregionOrigin<'tcx>,
kind: GenericKind<'tcx>,
- sub: Region,
- bound: VerifyBound) {
+ sub: &'tcx Region,
+ bound: VerifyBound<'tcx>) {
self.add_verify(Verify {
kind: kind,
origin: origin,
});
}
- pub fn lub_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region {
+ pub fn lub_regions(&self,
+ origin: SubregionOrigin<'tcx>,
+ a: &'tcx Region,
+ b: &'tcx Region)
+ -> &'tcx Region {
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
debug!("RegionVarBindings: lub_regions({:?}, {:?})", a, b);
- if a == ty::ReStatic || b == ty::ReStatic {
- ReStatic // nothing lives longer than static
- } else if a == b {
- a // LUB(a,a) = a
- } else {
- self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| {
- this.make_subregion(origin.clone(), old_r, new_r)
- })
+ match (a, b) {
+ (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
+ r // nothing lives longer than static
+ }
+
+ _ if a == b => {
+ a // LUB(a,a) = a
+ }
+
+ _ => {
+ self.combine_vars(Lub, a, b, origin.clone(), |this, old_r, new_r| {
+ this.make_subregion(origin.clone(), old_r, new_r)
+ })
+ }
}
}
- pub fn glb_regions(&self, origin: SubregionOrigin<'tcx>, a: Region, b: Region) -> Region {
+ pub fn glb_regions(&self,
+ origin: SubregionOrigin<'tcx>,
+ a: &'tcx Region,
+ b: &'tcx Region)
+ -> &'tcx Region {
// cannot add constraints once regions are resolved
assert!(self.values_are_none());
debug!("RegionVarBindings: glb_regions({:?}, {:?})", a, b);
match (a, b) {
- (ReStatic, r) | (r, ReStatic) => {
+ (&ReStatic, r) | (r, &ReStatic) => {
r // static lives longer than everything else
}
}
}
- pub fn resolve_var(&self, rid: RegionVid) -> ty::Region {
+ pub fn resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region {
match *self.values.borrow() {
None => {
span_bug!((*self.var_origins.borrow())[rid.index as usize].span(),
been computed!")
}
Some(ref values) => {
- let r = lookup(values, rid);
+ let r = lookup(self.tcx, values, rid);
debug!("resolve_var({:?}) = {:?}", rid, r);
r
}
}
}
- pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> ty::Region {
- ty::ReVar(self.unification_table.borrow_mut().find_value(rid).min_vid)
+ pub fn opportunistic_resolve_var(&self, rid: RegionVid) -> &'tcx ty::Region {
+ let vid = self.unification_table.borrow_mut().find_value(rid).min_vid;
+ self.tcx.mk_region(ty::ReVar(vid))
}
- fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap> {
+ fn combine_map(&self, t: CombineMapType) -> &RefCell<CombineMap<'tcx>> {
match t {
Glb => &self.glbs,
Lub => &self.lubs,
pub fn combine_vars<F>(&self,
t: CombineMapType,
- a: Region,
- b: Region,
+ a: &'tcx Region,
+ b: &'tcx Region,
origin: SubregionOrigin<'tcx>,
mut relate: F)
- -> Region
- where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, Region, Region)
+ -> &'tcx Region
+ where F: FnMut(&RegionVarBindings<'a, 'gcx, 'tcx>, &'tcx Region, &'tcx Region)
{
let vars = TwoRegions { a: a, b: b };
if let Some(&c) = self.combine_map(t).borrow().get(&vars) {
- return ReVar(c);
+ return self.tcx.mk_region(ReVar(c));
}
let c = self.new_region_var(MiscVariable(origin.span()));
self.combine_map(t).borrow_mut().insert(vars, c);
if self.in_snapshot() {
self.undo_log.borrow_mut().push(AddCombination(t, vars));
}
- relate(self, a, ReVar(c));
- relate(self, b, ReVar(c));
+ relate(self, a, self.tcx.mk_region(ReVar(c)));
+ relate(self, b, self.tcx.mk_region(ReVar(c)));
debug!("combine_vars() c={:?}", c);
- ReVar(c)
+ self.tcx.mk_region(ReVar(c))
}
pub fn vars_created_since_snapshot(&self, mark: &RegionSnapshot) -> Vec<RegionVid> {
/// related to other regions.
pub fn tainted(&self,
mark: &RegionSnapshot,
- r0: Region,
+ r0: &'tcx Region,
directions: TaintDirections)
- -> FnvHashSet<ty::Region> {
+ -> FnvHashSet<&'tcx ty::Region> {
debug!("tainted(mark={:?}, r0={:?}, directions={:?})",
mark, r0, directions);
// edges and add any new regions we find to result_set. This
// is not a terribly efficient implementation.
let mut taint_set = TaintSet::new(directions, r0);
- taint_set.fixed_point(&self.undo_log.borrow()[mark.length..],
+ taint_set.fixed_point(self.tcx,
+ &self.undo_log.borrow()[mark.length..],
&self.verifys.borrow());
debug!("tainted: result={:?}", taint_set.regions);
return taint_set.into_set();
errors
}
- fn lub_concrete_regions(&self, free_regions: &FreeRegionMap, a: Region, b: Region) -> Region {
+ fn lub_concrete_regions(&self,
+ free_regions: &FreeRegionMap,
+ a: &'tcx Region,
+ b: &'tcx Region)
+ -> &'tcx Region {
match (a, b) {
- (ReLateBound(..), _) |
- (_, ReLateBound(..)) |
- (ReEarlyBound(..), _) |
- (_, ReEarlyBound(..)) |
- (ReErased, _) |
- (_, ReErased) => {
+ (&ReLateBound(..), _) |
+ (_, &ReLateBound(..)) |
+ (&ReEarlyBound(..), _) |
+ (_, &ReEarlyBound(..)) |
+ (&ReErased, _) |
+ (_, &ReErased) => {
bug!("cannot relate region: LUB({:?}, {:?})", a, b);
}
- (ReStatic, _) | (_, ReStatic) => {
- ReStatic // nothing lives longer than static
+ (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
+ r // nothing lives longer than static
}
- (ReEmpty, r) | (r, ReEmpty) => {
+ (&ReEmpty, r) | (r, &ReEmpty) => {
r // everything lives longer than empty
}
- (ReVar(v_id), _) | (_, ReVar(v_id)) => {
+ (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
span_bug!((*self.var_origins.borrow())[v_id.index as usize].span(),
"lub_concrete_regions invoked with non-concrete \
regions: {:?}, {:?}",
b);
}
- (ReFree(ref fr), ReScope(s_id)) |
- (ReScope(s_id), ReFree(ref fr)) => {
- let f = ReFree(*fr);
+ (&ReFree(fr), &ReScope(s_id)) |
+ (&ReScope(s_id), &ReFree(fr)) => {
// A "free" region can be interpreted as "some region
// at least as big as the block fr.scope_id". So, we can
// reasonably compare free regions and scopes:
// if the free region's scope `fr.scope_id` is bigger than
// the scope region `s_id`, then the LUB is the free
// region itself:
- f
+ self.tcx.mk_region(ReFree(fr))
} else {
// otherwise, we don't know what the free region is,
// so we must conservatively say the LUB is static:
- ReStatic
+ self.tcx.mk_region(ReStatic)
}
}
- (ReScope(a_id), ReScope(b_id)) => {
+ (&ReScope(a_id), &ReScope(b_id)) => {
// The region corresponding to an outer block is a
// subtype of the region corresponding to an inner
// block.
- ReScope(self.tcx.region_maps.nearest_common_ancestor(a_id, b_id))
+ self.tcx.mk_region(ReScope(
+ self.tcx.region_maps.nearest_common_ancestor(a_id, b_id)))
}
- (ReFree(a_fr), ReFree(b_fr)) => {
- free_regions.lub_free_regions(a_fr, b_fr)
+ (&ReFree(a_fr), &ReFree(b_fr)) => {
+ self.tcx.mk_region(free_regions.lub_free_regions(a_fr, b_fr))
}
// For these types, we cannot define any additional
// relationship:
- (ReSkolemized(..), _) |
- (_, ReSkolemized(..)) => {
+ (&ReSkolemized(..), _) |
+ (_, &ReSkolemized(..)) => {
if a == b {
a
} else {
- ReStatic
+ self.tcx.mk_region(ReStatic)
}
}
}
// ______________________________________________________________________
#[derive(Copy, Clone, Debug)]
-pub enum VarValue {
- Value(Region),
+pub enum VarValue<'tcx> {
+ Value(&'tcx Region),
ErrorValue,
}
struct RegionAndOrigin<'tcx> {
- region: Region,
+ region: &'tcx Region,
origin: SubregionOrigin<'tcx>,
}
-type RegionGraph = graph::Graph<(), Constraint>;
+type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>;
impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
fn infer_variable_values(&self,
free_regions: &FreeRegionMap,
errors: &mut Vec<RegionResolutionError<'tcx>>,
subject: ast::NodeId)
- -> Vec<VarValue> {
+ -> Vec<VarValue<'tcx>> {
let mut var_data = self.construct_var_data();
// Dorky hack to cause `dump_constraints` to only get called
var_data
}
- fn construct_var_data(&self) -> Vec<VarValue> {
+ fn construct_var_data(&self) -> Vec<VarValue<'tcx>> {
(0..self.num_vars() as usize)
- .map(|_| Value(ty::ReEmpty))
+ .map(|_| Value(self.tcx.mk_region(ty::ReEmpty)))
.collect()
}
}
}
- fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue]) {
+ fn expansion(&self, free_regions: &FreeRegionMap, var_values: &mut [VarValue<'tcx>]) {
self.iterate_until_fixed_point("Expansion", |constraint, origin| {
debug!("expansion: constraint={:?} origin={:?}",
constraint, origin);
fn expand_node(&self,
free_regions: &FreeRegionMap,
- a_region: Region,
+ a_region: &'tcx Region,
b_vid: RegionVid,
- b_data: &mut VarValue)
+ b_data: &mut VarValue<'tcx>)
-> bool {
debug!("expand_node({:?}, {:?} == {:?})",
a_region,
b_data);
// Check if this relationship is implied by a given.
- match a_region {
+ match *a_region {
ty::ReFree(fr) => {
if self.givens.borrow().contains(&(fr, b_vid)) {
debug!("given");
/// and check that they are satisfied.
fn collect_errors(&self,
free_regions: &FreeRegionMap,
- var_data: &mut Vec<VarValue>,
+ var_data: &mut Vec<VarValue<'tcx>>,
errors: &mut Vec<RegionResolutionError<'tcx>>) {
let constraints = self.constraints.borrow();
for (constraint, origin) in constraints.iter() {
for verify in self.verifys.borrow().iter() {
debug!("collect_errors: verify={:?}", verify);
- let sub = normalize(var_data, verify.region);
+ let sub = normalize(self.tcx, var_data, verify.region);
if verify.bound.is_met(self.tcx, free_regions, var_data, sub) {
continue;
}
/// and create a `RegionResolutionError` for each of them.
fn collect_var_errors(&self,
free_regions: &FreeRegionMap,
- var_data: &[VarValue],
- graph: &RegionGraph,
+ var_data: &[VarValue<'tcx>],
+ graph: &RegionGraph<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>) {
debug!("collect_var_errors");
}
}
- fn construct_graph(&self) -> RegionGraph {
+ fn construct_graph(&self) -> RegionGraph<'tcx> {
let num_vars = self.num_vars();
let constraints = self.constraints.borrow();
fn collect_error_for_expanding_node(&self,
free_regions: &FreeRegionMap,
- graph: &RegionGraph,
+ graph: &RegionGraph<'tcx>,
dup_vec: &mut [u32],
node_idx: RegionVid,
errors: &mut Vec<RegionResolutionError<'tcx>>) {
// the user will more likely get a specific suggestion.
fn free_regions_first(a: &RegionAndOrigin, b: &RegionAndOrigin) -> Ordering {
match (a.region, b.region) {
- (ReFree(..), ReFree(..)) => Equal,
- (ReFree(..), _) => Less,
- (_, ReFree(..)) => Greater,
+ (&ReFree(..), &ReFree(..)) => Equal,
+ (&ReFree(..), _) => Less,
+ (_, &ReFree(..)) => Greater,
(_, _) => Equal,
}
}
}
fn collect_concrete_regions(&self,
- graph: &RegionGraph,
+ graph: &RegionGraph<'tcx>,
orig_node_idx: RegionVid,
dir: Direction,
dup_vec: &mut [u32])
fn process_edges<'a, 'gcx, 'tcx>(this: &RegionVarBindings<'a, 'gcx, 'tcx>,
state: &mut WalkState<'tcx>,
- graph: &RegionGraph,
+ graph: &RegionGraph<'tcx>,
source_vid: RegionVid,
dir: Direction) {
debug!("process_edges(source_vid={:?}, dir={:?})", source_vid, dir);
}
fn iterate_until_fixed_point<F>(&self, tag: &str, mut body: F)
- where F: FnMut(&Constraint, &SubregionOrigin<'tcx>) -> bool
+ where F: FnMut(&Constraint<'tcx>, &SubregionOrigin<'tcx>) -> bool
{
let mut iteration = 0;
let mut changed = true;
}
-fn normalize(values: &Vec<VarValue>, r: ty::Region) -> ty::Region {
- match r {
- ty::ReVar(rid) => lookup(values, rid),
+fn normalize<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ values: &Vec<VarValue<'tcx>>,
+ r: &'tcx ty::Region)
+ -> &'tcx ty::Region {
+ match *r {
+ ty::ReVar(rid) => lookup(tcx, values, rid),
_ => r,
}
}
-fn lookup(values: &Vec<VarValue>, rid: ty::RegionVid) -> ty::Region {
+fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ values: &Vec<VarValue<'tcx>>,
+ rid: ty::RegionVid)
+ -> &'tcx ty::Region {
match values[rid.index as usize] {
Value(r) => r,
- ErrorValue => ReStatic, // Previously reported error.
+ ErrorValue => tcx.mk_region(ReStatic), // Previously reported error.
}
}
}
}
-impl<'a, 'gcx, 'tcx> VerifyBound {
- fn for_each_region(&self, f: &mut FnMut(ty::Region)) {
+impl<'a, 'gcx, 'tcx> VerifyBound<'tcx> {
+ fn for_each_region(&self, f: &mut FnMut(&'tcx ty::Region)) {
match self {
&VerifyBound::AnyRegion(ref rs) |
&VerifyBound::AllRegions(ref rs) => for &r in rs {
pub fn must_hold(&self) -> bool {
match self {
- &VerifyBound::AnyRegion(ref bs) => bs.contains(&ty::ReStatic),
+ &VerifyBound::AnyRegion(ref bs) => bs.contains(&&ty::ReStatic),
&VerifyBound::AllRegions(ref bs) => bs.is_empty(),
&VerifyBound::AnyBound(ref bs) => bs.iter().any(|b| b.must_hold()),
&VerifyBound::AllBounds(ref bs) => bs.iter().all(|b| b.must_hold()),
pub fn cannot_hold(&self) -> bool {
match self {
&VerifyBound::AnyRegion(ref bs) => bs.is_empty(),
- &VerifyBound::AllRegions(ref bs) => bs.contains(&ty::ReEmpty),
+ &VerifyBound::AllRegions(ref bs) => bs.contains(&&ty::ReEmpty),
&VerifyBound::AnyBound(ref bs) => bs.iter().all(|b| b.cannot_hold()),
&VerifyBound::AllBounds(ref bs) => bs.iter().any(|b| b.cannot_hold()),
}
}
- pub fn or(self, vb: VerifyBound) -> VerifyBound {
+ pub fn or(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
if self.must_hold() || vb.cannot_hold() {
self
} else if self.cannot_hold() || vb.must_hold() {
}
}
- pub fn and(self, vb: VerifyBound) -> VerifyBound {
+ pub fn and(self, vb: VerifyBound<'tcx>) -> VerifyBound<'tcx> {
if self.must_hold() && vb.must_hold() {
self
} else if self.cannot_hold() && vb.cannot_hold() {
fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
free_regions: &FreeRegionMap,
- var_values: &Vec<VarValue>,
- min: ty::Region)
+ var_values: &Vec<VarValue<'tcx>>,
+ min: &'tcx ty::Region)
-> bool {
match self {
&VerifyBound::AnyRegion(ref rs) =>
rs.iter()
- .map(|&r| normalize(var_values, r))
+ .map(|&r| normalize(tcx, var_values, r))
.any(|r| free_regions.is_subregion_of(tcx, min, r)),
&VerifyBound::AllRegions(ref rs) =>
rs.iter()
- .map(|&r| normalize(var_values, r))
+ .map(|&r| normalize(tcx, var_values, r))
.all(|r| free_regions.is_subregion_of(tcx, min, r)),
&VerifyBound::AnyBound(ref bs) =>
}
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
- match r {
- ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid),
- _ => r,
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+ match *r {
+ ty::ReVar(rid) => self.infcx.region_vars.opportunistic_resolve_var(rid),
+ _ => r,
}
}
}
}
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
- match r {
- ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid),
- _ => r,
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+ match *r {
+ ty::ReVar(rid) => self.infcx.region_vars.resolve_var(rid),
+ _ => r,
}
}
}
}
}
- fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region> {
debug!("{}.regions({:?}, {:?}) self.cause={:?}",
self.tag(), a, b, self.fields.cause);
// FIXME -- we have more fine-grained information available
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(collections)]
+#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
#![feature(enumset)]
declare_lint! {
pub TRANSMUTE_FROM_FN_ITEM_TYPES,
- Warn,
+ Deny,
"transmute from function item type to pointer-sized type erroneously allowed"
}
for (lint_id, level, span) in v {
let (now, now_source) = self.lints().get_level_source(lint_id);
if now == Forbid && level != Forbid {
- let lint_name = lint_id.as_str();
+ let lint_name = lint_id.to_string();
let mut diag_builder = struct_span_err!(self.sess(), span, E0453,
"{}({}) overruled by outer forbid({})",
level.as_str(), lint_name,
for &(lint, span, ref msg) in v {
span_bug!(span,
"unprocessed lint {} at {}: {}",
- lint.as_str(), tcx.map.node_to_string(*id), *msg)
+ lint.to_string(), tcx.map.node_to_string(*id), *msg)
}
}
// in the iteration code.
for (_, v) in sess.lints.borrow().iter() {
for &(lint, span, ref msg) in v {
- span_bug!(span, "unprocessed lint {}: {}", lint.as_str(), *msg)
+ span_bug!(span, "unprocessed lint {}: {}", lint.to_string(), *msg)
}
}
}
}
/// Get the name of the lint.
- pub fn as_str(&self) -> String {
+ pub fn to_string(&self) -> String {
self.lint.name_lower()
}
}
fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind;
fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> ty::ClosureTy<'tcx>;
- fn item_variances(&self, def: DefId) -> ty::ItemVariances;
+ fn item_variances(&self, def: DefId) -> Vec<ty::Variance>;
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Ty<'tcx>;
fn is_default_impl(&self, impl_did: DefId) -> bool;
fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool;
fn is_foreign_item(&self, did: DefId) -> bool;
- fn is_static_method(&self, did: DefId) -> bool;
fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool;
fn is_typedef(&self, did: DefId) -> bool;
fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { bug!("closure_kind") }
fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-> ty::ClosureTy<'tcx> { bug!("closure_ty") }
- fn item_variances(&self, def: DefId) -> ty::ItemVariances { bug!("item_variances") }
+ fn item_variances(&self, def: DefId) -> Vec<ty::Variance> { bug!("item_variances") }
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { bug!("repr_attrs") }
fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-> Ty<'tcx> { bug!("item_type") }
fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool
{ bug!("is_extern_item") }
fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
- fn is_static_method(&self, did: DefId) -> bool { bug!("is_static_method") }
fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool { false }
fn is_typedef(&self, did: DefId) -> bool { bug!("is_typedef") }
Def::AssociatedTy(..) | Def::Method(_) | Def::AssociatedConst(_)
if self.tcx.trait_of_item(def.def_id()).is_some() => {
if let Some(substs) = self.tcx.tables.borrow().item_substs.get(&id) {
- match substs.substs.types[0].sty {
+ match substs.substs.type_at(0).sty {
TyEnum(tyid, _) | TyStruct(tyid, _) => {
self.check_def_id(tyid.did)
}
borrow_id: ast::NodeId,
borrow_span: Span,
cmt: mc::cmt<'tcx>,
- loan_region: ty::Region,
+ loan_region: &'tcx ty::Region,
bk: ty::BorrowKind,
loan_cause: LoanCause);
for arg in &decl.inputs {
let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
- let fn_body_scope = self.tcx().region_maps.node_extent(body.id);
+ let fn_body_scope_r = self.tcx().node_scope_region(body.id);
let arg_cmt = self.mc.cat_rvalue(
arg.id,
arg.pat.span,
- ty::ReScope(fn_body_scope), // Args live only as long as the fn body.
+ fn_body_scope_r, // Args live only as long as the fn body.
arg_ty);
self.walk_irrefutable_pat(arg_cmt, &arg.pat);
fn borrow_expr(&mut self,
expr: &hir::Expr,
- r: ty::Region,
+ r: &'tcx ty::Region,
bk: ty::BorrowKind,
cause: LoanCause) {
debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})",
hir::ExprMatch(ref discr, ref arms, _) => {
let discr_cmt = return_if_err!(self.mc.cat_expr(&discr));
- self.borrow_expr(&discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
+ let r = self.tcx().mk_region(ty::ReEmpty);
+ self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant);
// treatment of the discriminant is handled while walking the arms.
for arm in arms {
// make sure that the thing we are pointing out stays valid
// for the lifetime `scope_r` of the resulting ptr:
let expr_ty = return_if_err!(self.mc.infcx.node_ty(expr.id));
- if let ty::TyRef(&r, _) = expr_ty.sty {
+ if let ty::TyRef(r, _) = expr_ty.sty {
let bk = ty::BorrowKind::from_mutbl(m);
self.borrow_expr(&base, r, bk, AddrOf);
}
let callee_ty = return_if_err!(self.mc.infcx.expr_ty_adjusted(callee));
debug!("walk_callee: callee={:?} callee_ty={:?}",
callee, callee_ty);
- let call_scope = self.tcx().region_maps.node_extent(call.id);
match callee_ty.sty {
ty::TyFnDef(..) | ty::TyFnPtr(_) => {
self.consume_expr(callee);
};
match overloaded_call_type {
FnMutOverloadedCall => {
+ let call_scope_r = self.tcx().node_scope_region(call.id);
self.borrow_expr(callee,
- ty::ReScope(call_scope),
+ call_scope_r,
ty::MutBorrow,
ClosureInvocation);
}
FnOverloadedCall => {
+ let call_scope_r = self.tcx().node_scope_region(call.id);
self.borrow_expr(callee,
- ty::ReScope(call_scope),
+ call_scope_r,
ty::ImmBorrow,
ClosureInvocation);
}
};
let bk = ty::BorrowKind::from_mutbl(m);
self.delegate.borrow(expr.id, expr.span, cmt,
- *r, bk, AutoRef);
+ r, bk, AutoRef);
}
}
}
self.delegate.borrow(expr.id,
expr.span,
cmt_base,
- *r,
+ r,
ty::BorrowKind::from_mutbl(m),
AutoRef);
}
// Converting from a &T to *T (or &mut T to *mut T) is
// treated as borrowing it for the enclosing temporary
// scope.
- let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
+ let r = self.tcx().node_scope_region(expr.id);
self.delegate.borrow(expr.id,
expr.span,
// methods are implicitly autoref'd which sadly does not use
// adjustments, so we must hardcode the borrow here.
- let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id));
+ let r = self.tcx().node_scope_region(expr.id);
let bk = ty::ImmBorrow;
for &arg in &rhs {
// It is also a borrow or copy/move of the value being matched.
match bmode {
hir::BindByRef(m) => {
- if let ty::TyRef(&r, _) = pat_ty.sty {
+ if let ty::TyRef(r, _) = pat_ty.sty {
let bk = ty::BorrowKind::from_mutbl(m);
delegate.borrow(pat.id, pat.span, cmt_pat, r, bk, RefBinding);
}
for implied_bound in implied_bounds {
debug!("implied bound: {:?}", implied_bound);
match *implied_bound {
- ImpliedBound::RegionSubRegion(ty::ReFree(free_a), ty::ReFree(free_b)) => {
+ ImpliedBound::RegionSubRegion(&ty::ReFree(free_a), &ty::ReFree(free_b)) => {
self.relate_free_regions(free_a, free_b);
}
ImpliedBound::RegionSubRegion(..) |
}
ty::Predicate::RegionOutlives(ty::Binder(ty::OutlivesPredicate(r_a, r_b))) => {
match (r_a, r_b) {
- (ty::ReStatic, ty::ReFree(_)) => {},
- (ty::ReFree(fr_a), ty::ReStatic) => self.relate_to_static(fr_a),
- (ty::ReFree(fr_a), ty::ReFree(fr_b)) => {
+ (&ty::ReStatic, &ty::ReFree(_)) => {},
+ (&ty::ReFree(fr_a), &ty::ReStatic) => self.relate_to_static(fr_a),
+ (&ty::ReFree(fr_a), &ty::ReFree(fr_b)) => {
// Record that `'a:'b`. Or, put another way, `'b <= 'a`.
self.relate_free_regions(fr_b, fr_a);
}
/// inference* and sadly the logic is somewhat duplicated with the code in infer.rs.
pub fn is_subregion_of(&self,
tcx: TyCtxt,
- sub_region: ty::Region,
- super_region: ty::Region)
+ sub_region: &ty::Region,
+ super_region: &ty::Region)
-> bool {
let result = sub_region == super_region || {
match (sub_region, super_region) {
- (ty::ReEmpty, _) |
- (_, ty::ReStatic) =>
+ (&ty::ReEmpty, _) |
+ (_, &ty::ReStatic) =>
true,
- (ty::ReScope(sub_scope), ty::ReScope(super_scope)) =>
+ (&ty::ReScope(sub_scope), &ty::ReScope(super_scope)) =>
tcx.region_maps.is_subscope_of(sub_scope, super_scope),
- (ty::ReScope(sub_scope), ty::ReFree(fr)) =>
+ (&ty::ReScope(sub_scope), &ty::ReFree(fr)) =>
tcx.region_maps.is_subscope_of(sub_scope, fr.scope) ||
self.is_static(fr),
- (ty::ReFree(sub_fr), ty::ReFree(super_fr)) =>
+ (&ty::ReFree(sub_fr), &ty::ReFree(super_fr)) =>
self.sub_free_region(sub_fr, super_fr),
- (ty::ReStatic, ty::ReFree(sup_fr)) =>
+ (&ty::ReStatic, &ty::ReFree(sup_fr)) =>
self.is_static(sup_fr),
_ =>
#[derive(Clone, PartialEq)]
pub enum Categorization<'tcx> {
- Rvalue(ty::Region), // temporary val, argument is its scope
+ Rvalue(&'tcx ty::Region), // temporary val, argument is its scope
StaticItem,
Upvar(Upvar), // upvar referenced by closure env
Local(ast::NodeId), // local variable
- Deref(cmt<'tcx>, usize, PointerKind), // deref of a ptr
+ Deref(cmt<'tcx>, usize, PointerKind<'tcx>), // deref of a ptr
Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc
Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1)
// different kinds of pointers:
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
-pub enum PointerKind {
+pub enum PointerKind<'tcx> {
/// `Box<T>`
Unique,
/// `&T`
- BorrowedPtr(ty::BorrowKind, ty::Region),
+ BorrowedPtr(ty::BorrowKind, &'tcx ty::Region),
/// `*T`
UnsafePtr(hir::Mutability),
/// Implicit deref of the `&T` that results from an overloaded index `[]`.
- Implicit(ty::BorrowKind, ty::Region),
+ Implicit(ty::BorrowKind, &'tcx ty::Region),
}
// We use the term "interior" to mean "something reachable from the
// We pun on *T to mean both actual deref of a ptr as well
// as accessing of components:
#[derive(Copy, Clone)]
-pub enum deref_kind {
- deref_ptr(PointerKind),
+pub enum deref_kind<'tcx> {
+ deref_ptr(PointerKind<'tcx>),
deref_interior(InteriorKind),
}
ty::TyRef(r, mt) => {
let kind = ty::BorrowKind::from_mutbl(mt.mutbl);
- Ok(deref_ptr(BorrowedPtr(kind, *r)))
+ Ok(deref_ptr(BorrowedPtr(kind, r)))
}
ty::TyRawPtr(ref mt) => {
};
// Region of environment pointer
- let env_region = ty::ReFree(ty::FreeRegion {
+ let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion {
// The environment of a closure is guaranteed to
// outlive any bindings introduced in the body of the
// closure itself.
scope: self.tcx().region_maps.item_extent(fn_body_id),
bound_region: ty::BrEnv
- });
+ }));
let env_ptr = BorrowedPtr(env_borrow_kind, env_region);
/// Returns the lifetime of a temporary created by expr with id `id`.
/// This could be `'static` if `id` is part of a constant expression.
- pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region {
- match self.infcx.temporary_scope(id) {
+ pub fn temporary_scope(&self, id: ast::NodeId) -> &'tcx ty::Region {
+ self.tcx().mk_region(match self.infcx.temporary_scope(id) {
Some(scope) => ty::ReScope(scope),
None => ty::ReStatic
- }
+ })
}
pub fn cat_rvalue_node(&self,
let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
self.temporary_scope(id)
} else {
- ty::ReStatic
+ self.tcx().mk_region(ty::ReStatic)
};
let ret = self.cat_rvalue(id, span, re, expr_ty);
debug!("cat_rvalue_node ret {:?}", ret);
pub fn cat_rvalue(&self,
cmt_id: ast::NodeId,
span: Span,
- temp_scope: ty::Region,
+ temp_scope: &'tcx ty::Region,
expr_ty: Ty<'tcx>) -> cmt<'tcx> {
let ret = Rc::new(cmt_ {
id:cmt_id,
}
}
-impl fmt::Debug for PointerKind {
+impl<'tcx> fmt::Debug for PointerKind<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Unique => write!(f, "Box"),
// (This is the special case aluded to in the
// doc-comment for this method)
let stmt_span = blk.stmts[r.first_statement_index as usize].span;
- Some(Span { lo: stmt_span.hi, ..blk.span })
+ Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id })
}
}
}
#[derive(PartialEq, Debug)]
enum ScopeChain<'a> {
- /// EarlyScope(['a, 'b, ...], s) extends s with early-bound
- /// lifetimes.
- EarlyScope(&'a [hir::LifetimeDef], Scope<'a>),
+ /// EarlyScope(['a, 'b, ...], start, s) extends s with early-bound
+ /// lifetimes, with consecutive parameter indices from `start`.
+ /// That is, 'a has index `start`, 'b has index `start + 1`, etc.
+ /// Indices before `start` correspond to other generic parameters
+ /// of a parent item (trait/impl of a method), or `Self` in traits.
+ EarlyScope(&'a [hir::LifetimeDef], u32, Scope<'a>),
/// LateScope(['a, 'b, ...], s) extends s with late-bound
/// lifetimes introduced by the declaration binder_id.
LateScope(&'a [hir::LifetimeDef], Scope<'a>),
hir::ItemImpl(_, _, ref generics, _, _, _) => {
// These kinds of items have only early bound lifetime parameters.
let lifetimes = &generics.lifetimes;
- this.with(EarlyScope(lifetimes, &ROOT_SCOPE), |old_scope, this| {
+ let start = if let hir::ItemTrait(..) = item.node {
+ 1 // Self comes before lifetimes
+ } else {
+ 0
+ };
+ this.with(EarlyScope(lifetimes, start, &ROOT_SCOPE), |old_scope, this| {
this.check_lifetime_defs(old_scope, lifetimes);
intravisit::walk_item(this, item);
});
FnScope { s, .. } => { scope = s; }
RootScope => { return; }
- EarlyScope(lifetimes, s) |
+ EarlyScope(lifetimes, _, s) |
LateScope(lifetimes, s) => {
for lifetime_def in lifetimes {
// FIXME (#24278): non-hygienic comparison
.cloned()
.partition(|l| self.map.late_bound.contains_key(&l.lifetime.id));
+ // Find the start of nested early scopes, e.g. in methods.
+ let mut start = 0;
+ if let EarlyScope(..) = *self.scope {
+ let parent = self.hir_map.expect_item(self.hir_map.get_parent(fn_id));
+ if let hir::ItemTrait(..) = parent.node {
+ start += 1; // Self comes first.
+ }
+ match parent.node {
+ hir::ItemTrait(_, ref generics, _, _) |
+ hir::ItemImpl(_, _, ref generics, _, _, _) => {
+ start += generics.lifetimes.len() + generics.ty_params.len();
+ }
+ _ => {}
+ }
+ }
+
let this = self;
- this.with(EarlyScope(&early, this.scope), move |old_scope, this| {
+ this.with(EarlyScope(&early, start as u32, this.scope), move |old_scope, this| {
this.with(LateScope(&late, this.scope), move |_, this| {
this.check_lifetime_defs(old_scope, &generics.lifetimes);
walk(this);
break;
}
- EarlyScope(lifetimes, s) => {
+ EarlyScope(lifetimes, start, s) => {
match search_lifetimes(lifetimes, lifetime_ref) {
- Some((mut index, lifetime_def)) => {
- // Adjust for nested early scopes, e.g. in methods.
- let mut parent = s;
- while let EarlyScope(lifetimes, s) = *parent {
- index += lifetimes.len() as u32;
- parent = s;
- }
- assert_eq!(*parent, RootScope);
-
+ Some((index, lifetime_def)) => {
let decl_id = lifetime_def.id;
- let def = DefEarlyBoundRegion(index, decl_id);
+ let def = DefEarlyBoundRegion(start + index, decl_id);
self.insert_lifetime(lifetime_ref, def);
return;
}
break;
}
- EarlyScope(lifetimes, s) |
+ EarlyScope(lifetimes, _, s) |
LateScope(lifetimes, s) => {
search_result = search_lifetimes(lifetimes, lifetime_ref);
if search_result.is_some() {
return;
}
- EarlyScope(lifetimes, s) |
+ EarlyScope(lifetimes, _, s) |
LateScope(lifetimes, s) => {
if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) {
signal_shadowing_problem(
Repeat(Operand<'tcx>, TypedConstVal<'tcx>),
/// &x or &mut x
- Ref(Region, BorrowKind, Lvalue<'tcx>),
+ Ref(&'tcx Region, BorrowKind, Lvalue<'tcx>),
/// length of a [X] or [X;n] value
Len(Lvalue<'tcx>),
type Item = BasicBlock;
type Iter = IntoIter<BasicBlock>;
}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]
+pub struct Location {
+ /// the location is within this block
+ pub block: BasicBlock,
+
+ /// the location is the start of the this statement; or, if `statement_index`
+ /// == num-statements, then the start of the terminator.
+ pub statement_index: usize,
+}
+
}
&Rvalue::Ref(reg, bk, ref lv) => {
let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
- Some(tcx.mk_ref(
- tcx.mk_region(reg),
+ Some(tcx.mk_ref(reg,
ty::TypeAndMut {
ty: lv_ty,
mutbl: bk.to_mutbl_lossy()
fn visit_statement(&mut self,
block: BasicBlock,
- statement: & $($mutability)* Statement<'tcx>) {
- self.super_statement(block, statement);
+ statement: & $($mutability)* Statement<'tcx>,
+ location: Location) {
+ self.super_statement(block, statement, location);
}
fn visit_assign(&mut self,
block: BasicBlock,
lvalue: & $($mutability)* Lvalue<'tcx>,
- rvalue: & $($mutability)* Rvalue<'tcx>) {
- self.super_assign(block, lvalue, rvalue);
+ rvalue: & $($mutability)* Rvalue<'tcx>,
+ location: Location) {
+ self.super_assign(block, lvalue, rvalue, location);
}
fn visit_terminator(&mut self,
block: BasicBlock,
- terminator: & $($mutability)* Terminator<'tcx>) {
- self.super_terminator(block, terminator);
+ terminator: & $($mutability)* Terminator<'tcx>,
+ location: Location) {
+ self.super_terminator(block, terminator, location);
}
fn visit_terminator_kind(&mut self,
block: BasicBlock,
- kind: & $($mutability)* TerminatorKind<'tcx>) {
- self.super_terminator_kind(block, kind);
+ kind: & $($mutability)* TerminatorKind<'tcx>,
+ location: Location) {
+ self.super_terminator_kind(block, kind, location);
}
fn visit_assert_message(&mut self,
- msg: & $($mutability)* AssertMessage<'tcx>) {
- self.super_assert_message(msg);
+ msg: & $($mutability)* AssertMessage<'tcx>,
+ location: Location) {
+ self.super_assert_message(msg, location);
}
fn visit_rvalue(&mut self,
- rvalue: & $($mutability)* Rvalue<'tcx>) {
- self.super_rvalue(rvalue);
+ rvalue: & $($mutability)* Rvalue<'tcx>,
+ location: Location) {
+ self.super_rvalue(rvalue, location);
}
fn visit_operand(&mut self,
- operand: & $($mutability)* Operand<'tcx>) {
- self.super_operand(operand);
+ operand: & $($mutability)* Operand<'tcx>,
+ location: Location) {
+ self.super_operand(operand, location);
}
fn visit_lvalue(&mut self,
lvalue: & $($mutability)* Lvalue<'tcx>,
- context: LvalueContext) {
- self.super_lvalue(lvalue, context);
+ context: LvalueContext,
+ location: Location) {
+ self.super_lvalue(lvalue, context, location);
}
fn visit_projection(&mut self,
lvalue: & $($mutability)* LvalueProjection<'tcx>,
- context: LvalueContext) {
- self.super_projection(lvalue, context);
+ context: LvalueContext,
+ location: Location) {
+ self.super_projection(lvalue, context, location);
}
fn visit_projection_elem(&mut self,
lvalue: & $($mutability)* LvalueElem<'tcx>,
- context: LvalueContext) {
- self.super_projection_elem(lvalue, context);
+ context: LvalueContext,
+ location: Location) {
+ self.super_projection_elem(lvalue, context, location);
}
fn visit_branch(&mut self,
}
fn visit_constant(&mut self,
- constant: & $($mutability)* Constant<'tcx>) {
- self.super_constant(constant);
+ constant: & $($mutability)* Constant<'tcx>,
+ location: Location) {
+ self.super_constant(constant, location);
}
fn visit_literal(&mut self,
- literal: & $($mutability)* Literal<'tcx>) {
- self.super_literal(literal);
+ literal: & $($mutability)* Literal<'tcx>,
+ location: Location) {
+ self.super_literal(literal, location);
}
fn visit_def_id(&mut self,
- def_id: & $($mutability)* DefId) {
+ def_id: & $($mutability)* DefId,
+ _: Location) {
self.super_def_id(def_id);
}
}
fn visit_const_val(&mut self,
- const_val: & $($mutability)* ConstVal) {
+ const_val: & $($mutability)* ConstVal,
+ _: Location) {
self.super_const_val(const_val);
}
fn visit_const_usize(&mut self,
- const_usize: & $($mutability)* ConstUsize) {
+ const_usize: & $($mutability)* ConstUsize,
+ _: Location) {
self.super_const_usize(const_usize);
}
fn visit_typed_const_val(&mut self,
- val: & $($mutability)* TypedConstVal<'tcx>) {
- self.super_typed_const_val(val);
+ val: & $($mutability)* TypedConstVal<'tcx>,
+ location: Location) {
+ self.super_typed_const_val(val, location);
}
fn visit_var_decl(&mut self,
is_cleanup: _
} = *data;
+ let mut index = 0;
for statement in statements {
- self.visit_statement(block, statement);
+ let location = Location { block: block, statement_index: index };
+ self.visit_statement(block, statement, location);
+ index += 1;
}
if let Some(ref $($mutability)* terminator) = *terminator {
- self.visit_terminator(block, terminator);
+ let location = Location { block: block, statement_index: index };
+ self.visit_terminator(block, terminator, location);
}
}
fn super_statement(&mut self,
block: BasicBlock,
- statement: & $($mutability)* Statement<'tcx>) {
+ statement: & $($mutability)* Statement<'tcx>,
+ location: Location) {
let Statement {
ref $($mutability)* source_info,
ref $($mutability)* kind,
match *kind {
StatementKind::Assign(ref $($mutability)* lvalue,
ref $($mutability)* rvalue) => {
- self.visit_assign(block, lvalue, rvalue);
+ self.visit_assign(block, lvalue, rvalue, location);
}
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
- self.visit_lvalue(lvalue, LvalueContext::Store);
+ self.visit_lvalue(lvalue, LvalueContext::Store, location);
}
StatementKind::StorageLive(ref $($mutability)* lvalue) => {
- self.visit_lvalue(lvalue, LvalueContext::StorageLive);
+ self.visit_lvalue(lvalue, LvalueContext::StorageLive, location);
}
StatementKind::StorageDead(ref $($mutability)* lvalue) => {
- self.visit_lvalue(lvalue, LvalueContext::StorageDead);
+ self.visit_lvalue(lvalue, LvalueContext::StorageDead, location);
}
}
}
fn super_assign(&mut self,
_block: BasicBlock,
lvalue: &$($mutability)* Lvalue<'tcx>,
- rvalue: &$($mutability)* Rvalue<'tcx>) {
- self.visit_lvalue(lvalue, LvalueContext::Store);
- self.visit_rvalue(rvalue);
+ rvalue: &$($mutability)* Rvalue<'tcx>,
+ location: Location) {
+ self.visit_lvalue(lvalue, LvalueContext::Store, location);
+ self.visit_rvalue(rvalue, location);
}
fn super_terminator(&mut self,
block: BasicBlock,
- terminator: &$($mutability)* Terminator<'tcx>) {
+ terminator: &$($mutability)* Terminator<'tcx>,
+ location: Location) {
let Terminator {
ref $($mutability)* source_info,
ref $($mutability)* kind,
} = *terminator;
self.visit_source_info(source_info);
- self.visit_terminator_kind(block, kind);
+ self.visit_terminator_kind(block, kind, location);
}
fn super_terminator_kind(&mut self,
block: BasicBlock,
- kind: & $($mutability)* TerminatorKind<'tcx>) {
+ kind: & $($mutability)* TerminatorKind<'tcx>,
+ source_location: Location) {
match *kind {
TerminatorKind::Goto { target } => {
self.visit_branch(block, target);
TerminatorKind::If { ref $($mutability)* cond,
ref $($mutability)* targets } => {
- self.visit_operand(cond);
+ self.visit_operand(cond, source_location);
for &target in targets.as_slice() {
self.visit_branch(block, target);
}
TerminatorKind::Switch { ref $($mutability)* discr,
adt_def: _,
ref targets } => {
- self.visit_lvalue(discr, LvalueContext::Inspect);
+ self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
for &target in targets {
self.visit_branch(block, target);
}
ref $($mutability)* switch_ty,
ref $($mutability)* values,
ref targets } => {
- self.visit_lvalue(discr, LvalueContext::Inspect);
+ self.visit_lvalue(discr, LvalueContext::Inspect, source_location);
self.visit_ty(switch_ty);
for value in values {
- self.visit_const_val(value);
+ self.visit_const_val(value, source_location);
}
for &target in targets {
self.visit_branch(block, target);
TerminatorKind::Drop { ref $($mutability)* location,
target,
unwind } => {
- self.visit_lvalue(location, LvalueContext::Drop);
+ self.visit_lvalue(location, LvalueContext::Drop, source_location);
self.visit_branch(block, target);
unwind.map(|t| self.visit_branch(block, t));
}
ref $($mutability)* value,
target,
unwind } => {
- self.visit_lvalue(location, LvalueContext::Drop);
- self.visit_operand(value);
+ self.visit_lvalue(location, LvalueContext::Drop, source_location);
+ self.visit_operand(value, source_location);
self.visit_branch(block, target);
unwind.map(|t| self.visit_branch(block, t));
}
ref $($mutability)* args,
ref $($mutability)* destination,
cleanup } => {
- self.visit_operand(func);
+ self.visit_operand(func, source_location);
for arg in args {
- self.visit_operand(arg);
+ self.visit_operand(arg, source_location);
}
if let Some((ref $($mutability)* destination, target)) = *destination {
- self.visit_lvalue(destination, LvalueContext::Call);
+ self.visit_lvalue(destination, LvalueContext::Call, source_location);
self.visit_branch(block, target);
}
cleanup.map(|t| self.visit_branch(block, t));
ref $($mutability)* msg,
target,
cleanup } => {
- self.visit_operand(cond);
- self.visit_assert_message(msg);
+ self.visit_operand(cond, source_location);
+ self.visit_assert_message(msg, source_location);
self.visit_branch(block, target);
cleanup.map(|t| self.visit_branch(block, t));
}
}
fn super_assert_message(&mut self,
- msg: & $($mutability)* AssertMessage<'tcx>) {
+ msg: & $($mutability)* AssertMessage<'tcx>,
+ location: Location) {
match *msg {
AssertMessage::BoundsCheck {
ref $($mutability)* len,
ref $($mutability)* index
} => {
- self.visit_operand(len);
- self.visit_operand(index);
+ self.visit_operand(len, location);
+ self.visit_operand(index, location);
}
AssertMessage::Math(_) => {}
}
}
fn super_rvalue(&mut self,
- rvalue: & $($mutability)* Rvalue<'tcx>) {
+ rvalue: & $($mutability)* Rvalue<'tcx>,
+ location: Location) {
match *rvalue {
Rvalue::Use(ref $($mutability)* operand) => {
- self.visit_operand(operand);
+ self.visit_operand(operand, location);
}
Rvalue::Repeat(ref $($mutability)* value,
ref $($mutability)* typed_const_val) => {
- self.visit_operand(value);
- self.visit_typed_const_val(typed_const_val);
+ self.visit_operand(value, location);
+ self.visit_typed_const_val(typed_const_val, location);
}
Rvalue::Ref(r, bk, ref $($mutability)* path) => {
self.visit_lvalue(path, LvalueContext::Borrow {
region: r,
kind: bk
- });
+ }, location);
}
Rvalue::Len(ref $($mutability)* path) => {
- self.visit_lvalue(path, LvalueContext::Inspect);
+ self.visit_lvalue(path, LvalueContext::Inspect, location);
}
Rvalue::Cast(_cast_kind,
ref $($mutability)* operand,
ref $($mutability)* ty) => {
- self.visit_operand(operand);
+ self.visit_operand(operand, location);
self.visit_ty(ty);
}
Rvalue::CheckedBinaryOp(_bin_op,
ref $($mutability)* lhs,
ref $($mutability)* rhs) => {
- self.visit_operand(lhs);
- self.visit_operand(rhs);
+ self.visit_operand(lhs, location);
+ self.visit_operand(rhs, location);
}
Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
- self.visit_operand(op);
+ self.visit_operand(op, location);
}
Rvalue::Box(ref $($mutability)* ty) => {
}
AggregateKind::Closure(ref $($mutability)* def_id,
ref $($mutability)* closure_substs) => {
- self.visit_def_id(def_id);
+ self.visit_def_id(def_id, location);
self.visit_closure_substs(closure_substs);
}
}
for operand in operands {
- self.visit_operand(operand);
+ self.visit_operand(operand, location);
}
}
ref $($mutability)* inputs,
asm: _ } => {
for output in & $($mutability)* outputs[..] {
- self.visit_lvalue(output, LvalueContext::Store);
+ self.visit_lvalue(output, LvalueContext::Store, location);
}
for input in & $($mutability)* inputs[..] {
- self.visit_operand(input);
+ self.visit_operand(input, location);
}
}
}
}
fn super_operand(&mut self,
- operand: & $($mutability)* Operand<'tcx>) {
+ operand: & $($mutability)* Operand<'tcx>,
+ location: Location) {
match *operand {
Operand::Consume(ref $($mutability)* lvalue) => {
- self.visit_lvalue(lvalue, LvalueContext::Consume);
+ self.visit_lvalue(lvalue, LvalueContext::Consume, location);
}
Operand::Constant(ref $($mutability)* constant) => {
- self.visit_constant(constant);
+ self.visit_constant(constant, location);
}
}
}
fn super_lvalue(&mut self,
lvalue: & $($mutability)* Lvalue<'tcx>,
- context: LvalueContext) {
+ context: LvalueContext,
+ location: Location) {
match *lvalue {
Lvalue::Var(_) |
Lvalue::Temp(_) |
Lvalue::ReturnPointer => {
}
Lvalue::Static(ref $($mutability)* def_id) => {
- self.visit_def_id(def_id);
+ self.visit_def_id(def_id, location);
}
Lvalue::Projection(ref $($mutability)* proj) => {
- self.visit_projection(proj, context);
+ self.visit_projection(proj, context, location);
}
}
}
fn super_projection(&mut self,
proj: & $($mutability)* LvalueProjection<'tcx>,
- context: LvalueContext) {
+ context: LvalueContext,
+ location: Location) {
let Projection {
ref $($mutability)* base,
ref $($mutability)* elem,
} = *proj;
- self.visit_lvalue(base, LvalueContext::Projection);
- self.visit_projection_elem(elem, context);
+ self.visit_lvalue(base, LvalueContext::Projection, location);
+ self.visit_projection_elem(elem, context, location);
}
fn super_projection_elem(&mut self,
proj: & $($mutability)* LvalueElem<'tcx>,
- _context: LvalueContext) {
+ _context: LvalueContext,
+ location: Location) {
match *proj {
ProjectionElem::Deref => {
}
self.visit_ty(ty);
}
ProjectionElem::Index(ref $($mutability)* operand) => {
- self.visit_operand(operand);
+ self.visit_operand(operand, location);
}
ProjectionElem::ConstantIndex { offset: _,
min_length: _,
}
fn super_constant(&mut self,
- constant: & $($mutability)* Constant<'tcx>) {
+ constant: & $($mutability)* Constant<'tcx>,
+ location: Location) {
let Constant {
ref $($mutability)* span,
ref $($mutability)* ty,
self.visit_span(span);
self.visit_ty(ty);
- self.visit_literal(literal);
+ self.visit_literal(literal, location);
}
fn super_typed_const_val(&mut self,
- constant: & $($mutability)* TypedConstVal<'tcx>) {
+ constant: & $($mutability)* TypedConstVal<'tcx>,
+ location: Location) {
let TypedConstVal {
ref $($mutability)* span,
ref $($mutability)* ty,
self.visit_span(span);
self.visit_ty(ty);
- self.visit_const_usize(value);
+ self.visit_const_usize(value, location);
}
fn super_literal(&mut self,
- literal: & $($mutability)* Literal<'tcx>) {
+ literal: & $($mutability)* Literal<'tcx>,
+ location: Location) {
match *literal {
Literal::Item { ref $($mutability)* def_id,
ref $($mutability)* substs } => {
- self.visit_def_id(def_id);
+ self.visit_def_id(def_id, location);
self.visit_substs(substs);
}
Literal::Value { ref $($mutability)* value } => {
- self.visit_const_val(value);
+ self.visit_const_val(value, location);
}
Literal::Promoted { index: _ } => {}
}
make_mir_visitor!(MutVisitor,mut);
#[derive(Copy, Clone, Debug)]
-pub enum LvalueContext {
+pub enum LvalueContext<'tcx> {
// Appears as LHS of an assignment
Store,
Inspect,
// Being borrowed
- Borrow { region: Region, kind: BorrowKind },
+ Borrow { region: &'tcx Region, kind: BorrowKind },
// Being sliced -- this should be same as being borrowed, probably
Slice { from_start: usize, from_end: usize },
"force overflow checks on or off"),
trace_macros: bool = (false, parse_bool, [UNTRACKED],
"for every macro invocation, print its name and arguments"),
+ debug_macros: bool = (false, parse_bool, [TRACKED],
+ "emit line numbers debug info inside macros"),
enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED],
"force nonzeroing move optimization on"),
keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED],
if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) {
self_match_impls.push(def_id);
- if trait_ref.substs.types[1..].iter()
- .zip(&impl_trait_ref.substs.types[1..])
+ if trait_ref.substs.types().skip(1)
+ .zip(impl_trait_ref.substs.types().skip(1))
.all(|(u,v)| self.fuzzy_match_tys(u, v))
{
fuzzy_match_impls.push(def_id);
return;
}
- let mut err = struct_span_err!(
- self.tcx.sess, span, E0277,
+ let mut err = struct_span_err!(self.tcx.sess, span, E0277,
"the trait bound `{}` is not satisfied",
trait_ref.to_predicate());
+ err.span_label(span, &format!("trait `{}` not satisfied",
+ trait_ref.to_predicate()));
// Try to report a help message
ty::Predicate::Trait(ref data) => {
let trait_ref = data.to_poly_trait_ref();
let self_ty = trait_ref.self_ty();
- let all_types = &trait_ref.substs().types;
- if all_types.references_error() {
+ if predicate.references_error() {
} else {
// Typically, this ambiguity should only happen if
// there are unresolved type inference variables
#[derive(Clone)]
pub struct RegionObligation<'tcx> {
- pub sub_region: ty::Region,
+ pub sub_region: &'tcx ty::Region,
pub sup_type: Ty<'tcx>,
pub cause: ObligationCause<'tcx>,
}
// Auto trait obligations on `impl Trait`.
if tcx.trait_has_default_impl(predicate.def_id()) {
let substs = predicate.skip_binder().trait_ref.substs;
- if substs.types.len() == 1 && substs.regions.is_empty() {
+ if substs.types().count() == 1 && substs.regions().next().is_none() {
if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
return true;
}
let concrete_ty = ty_scheme.ty.subst(tcx, substs);
let predicate = ty::TraitRef {
def_id: self.predicate.def_id(),
- substs: Substs::new_trait(tcx, vec![], vec![], concrete_ty)
+ substs: Substs::new_trait(tcx, concrete_ty, &[])
}.to_predicate();
let original_obligation = Obligation::new(self.cause.clone(),
pub fn register_region_obligation(&mut self,
t_a: Ty<'tcx>,
- r_b: ty::Region,
+ r_b: &'tcx ty::Region,
cause: ObligationCause<'tcx>)
{
register_region_obligation(t_a, r_b, cause, &mut self.region_obligations);
{
t.skip_binder() // ok b/c this check doesn't care about regions
.input_types()
- .iter()
- .map(|t| selcx.infcx().resolve_type_vars_if_possible(t))
+ .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t))
.filter(|t| t.has_infer_types())
.flat_map(|t| t.walk())
.filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false })
// Otherwise, we have something of the form
// `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
Some(t_a) => {
- register_region_obligation(t_a, ty::ReStatic,
+ let r_static = selcx.tcx().mk_region(ty::ReStatic);
+ register_region_obligation(t_a, r_static,
obligation.cause.clone(),
region_obligations);
Ok(Some(vec![]))
}
fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
- r_b: ty::Region,
+ r_b: &'tcx ty::Region,
cause: ObligationCause<'tcx>,
region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
{
match predicate {
ty::Predicate::Trait(ref data) => {
// In the case of a trait predicate, we can skip the "self" type.
- data.0.trait_ref.input_types()[1..].iter().any(|t| t.has_self_ty())
+ data.skip_binder().input_types().skip(1).any(|t| t.has_self_ty())
}
ty::Predicate::Projection(..) |
ty::Predicate::WellFormed(..) |
use hir::def_id::DefId;
use infer;
use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin};
-use ty::subst::{Subst, Substs};
+use ty::subst::{Kind, Subst, Substs};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use traits;
use ty::fast_reject;
// This suffices to allow chains like `FnMut` implemented in
// terms of `Fn` etc, but we could probably make this more
// precise still.
- let input_types = stack.fresh_trait_ref.0.input_types();
- let unbound_input_types = input_types.iter().any(|ty| ty.is_fresh());
+ let unbound_input_types = stack.fresh_trait_ref.input_types().any(|ty| ty.is_fresh());
if unbound_input_types && self.intercrate {
debug!("evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous",
stack.fresh_trait_ref);
match *candidate {
Ok(Some(_)) | Err(_) => true,
- Ok(None) => {
- cache_fresh_trait_pred.0.trait_ref.substs.types.has_infer_types()
- }
+ Ok(None) => cache_fresh_trait_pred.has_infer_types()
}
}
obligation: &TraitObligation<'tcx>,
trait_bound: ty::PolyTraitRef<'tcx>,
skol_trait_ref: ty::TraitRef<'tcx>,
- skol_map: &infer::SkolemizationMap,
+ skol_map: &infer::SkolemizationMap<'tcx>,
snapshot: &infer::CombinedSnapshot)
-> bool
{
return;
}
};
- let target = obligation.predicate.skip_binder().input_types()[1];
+ let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})",
source, target);
// for `PhantomData<T>`, we pass `T`
ty::TyStruct(def, substs) if def.is_phantom_data() => {
- substs.types.to_vec()
+ substs.types().collect()
}
ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
trait_def_id,
recursion_depth,
normalized_ty,
- vec![]);
+ &[]);
obligations.push(skol_obligation);
this.infcx().plug_leaks(skol_map, snapshot, &obligations)
})
match self_ty.sty {
ty::TyTrait(ref data) => {
// OK to skip the binder, it is reintroduced below
- let input_types = data.principal.skip_binder().input_types();
+ let input_types = data.principal.input_types();
let assoc_types = data.projection_bounds.iter()
.map(|pb| pb.skip_binder().ty);
- let all_types: Vec<_> = input_types.iter().cloned()
- .chain(assoc_types)
- .collect();
+ let all_types: Vec<_> = input_types.chain(assoc_types)
+ .collect();
// reintroduce the two binding levels we skipped, then flatten into one
let all_types = ty::Binder(ty::Binder(all_types));
mut substs: Normalized<'tcx, &'tcx Substs<'tcx>>,
cause: ObligationCause<'tcx>,
recursion_depth: usize,
- skol_map: infer::SkolemizationMap,
+ skol_map: infer::SkolemizationMap<'tcx>,
snapshot: &infer::CombinedSnapshot)
-> VtableImplData<'tcx, PredicateObligation<'tcx>>
{
// regions here. See the comment there for more details.
let source = self.infcx.shallow_resolve(
tcx.no_late_bound_regions(&obligation.self_ty()).unwrap());
- let target = obligation.predicate.skip_binder().input_types()[1];
+ let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1);
let target = self.infcx.shallow_resolve(target);
debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})",
} else {
return Err(Unimplemented);
};
- let mut ty_params = BitVector::new(substs_a.types.len());
+ let mut ty_params = BitVector::new(substs_a.types().count());
let mut found = false;
for ty in field.walk() {
if let ty::TyParam(p) = ty.sty {
// TyError and ensure they do not affect any other fields.
// This could be checked after type collection for any struct
// with a potentially unsized trailing field.
- let types = substs_a.types.iter().enumerate().map(|(i, ty)| {
+ let params = substs_a.params().iter().enumerate().map(|(i, &k)| {
if ty_params.contains(i) {
- tcx.types.err
+ Kind::from(tcx.types.err)
} else {
- ty
+ k
}
- }).collect();
- let substs = Substs::new(tcx, types, substs_a.regions.clone());
+ });
+ let substs = Substs::new(tcx, params);
for &ty in fields.split_last().unwrap().1 {
if ty.subst(tcx, substs).references_error() {
return Err(Unimplemented);
// Check that the source structure with the target's
// type parameters is a subtype of the target.
- let types = substs_a.types.iter().enumerate().map(|(i, ty)| {
+ let params = substs_a.params().iter().enumerate().map(|(i, &k)| {
if ty_params.contains(i) {
- substs_b.types[i]
+ Kind::from(substs_b.type_at(i))
} else {
- ty
+ k
}
- }).collect();
- let substs = Substs::new(tcx, types, substs_a.regions.clone());
- let new_struct = tcx.mk_struct(def, substs);
+ });
+ let new_struct = tcx.mk_struct(def, Substs::new(tcx, params));
let origin = TypeOrigin::Misc(obligation.cause.span);
let InferOk { obligations, .. } =
self.infcx.sub_types(false, origin, new_struct, target)
obligation.predicate.def_id(),
obligation.recursion_depth + 1,
inner_source,
- vec![inner_target]));
+ &[inner_target]));
}
_ => bug!()
impl_def_id: DefId,
obligation: &TraitObligation<'tcx>,
snapshot: &infer::CombinedSnapshot)
- -> (Normalized<'tcx, &'tcx Substs<'tcx>>, infer::SkolemizationMap)
+ -> (Normalized<'tcx, &'tcx Substs<'tcx>>,
+ infer::SkolemizationMap<'tcx>)
{
match self.match_impl(impl_def_id, obligation, snapshot) {
Ok((substs, skol_map)) => (substs, skol_map),
obligation: &TraitObligation<'tcx>,
snapshot: &infer::CombinedSnapshot)
-> Result<(Normalized<'tcx, &'tcx Substs<'tcx>>,
- infer::SkolemizationMap), ()>
+ infer::SkolemizationMap<'tcx>), ()>
{
let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap();
// substitution if we find that any of the input types, when
// simplified, do not match.
- obligation.predicate.0.input_types().iter()
+ obligation.predicate.skip_binder().input_types()
.zip(impl_trait_ref.input_types())
- .any(|(&obligation_ty, &impl_ty)| {
+ .any(|(obligation_ty, impl_ty)| {
let simplified_obligation_ty =
fast_reject::simplify_type(self.tcx(), obligation_ty, true);
let simplified_impl_ty =
recursion_depth: usize,
def_id: DefId, // of impl or trait
substs: &Substs<'tcx>, // for impl or trait
- skol_map: infer::SkolemizationMap,
+ skol_map: infer::SkolemizationMap<'tcx>,
snapshot: &infer::CombinedSnapshot)
-> Vec<PredicateObligation<'tcx>>
{
Ok(def_id) => {
Ok(ty::TraitRef {
def_id: def_id,
- substs: Substs::new_trait(self, vec![], vec![], param_ty)
+ substs: Substs::new_trait(self, param_ty, &[])
})
}
Err(e) => {
trait_def_id: DefId,
recursion_depth: usize,
param_ty: Ty<'tcx>,
- ty_params: Vec<Ty<'tcx>>)
+ ty_params: &[Ty<'tcx>])
-> PredicateObligation<'tcx>
{
let trait_ref = ty::TraitRef {
def_id: trait_def_id,
- substs: Substs::new_trait(self, ty_params, vec![], param_ty)
+ substs: Substs::new_trait(self, param_ty, ty_params)
};
predicate_for_trait_ref(cause, trait_ref, recursion_depth)
}
};
let trait_ref = ty::TraitRef {
def_id: fn_trait_def_id,
- substs: Substs::new_trait(self, vec![arguments_tuple], vec![], self_ty),
+ substs: Substs::new_trait(self, self_ty, &[arguments_tuple]),
};
ty::Binder((trait_ref, sig.0.output))
}
self.relate(a, b)
}
- fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> {
+ fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region> {
debug!("{}.regions({:?}, {:?})",
self.tag(),
a,
pub method_map: ty::MethodMap<'tcx>,
/// Borrows
- pub upvar_capture_map: ty::UpvarCaptureMap,
+ pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
/// Records the type of each closure. The def ID is the ID of the
/// expression defining the closure.
impl_interners!('tcx,
type_list: mk_type_list(Vec<Ty<'tcx>>, keep_local) -> [Ty<'tcx>],
substs: mk_substs(Substs<'tcx>, |substs: &Substs| {
- keep_local(&substs.types) || keep_local(&substs.regions)
+ substs.params().iter().any(keep_local)
}) -> Substs<'tcx>,
bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| {
keep_local(&fty.sig)
}) -> BareFnTy<'tcx>,
- region: mk_region(Region, keep_local) -> Region
+ region: mk_region(Region, |r| {
+ match r {
+ &ty::ReVar(_) | &ty::ReSkolemized(..) => true,
+ _ => false
+ }
+ }) -> Region
);
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
FixedArraySize(ExpectedFound<usize>),
TyParamSize(ExpectedFound<usize>),
ArgCount,
- RegionsDoesNotOutlive(Region, Region),
- RegionsNotSame(Region, Region),
- RegionsNoOverlap(Region, Region),
- RegionsInsufficientlyPolymorphic(BoundRegion, Region),
- RegionsOverlyPolymorphic(BoundRegion, Region),
+ RegionsDoesNotOutlive(&'tcx Region, &'tcx Region),
+ RegionsNotSame(&'tcx Region, &'tcx Region),
+ RegionsNoOverlap(&'tcx Region, &'tcx Region),
+ RegionsInsufficientlyPolymorphic(BoundRegion, &'tcx Region),
+ RegionsOverlyPolymorphic(BoundRegion, &'tcx Region),
Sorts(ExpectedFound<Ty<'tcx>>),
IntegerAsChar,
IntMismatch(ExpectedFound<ty::IntVarValue>),
self.note_and_explain_region(db, "concrete lifetime that was found is ",
conc_region, "");
}
- RegionsOverlyPolymorphic(_, ty::ReVar(_)) => {
+ RegionsOverlyPolymorphic(_, &ty::ReVar(_)) => {
// don't bother to print out the message below for
// inference variables, it's not very illuminating.
}
}
&ty::TyRef(r, ref m) => {
- self.add_region(*r);
+ self.add_region(r);
self.add_ty(m.ty);
}
self.add_bound_computation(&computation);
}
- fn add_region(&mut self, r: ty::Region) {
- match r {
+ fn add_region(&mut self, r: &ty::Region) {
+ match *r {
ty::ReVar(..) => {
self.add_flags(TypeFlags::HAS_RE_INFER);
self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX);
}
fn add_substs(&mut self, substs: &Substs) {
- self.add_tys(&substs.types);
- for &r in &substs.regions {
+ for ty in substs.types() {
+ self.add_ty(ty);
+ }
+
+ for r in substs.regions() {
self.add_region(r);
}
}
fty.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
r.super_fold_with(self)
}
t.super_visit_with(self)
}
- fn visit_region(&mut self, r: ty::Region) -> bool {
+ fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
r.super_visit_with(self)
}
}
/// whether any late-bound regions were skipped
pub fn collect_regions<T>(self,
value: &T,
- region_set: &mut FnvHashSet<ty::Region>)
+ region_set: &mut FnvHashSet<&'tcx ty::Region>)
-> bool
where T : TypeFoldable<'tcx>
{
let mut have_bound_regions = false;
- self.fold_regions(value, &mut have_bound_regions,
- |r, d| { region_set.insert(r.from_depth(d)); r });
+ self.fold_regions(value, &mut have_bound_regions, |r, d| {
+ region_set.insert(self.mk_region(r.from_depth(d)));
+ r
+ });
have_bound_regions
}
skipped_regions: &mut bool,
mut f: F)
-> T
- where F : FnMut(ty::Region, u32) -> ty::Region,
+ where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region,
T : TypeFoldable<'tcx>,
{
value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f))
tcx: TyCtxt<'a, 'gcx, 'tcx>,
skipped_regions: &'a mut bool,
current_depth: u32,
- fld_r: &'a mut (FnMut(ty::Region, u32) -> ty::Region + 'a),
+ fld_r: &'a mut (FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region + 'a),
}
impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> {
pub fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
skipped_regions: &'a mut bool,
fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx>
- where F : FnMut(ty::Region, u32) -> ty::Region
+ where F : FnMut(&'tcx ty::Region, u32) -> &'tcx ty::Region
{
RegionFolder {
tcx: tcx,
t
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
- match r {
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
+ match *r {
ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => {
debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})",
r, self.current_depth);
struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
current_depth: u32,
- fld_r: &'a mut (FnMut(ty::BoundRegion) -> ty::Region + 'a),
- map: FnvHashMap<ty::BoundRegion, ty::Region>
+ fld_r: &'a mut (FnMut(ty::BoundRegion) -> &'tcx ty::Region + 'a),
+ map: FnvHashMap<ty::BoundRegion, &'tcx ty::Region>
}
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
pub fn replace_late_bound_regions<T,F>(self,
value: &Binder<T>,
mut f: F)
- -> (T, FnvHashMap<ty::BoundRegion, ty::Region>)
- where F : FnMut(ty::BoundRegion) -> ty::Region,
+ -> (T, FnvHashMap<ty::BoundRegion, &'tcx ty::Region>)
+ where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region,
T : TypeFoldable<'tcx>,
{
let mut replacer = RegionReplacer::new(self, &mut f);
where T : TypeFoldable<'tcx>
{
self.replace_late_bound_regions(value, |br| {
- ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})
+ self.mk_region(ty::ReFree(ty::FreeRegion {
+ scope: all_outlive_scope,
+ bound_region: br
+ }))
}).0
}
let bound0_value = bound2_value.skip_binder().skip_binder();
let value = self.fold_regions(bound0_value, &mut false,
|region, current_depth| {
- match region {
+ match *region {
ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => {
// should be true if no escaping regions from bound2_value
assert!(debruijn.depth - current_depth <= 1);
- ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)
+ self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br))
}
_ => {
region
pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
where T : TypeFoldable<'tcx>
{
- self.replace_late_bound_regions(value, |_| ty::ReErased).0
+ self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0
}
/// Rewrite any late-bound regions so that they are anonymous. Region numbers are
let mut counter = 0;
Binder(self.replace_late_bound_regions(sig, |_| {
counter += 1;
- ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))
+ self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter)))
}).0)
}
}
impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> {
fn new<F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, fld_r: &'a mut F)
-> RegionReplacer<'a, 'gcx, 'tcx>
- where F : FnMut(ty::BoundRegion) -> ty::Region
+ where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region
{
RegionReplacer {
tcx: tcx,
t.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
- match r {
+ fn fold_region(&mut self, r:&'tcx ty::Region) -> &'tcx ty::Region {
+ match *r {
ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
let fld_r = &mut self.fld_r;
let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
- if let ty::ReLateBound(debruijn1, br) = region {
+ if let ty::ReLateBound(debruijn1, br) = *region {
// If the callback returns a late-bound region,
// that region should always use depth 1. Then we
// adjust it to the correct depth.
assert_eq!(debruijn1.depth, 1);
- ty::ReLateBound(debruijn, br)
+ self.tcx.mk_region(ty::ReLateBound(debruijn, br))
} else {
region
}
}
- r => r
+ _ => r
}
}
}
u.super_fold_with(self)
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
// because late-bound regions affect subtyping, we can't
// erase the bound/free distinction, but we can replace
// all free regions with 'erased.
// type system never "sees" those, they get substituted
// away. In trans, they will always be erased to 'erased
// whenever a substitution occurs.
- match r {
+ match *r {
ty::ReLateBound(..) => r,
- _ => ty::ReErased
+ _ => self.tcx().mk_region(ty::ReErased)
}
}
}
value, amount);
value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
- shift_region(region, amount)
+ tcx.mk_region(shift_region(*region, amount))
}))
}
t.region_depth > self.depth
}
- fn visit_region(&mut self, r: ty::Region) -> bool {
+ fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
r.escapes_depth(self.depth)
}
}
t.flags.get().intersects(self.flags)
}
- fn visit_region(&mut self, r: ty::Region) -> bool {
+ fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
if self.flags.intersects(ty::TypeFlags::HAS_LOCAL_NAMES) {
// does this represent a region that cannot be named
// in a global way? used in fulfillment caching.
- match r {
+ match *r {
ty::ReStatic | ty::ReEmpty | ty::ReErased => {}
_ => return true,
}
}
- if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER) {
- match r {
+ if self.flags.intersects(ty::TypeFlags::HAS_RE_INFER |
+ ty::TypeFlags::KEEP_IN_LOCAL_TCX) {
+ match *r {
ty::ReVar(_) | ty::ReSkolemized(..) => { return true }
_ => {}
}
t.super_visit_with(self)
}
- fn visit_region(&mut self, r: ty::Region) -> bool {
- match r {
+ fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+ match *r {
ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
self.regions.insert(br);
}
match self_ty.sty {
ty::TyStruct(adt_def, substs) |
ty::TyEnum(adt_def, substs) => {
- if substs.types.is_empty() { // ignore regions
+ if substs.types().next().is_none() { // ignore regions
self.push_item_path(buffer, adt_def.did);
} else {
buffer.push(&format!("<{}>", self_ty));
dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef<'tcx> }
dep_map_ty! { AdtDefs: ItemSignature(DefId) -> ty::AdtDefMaster<'tcx> }
-dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<ty::ItemVariances> }
+dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc<Vec<DefId>> }
dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec<ty::ImplOrTraitItemId> }
dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc<Vec<ty::ImplOrTraitItem<'tcx>>> }
pub generics: &'tcx Generics<'tcx>,
pub predicates: GenericPredicates<'tcx>,
pub fty: &'tcx BareFnTy<'tcx>,
- pub explicit_self: ExplicitSelfCategory,
+ pub explicit_self: ExplicitSelfCategory<'tcx>,
pub vis: Visibility,
pub defaultness: hir::Defaultness,
pub def_id: DefId,
generics: &'tcx ty::Generics<'tcx>,
predicates: GenericPredicates<'tcx>,
fty: &'tcx BareFnTy<'tcx>,
- explicit_self: ExplicitSelfCategory,
+ explicit_self: ExplicitSelfCategory<'tcx>,
vis: Visibility,
defaultness: hir::Defaultness,
def_id: DefId,
pub container: ImplOrTraitItemContainer,
}
-#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)]
-pub struct ItemVariances {
- pub types: Vec<Variance>,
- pub regions: Vec<Variance>,
-}
-
-impl ItemVariances {
- pub fn empty() -> ItemVariances {
- ItemVariances {
- types: vec![],
- regions: vec![],
- }
- }
-}
-
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)]
pub enum Variance {
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
/// Information describing the capture of an upvar. This is computed
/// during `typeck`, specifically by `regionck`.
#[derive(PartialEq, Clone, Debug, Copy)]
-pub enum UpvarCapture {
+pub enum UpvarCapture<'tcx> {
/// Upvar is captured by value. This is always true when the
/// closure is labeled `move`, but can also be true in other cases
/// depending on inference.
ByValue,
/// Upvar is captured by reference.
- ByRef(UpvarBorrow),
+ ByRef(UpvarBorrow<'tcx>),
}
#[derive(PartialEq, Clone, Copy)]
-pub struct UpvarBorrow {
+pub struct UpvarBorrow<'tcx> {
/// The kind of borrow: by-ref upvars have access to shared
/// immutable borrows, which are not part of the normal language
/// syntax.
pub kind: BorrowKind,
/// Region of the resulting reference.
- pub region: ty::Region,
+ pub region: &'tcx ty::Region,
}
-pub type UpvarCaptureMap = FnvHashMap<UpvarId, UpvarCapture>;
+pub type UpvarCaptureMap<'tcx> = FnvHashMap<UpvarId, UpvarCapture<'tcx>>;
#[derive(Copy, Clone)]
pub struct ClosureUpvar<'tcx> {
/// this is `None`, then the default is inherited from the
/// surrounding context. See RFC #599 for details.
#[derive(Copy, Clone)]
-pub enum ObjectLifetimeDefault {
+pub enum ObjectLifetimeDefault<'tcx> {
/// Require an explicit annotation. Occurs when multiple
/// `T:'a` constraints are found.
Ambiguous,
BaseDefault,
/// Use the given region as the default.
- Specific(Region),
+ Specific(&'tcx Region),
}
#[derive(Clone)]
pub index: u32,
pub default_def_id: DefId, // for use in error reporing about defaults
pub default: Option<Ty<'tcx>>,
- pub object_lifetime_default: ObjectLifetimeDefault,
+ pub object_lifetime_default: ObjectLifetimeDefault<'tcx>,
}
#[derive(Clone)]
-pub struct RegionParameterDef {
+pub struct RegionParameterDef<'tcx> {
pub name: Name,
pub def_id: DefId,
pub index: u32,
- pub bounds: Vec<ty::Region>,
+ pub bounds: Vec<&'tcx ty::Region>,
}
-impl RegionParameterDef {
+impl<'tcx> RegionParameterDef<'tcx> {
pub fn to_early_bound_region(&self) -> ty::Region {
ty::ReEarlyBound(ty::EarlyBoundRegion {
index: self.index,
pub parent: Option<DefId>,
pub parent_regions: u32,
pub parent_types: u32,
- pub regions: Vec<RegionParameterDef>,
+ pub regions: Vec<RegionParameterDef<'tcx>>,
pub types: Vec<TypeParameterDef<'tcx>>,
pub has_self: bool,
}
+impl<'tcx> Generics<'tcx> {
+ pub fn parent_count(&self) -> usize {
+ self.parent_regions as usize + self.parent_types as usize
+ }
+
+ pub fn own_count(&self) -> usize {
+ self.regions.len() + self.types.len()
+ }
+
+ pub fn count(&self) -> usize {
+ self.parent_count() + self.own_count()
+ }
+}
+
/// Bounds on generics.
#[derive(Clone)]
pub struct GenericPredicates<'tcx> {
Equate(PolyEquatePredicate<'tcx>),
/// where 'a : 'b
- RegionOutlives(PolyRegionOutlivesPredicate),
+ RegionOutlives(PolyRegionOutlivesPredicate<'tcx>),
/// where T : 'a
TypeOutlives(PolyTypeOutlivesPredicate<'tcx>),
// leads to more recompilation.
let def_ids: Vec<_> =
self.input_types()
- .iter()
.flat_map(|t| t.walk())
.filter_map(|t| match t.sty {
ty::TyStruct(adt_def, _) |
DepNode::TraitSelect(self.def_id(), def_ids)
}
- pub fn input_types(&self) -> &[Ty<'tcx>] {
- &self.trait_ref.substs.types
+ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+ self.trait_ref.input_types()
}
pub fn self_ty(&self) -> Ty<'tcx> {
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct OutlivesPredicate<A,B>(pub A, pub B); // `A : B`
pub type PolyOutlivesPredicate<A,B> = ty::Binder<OutlivesPredicate<A,B>>;
-pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate<ty::Region, ty::Region>;
-pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, ty::Region>;
+pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region,
+ &'tcx ty::Region>;
+pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>;
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
}
}
-impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate {
+impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
fn to_predicate(&self) -> Predicate<'tcx> {
Predicate::RegionOutlives(self.clone())
}
pub fn walk_tys(&self) -> IntoIter<Ty<'tcx>> {
let vec: Vec<_> = match *self {
ty::Predicate::Trait(ref data) => {
- data.0.trait_ref.input_types().to_vec()
+ data.skip_binder().input_types().collect()
}
ty::Predicate::Rfc1592(ref data) => {
return data.walk_tys()
}
ty::Predicate::Projection(ref data) => {
let trait_inputs = data.0.projection_ty.trait_ref.input_types();
- trait_inputs.iter()
- .cloned()
- .chain(Some(data.0.ty))
- .collect()
+ trait_inputs.chain(Some(data.0.ty)).collect()
}
ty::Predicate::WellFormed(data) => {
vec![data]
}
pub fn self_ty(&self) -> Ty<'tcx> {
- self.substs.types[0]
+ self.substs.type_at(0)
}
- pub fn input_types(&self) -> &[Ty<'tcx>] {
+ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
// Select only the "input types" from a trait-reference. For
// now this is all the types that appear in the
// trait-reference, but it should eventually exclude
// associated types.
- &self.substs.types
+ self.substs.types()
}
}
/// indicates it must outlive at least the function body (the user
/// may specify stronger requirements). This field indicates the
/// region of the callee.
- pub implicit_region_bound: ty::Region,
+ pub implicit_region_bound: &'tcx ty::Region,
/// Obligations that the caller must satisfy. This is basically
/// the set of bounds on the in-scope type parameters, translated
};
let sized_predicate = Binder(TraitRef {
def_id: sized_trait,
- substs: Substs::new_trait(tcx, vec![], vec![], ty)
+ substs: Substs::new_trait(tcx, ty, &[])
}).to_predicate();
let predicates = tcx.lookup_predicates(self.did).predicates;
if predicates.into_iter().any(|p| p == sized_predicate) {
|| self.lookup_repr_hints(did).contains(&attr::ReprSimd)
}
- pub fn item_variances(self, item_id: DefId) -> Rc<ItemVariances> {
+ pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> {
lookup_locally_or_in_crate_store(
"item_variance_map", item_id, &self.item_variance_map,
|| Rc::new(self.sess.cstore.item_variances(item_id)))
ty::ParameterEnvironment {
free_substs: Substs::empty(self),
caller_bounds: Vec::new(),
- implicit_region_bound: ty::ReEmpty,
+ implicit_region_bound: self.mk_region(ty::ReEmpty),
free_id_outlive: free_id_outlive
}
}
let substs = Substs::for_item(self.global_tcx(), def_id, |def, _| {
// map bound 'a => free 'a
- ReFree(FreeRegion { scope: free_id_outlive,
- bound_region: def.to_bound_region() })
+ self.global_tcx().mk_region(ReFree(FreeRegion {
+ scope: free_id_outlive,
+ bound_region: def.to_bound_region()
+ }))
}, |def, _| {
// map T => T
self.global_tcx().mk_param_from_def(def)
let unnormalized_env = ty::ParameterEnvironment {
free_substs: free_substs,
- implicit_region_bound: ty::ReScope(free_id_outlive),
+ implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)),
caller_bounds: predicates,
free_id_outlive: free_id_outlive,
};
traits::normalize_param_env_or_error(tcx, unnormalized_env, cause)
}
+ pub fn node_scope_region(self, id: NodeId) -> &'tcx Region {
+ self.mk_region(ty::ReScope(self.region_maps.node_extent(id)))
+ }
+
pub fn is_method_call(self, expr_id: NodeId) -> bool {
self.tables.borrow().method_map.contains_key(&MethodCall::expr(expr_id))
}
autoderefs))
}
- pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture> {
+ pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option<ty::UpvarCapture<'tcx>> {
Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone())
}
/// The category of explicit self.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
-pub enum ExplicitSelfCategory {
+pub enum ExplicitSelfCategory<'tcx> {
Static,
ByValue,
- ByReference(Region, hir::Mutability),
+ ByReference(&'tcx Region, hir::Mutability),
ByBox,
}
#[derive(Debug)]
pub enum Component<'tcx> {
- Region(ty::Region),
+ Region(&'tcx ty::Region),
Param(ty::ParamTy),
UnresolvedInferenceVariable(ty::InferTy),
}
}
-fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
+fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<&'tcx ty::Region>) {
for r in regions {
if !r.is_bound() {
out.push(Component::Region(r));
//! type equality, etc.
use hir::def_id::DefId;
-use ty::subst::Substs;
+use ty::subst::{Kind, Substs};
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::error::{ExpectedFound, TypeError};
use std::rc::Rc;
fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>)
-> RelateResult<'tcx, Ty<'tcx>>;
- fn regions(&mut self, a: ty::Region, b: ty::Region)
- -> RelateResult<'tcx, ty::Region>;
+ fn regions(&mut self, a: &'tcx ty::Region, b: &'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region>;
fn binders<T>(&mut self, a: &ty::Binder<T>, b: &ty::Binder<T>)
-> RelateResult<'tcx, ty::Binder<T>>
}
pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R,
- variances: Option<&ty::ItemVariances>,
+ variances: Option<&Vec<ty::Variance>>,
a_subst: &'tcx Substs<'tcx>,
b_subst: &'tcx Substs<'tcx>)
-> RelateResult<'tcx, &'tcx Substs<'tcx>>
{
let tcx = relation.tcx();
- let types = a_subst.types.iter().enumerate().map(|(i, a_ty)| {
- let b_ty = &b_subst.types[i];
- let variance = variances.map_or(ty::Invariant, |v| v.types[i]);
- relation.relate_with_variance(variance, a_ty, b_ty)
- }).collect::<Result<_, _>>()?;
-
- let regions = a_subst.regions.iter().enumerate().map(|(i, a_r)| {
- let b_r = &b_subst.regions[i];
- let variance = variances.map_or(ty::Invariant, |v| v.regions[i]);
- relation.relate_with_variance(variance, a_r, b_r)
- }).collect::<Result<_, _>>()?;
+ let params = a_subst.params().iter().zip(b_subst.params()).enumerate().map(|(i, (a, b))| {
+ let variance = variances.map_or(ty::Invariant, |v| v[i]);
+ if let (Some(a_ty), Some(b_ty)) = (a.as_type(), b.as_type()) {
+ Ok(Kind::from(relation.relate_with_variance(variance, &a_ty, &b_ty)?))
+ } else if let (Some(a_r), Some(b_r)) = (a.as_region(), b.as_region()) {
+ Ok(Kind::from(relation.relate_with_variance(variance, &a_r, &b_r)?))
+ } else {
+ bug!()
+ }
+ });
- Ok(Substs::new(tcx, types, regions))
+ Substs::maybe_new(tcx, params)
}
impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
(&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) =>
{
- let r = relation.relate_with_variance(ty::Contravariant, a_r, b_r)?;
+ let r = relation.relate_with_variance(ty::Contravariant, &a_r, &b_r)?;
let mt = relation.relate(a_mt, b_mt)?;
- Ok(tcx.mk_ref(tcx.mk_region(r), mt))
+ Ok(tcx.mk_ref(r, mt))
}
(&ty::TyArray(a_t, sz_a), &ty::TyArray(b_t, sz_b)) =>
}
}
-impl<'tcx> Relate<'tcx> for ty::Region {
+impl<'tcx> Relate<'tcx> for &'tcx ty::Region {
fn relate<'a, 'gcx, R>(relation: &mut R,
- a: &ty::Region,
- b: &ty::Region)
- -> RelateResult<'tcx, ty::Region>
+ a: &&'tcx ty::Region,
+ b: &&'tcx ty::Region)
+ -> RelateResult<'tcx, &'tcx ty::Region>
where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
{
relation.regions(*a, *b)
// except according to those terms.
use infer::type_variable;
-use ty::subst::Substs;
use ty::{self, Lift, Ty, TyCtxt};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
}
}
-impl<'tcx> Lift<'tcx> for ty::Region {
- type Lifted = Self;
- fn lift_to_tcx(&self, _: TyCtxt) -> Option<ty::Region> {
- Some(*self)
- }
-}
-
impl<'a, 'tcx> Lift<'tcx> for ty::TraitRef<'a> {
type Lifted = ty::TraitRef<'tcx>;
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
FixedArraySize(x) => FixedArraySize(x),
TyParamSize(x) => TyParamSize(x),
ArgCount => ArgCount,
- RegionsDoesNotOutlive(a, b) => RegionsDoesNotOutlive(a, b),
- RegionsNotSame(a, b) => RegionsNotSame(a, b),
- RegionsNoOverlap(a, b) => RegionsNoOverlap(a, b),
+ RegionsDoesNotOutlive(a, b) => {
+ return tcx.lift(&(a, b)).map(|(a, b)| RegionsDoesNotOutlive(a, b))
+ }
+ RegionsNotSame(a, b) => {
+ return tcx.lift(&(a, b)).map(|(a, b)| RegionsNotSame(a, b))
+ }
+ RegionsNoOverlap(a, b) => {
+ return tcx.lift(&(a, b)).map(|(a, b)| RegionsNoOverlap(a, b))
+ }
RegionsInsufficientlyPolymorphic(a, b) => {
- RegionsInsufficientlyPolymorphic(a, b)
+ return tcx.lift(&b).map(|b| RegionsInsufficientlyPolymorphic(a, b))
+ }
+ RegionsOverlyPolymorphic(a, b) => {
+ return tcx.lift(&b).map(|b| RegionsOverlyPolymorphic(a, b))
}
- RegionsOverlyPolymorphic(a, b) => RegionsOverlyPolymorphic(a, b),
IntegerAsChar => IntegerAsChar,
IntMismatch(x) => IntMismatch(x),
FloatMismatch(x) => FloatMismatch(x),
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::Region {
+impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
*self
}
}
}
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
- *self
- }
-
- fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- let region = folder.fold_region(**self);
- folder.tcx().mk_region(region)
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
- false
- }
-
- fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- visitor.visit_region(**self)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- let types = self.types.fold_with(folder);
- let regions = self.regions.fold_with(folder);
- Substs::new(folder.tcx(), types, regions)
- }
-
- fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- folder.fold_substs(self)
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.types.visit_with(visitor) || self.regions.visit_with(visitor)
- }
-}
-
impl<'tcx> TypeFoldable<'tcx> for ty::ClosureSubsts<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::ClosureSubsts {
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault {
+impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ty::ObjectLifetimeDefault::Ambiguous =>
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef {
+impl<'tcx> TypeFoldable<'tcx> for ty::RegionParameterDef<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::RegionParameterDef {
name: self.name,
use collections::enum_set::{self, EnumSet, CLike};
use std::fmt;
-use std::ops;
use std::mem;
+use std::ops;
use syntax::abi;
use syntax::ast::{self, Name};
use syntax::parse::token::keywords;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct TraitObject<'tcx> {
pub principal: PolyExistentialTraitRef<'tcx>,
- pub region_bound: ty::Region,
+ pub region_bound: &'tcx ty::Region,
pub builtin_bounds: BuiltinBounds,
pub projection_bounds: Vec<PolyExistentialProjection<'tcx>>,
}
self.0.substs
}
- pub fn input_types(&self) -> &[Ty<'tcx>] {
+ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
// FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
self.0.input_types()
}
}
impl<'tcx> ExistentialTraitRef<'tcx> {
- pub fn input_types(&self) -> &[Ty<'tcx>] {
+ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
// Select only the "input types" from a trait-reference. For
// now this is all the types that appear in the
// trait-reference, but it should eventually exclude
// associated types.
- &self.substs.types
+ self.substs.types()
}
}
self.0.def_id
}
- pub fn input_types(&self) -> &[Ty<'tcx>] {
+ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
// FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<>
self.0.input_types()
}
ReErased,
}
+impl<'tcx> Decodable for &'tcx Region {
+ fn decode<D: Decoder>(d: &mut D) -> Result<&'tcx Region, D::Error> {
+ let r = Decodable::decode(d)?;
+ cstore::tls::with_decoding_context(d, |dcx, _| {
+ Ok(dcx.tcx().mk_region(r))
+ })
+ }
+}
+
#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
pub struct EarlyBoundRegion {
pub index: u32,
/// Returns the regions directly referenced from this type (but
/// not types reachable from this type via `walk_tys`). This
/// ignores late-bound regions binders.
- pub fn regions(&self) -> Vec<ty::Region> {
+ pub fn regions(&self) -> Vec<&'tcx ty::Region> {
match self.sty {
TyRef(region, _) => {
- vec![*region]
+ vec![region]
}
TyTrait(ref obj) => {
let mut v = vec![obj.region_bound];
- v.extend_from_slice(&obj.principal.skip_binder().substs.regions);
+ v.extend(obj.principal.skip_binder().substs.regions());
v
}
TyEnum(_, substs) |
TyStruct(_, substs) |
TyAnon(_, substs) => {
- substs.regions.to_vec()
+ substs.regions().collect()
}
TyClosure(_, ref substs) => {
- substs.func_substs.regions.to_vec()
+ substs.func_substs.regions().collect()
}
TyProjection(ref data) => {
- data.trait_ref.substs.regions.to_vec()
+ data.trait_ref.substs.regions().collect()
}
TyFnDef(..) |
TyFnPtr(_) |
use middle::cstore;
use hir::def_id::DefId;
use ty::{self, Ty, TyCtxt};
-use ty::fold::{TypeFoldable, TypeFolder};
+use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use serialize::{Encodable, Encoder, Decodable, Decoder};
use syntax_pos::{Span, DUMMY_SP};
-///////////////////////////////////////////////////////////////////////////
+use core::nonzero::NonZero;
+use std::fmt;
+use std::iter;
+use std::marker::PhantomData;
+use std::mem;
+
+/// An entity in the Rust typesystem, which can be one of
+/// several kinds (only types and lifetimes for now).
+/// To reduce memory usage, a `Kind` is a interned pointer,
+/// with the lowest 2 bits being reserved for a tag to
+/// indicate the type (`Ty` or `Region`) it points to.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Kind<'tcx> {
+ ptr: NonZero<usize>,
+ marker: PhantomData<(Ty<'tcx>, &'tcx ty::Region)>
+}
+
+const TAG_MASK: usize = 0b11;
+const TYPE_TAG: usize = 0b00;
+const REGION_TAG: usize = 0b01;
+
+impl<'tcx> From<Ty<'tcx>> for Kind<'tcx> {
+ fn from(ty: Ty<'tcx>) -> Kind<'tcx> {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
+
+ let ptr = ty as *const _ as usize;
+ Kind {
+ ptr: unsafe {
+ NonZero::new(ptr | TYPE_TAG)
+ },
+ marker: PhantomData
+ }
+ }
+}
+
+impl<'tcx> From<&'tcx ty::Region> for Kind<'tcx> {
+ fn from(r: &'tcx ty::Region) -> Kind<'tcx> {
+ // Ensure we can use the tag bits.
+ assert_eq!(mem::align_of_val(r) & TAG_MASK, 0);
+
+ let ptr = r as *const _ as usize;
+ Kind {
+ ptr: unsafe {
+ NonZero::new(ptr | REGION_TAG)
+ },
+ marker: PhantomData
+ }
+ }
+}
+
+impl<'tcx> Kind<'tcx> {
+ #[inline]
+ unsafe fn downcast<T>(self, tag: usize) -> Option<&'tcx T> {
+ let ptr = *self.ptr;
+ if ptr & TAG_MASK == tag {
+ Some(&*((ptr & !TAG_MASK) as *const _))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ pub fn as_type(self) -> Option<Ty<'tcx>> {
+ unsafe {
+ self.downcast(TYPE_TAG)
+ }
+ }
+
+ #[inline]
+ pub fn as_region(self) -> Option<&'tcx ty::Region> {
+ unsafe {
+ self.downcast(REGION_TAG)
+ }
+ }
+}
+
+impl<'tcx> fmt::Debug for Kind<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if let Some(ty) = self.as_type() {
+ write!(f, "{:?}", ty)
+ } else if let Some(r) = self.as_region() {
+ write!(f, "{:?}", r)
+ } else {
+ write!(f, "<unknwon @ {:p}>", *self.ptr as *const ())
+ }
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ if let Some(ty) = self.as_type() {
+ Kind::from(ty.fold_with(folder))
+ } else if let Some(r) = self.as_region() {
+ Kind::from(r.fold_with(folder))
+ } else {
+ bug!()
+ }
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ if let Some(ty) = self.as_type() {
+ ty.visit_with(visitor)
+ } else if let Some(r) = self.as_region() {
+ r.visit_with(visitor)
+ } else {
+ bug!()
+ }
+ }
+}
/// A substitution mapping type/region parameters to new values.
-#[derive(Clone, PartialEq, Eq, Hash)]
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct Substs<'tcx> {
- pub types: Vec<Ty<'tcx>>,
- pub regions: Vec<ty::Region>,
+ params: Vec<Kind<'tcx>>
}
impl<'a, 'gcx, 'tcx> Substs<'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- t: Vec<Ty<'tcx>>,
- r: Vec<ty::Region>)
- -> &'tcx Substs<'tcx>
- {
- tcx.mk_substs(Substs { types: t, regions: r })
+ pub fn new<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
+ -> &'tcx Substs<'tcx>
+ where I: IntoIterator<Item=Kind<'tcx>> {
+ tcx.mk_substs(Substs {
+ params: params.into_iter().collect()
+ })
+ }
+
+ pub fn maybe_new<I, E>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
+ -> Result<&'tcx Substs<'tcx>, E>
+ where I: IntoIterator<Item=Result<Kind<'tcx>, E>> {
+ Ok(tcx.mk_substs(Substs {
+ params: params.into_iter().collect::<Result<_, _>>()?
+ }))
}
pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- mut t: Vec<Ty<'tcx>>,
- r: Vec<ty::Region>,
- s: Ty<'tcx>)
+ s: Ty<'tcx>,
+ t: &[Ty<'tcx>])
-> &'tcx Substs<'tcx>
{
- t.insert(0, s);
- Substs::new(tcx, t, r)
+ let t = iter::once(s).chain(t.iter().cloned());
+ Substs::new(tcx, t.map(Kind::from))
}
pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
- Substs::new(tcx, vec![], vec![])
+ Substs::new(tcx, vec![])
}
/// Creates a Substs for generic parameter definitions,
mut mk_region: FR,
mut mk_type: FT)
-> &'tcx Substs<'tcx>
- where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
+ where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
let defs = tcx.lookup_generics(def_id);
- let num_regions = defs.parent_regions as usize + defs.regions.len();
- let num_types = defs.parent_types as usize + defs.types.len();
let mut substs = Substs {
- regions: Vec::with_capacity(num_regions),
- types: Vec::with_capacity(num_types)
+ params: Vec::with_capacity(defs.count())
};
substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type);
- Substs::new(tcx, substs.types, substs.regions)
+ tcx.mk_substs(substs)
}
fn fill_item<FR, FT>(&mut self,
defs: &ty::Generics<'tcx>,
mk_region: &mut FR,
mk_type: &mut FT)
- where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> ty::Region,
+ where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
if let Some(def_id) = defs.parent {
let parent_defs = tcx.lookup_generics(def_id);
self.fill_item(tcx, parent_defs, mk_region, mk_type);
}
+ // Handle Self first, before all regions.
+ let mut types = defs.types.iter();
+ if defs.parent.is_none() && defs.has_self {
+ let def = types.next().unwrap();
+ let ty = mk_type(def, self);
+ assert_eq!(def.index as usize, self.params.len());
+ self.params.push(Kind::from(ty));
+ }
+
for def in &defs.regions {
let region = mk_region(def, self);
- assert_eq!(def.index as usize, self.regions.len());
- self.regions.push(region);
+ assert_eq!(def.index as usize, self.params.len());
+ self.params.push(Kind::from(region));
}
- for def in &defs.types {
+ for def in types {
let ty = mk_type(def, self);
- assert_eq!(def.index as usize, self.types.len());
- self.types.push(ty);
+ assert_eq!(def.index as usize, self.params.len());
+ self.params.push(Kind::from(ty));
}
}
pub fn is_noop(&self) -> bool {
- self.regions.is_empty() && self.types.is_empty()
+ self.params.is_empty()
+ }
+
+ #[inline]
+ pub fn params(&self) -> &[Kind<'tcx>] {
+ &self.params
+ }
+
+ #[inline]
+ pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+ self.params.iter().filter_map(|k| k.as_type())
+ }
+
+ #[inline]
+ pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=&'tcx ty::Region> + 'a {
+ self.params.iter().filter_map(|k| k.as_region())
+ }
+
+ #[inline]
+ pub fn type_at(&self, i: usize) -> Ty<'tcx> {
+ self.params[i].as_type().unwrap_or_else(|| {
+ bug!("expected type for param #{} in {:?}", i, self.params);
+ })
}
+ #[inline]
+ pub fn region_at(&self, i: usize) -> &'tcx ty::Region {
+ self.params[i].as_region().unwrap_or_else(|| {
+ bug!("expected region for param #{} in {:?}", i, self.params);
+ })
+ }
+
+ #[inline]
pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> {
- self.types[ty_param_def.index as usize]
+ self.type_at(ty_param_def.index as usize)
}
- pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region {
- self.regions[def.index as usize]
+ #[inline]
+ pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> &'tcx ty::Region {
+ self.region_at(def.index as usize)
}
/// Transform from substitutions for a child of `source_ancestor`
target_substs: &Substs<'tcx>)
-> &'tcx Substs<'tcx> {
let defs = tcx.lookup_generics(source_ancestor);
- let regions = target_substs.regions.iter()
- .chain(&self.regions[defs.regions.len()..]).cloned().collect();
- let types = target_substs.types.iter()
- .chain(&self.types[defs.types.len()..]).cloned().collect();
- Substs::new(tcx, types, regions)
+ tcx.mk_substs(Substs {
+ params: target_substs.params.iter()
+ .chain(&self.params[defs.own_count()..]).cloned().collect()
+ })
+ }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
+ fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ let params = self.params.iter().map(|k| k.fold_with(folder)).collect();
+ folder.tcx().mk_substs(Substs {
+ params: params
+ })
+ }
+
+ fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
+ folder.fold_substs(self)
+ }
+
+ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
+ self.params.visit_with(visitor)
}
}
t
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
// Note: This routine only handles regions that are bound on
// type declarations and other outer declarations, not those
// bound in *fn types*. Region substitution of the bound
// regions that appear in a function signature is done using
// the specialized routine `ty::replace_late_regions()`.
- match r {
+ match *r {
ty::ReEarlyBound(data) => {
- match self.substs.regions.get(data.index as usize) {
- Some(&r) => {
+ let r = self.substs.params.get(data.index as usize)
+ .and_then(|k| k.as_region());
+ match r {
+ Some(r) => {
self.shift_region_through_binders(r)
}
None => {
impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
// Look up the type in the substitutions. It really should be in there.
- let opt_ty = self.substs.types.get(p.idx as usize);
+ let opt_ty = self.substs.params.get(p.idx as usize)
+ .and_then(|k| k.as_type());
let ty = match opt_ty {
- Some(t) => *t,
+ Some(t) => t,
None => {
let span = self.span.unwrap_or(DUMMY_SP);
span_bug!(
source_ty,
p.idx,
self.root_ty,
- self.substs);
+ self.substs.params);
}
};
result
}
- fn shift_region_through_binders(&self, region: ty::Region) -> ty::Region {
- ty::fold::shift_region(region, self.region_binders_passed)
+ fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region {
+ self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
}
}
substs: &Substs<'tcx>)
-> ty::TraitRef<'tcx> {
let defs = tcx.lookup_generics(trait_id);
- let regions = substs.regions[..defs.regions.len()].to_vec();
- let types = substs.types[..defs.types.len()].to_vec();
+ let params = substs.params[..defs.own_count()].iter().cloned();
ty::TraitRef {
def_id: trait_id,
- substs: Substs::new(tcx, types, regions)
+ substs: Substs::new(tcx, params)
}
}
}
pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>,
trait_ref: ty::TraitRef<'tcx>)
-> ty::ExistentialTraitRef<'tcx> {
- let Substs { mut types, regions } = trait_ref.substs.clone();
-
- types.remove(0);
+ // Assert there is a Self.
+ trait_ref.substs.type_at(0);
+ let params = trait_ref.substs.params[1..].iter().cloned();
ty::ExistentialTraitRef {
def_id: trait_ref.def_id,
- substs: Substs::new(tcx, types, regions)
+ substs: Substs::new(tcx, params)
}
}
}
assert!(!self_ty.has_escaping_regions());
self.map_bound(|trait_ref| {
- let Substs { mut types, regions } = trait_ref.substs.clone();
-
- types.insert(0, self_ty);
-
+ let params = trait_ref.substs.params.iter().cloned();
+ let params = iter::once(Kind::from(self_ty)).chain(params);
ty::TraitRef {
def_id: trait_ref.def_id,
- substs: Substs::new(tcx, types, regions)
+ substs: Substs::new(tcx, params)
}
})
}
pub fn required_region_bounds(self,
erased_self_ty: Ty<'tcx>,
predicates: Vec<ty::Predicate<'tcx>>)
- -> Vec<ty::Region> {
+ -> Vec<&'tcx ty::Region> {
debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})",
erased_self_ty,
predicates);
ty.super_visit_with(self)
}
- fn visit_region(&mut self, r: ty::Region) -> bool {
- match r {
+ fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+ match *r {
ty::ReStatic | ty::ReErased => {
self.hash::<u32>(0);
}
return false;
}
- let types_a = &substs_a.types;
- let types_b = &substs_b.types;
-
- types_a.iter().zip(types_b).all(|(&a, &b)| same_type(a, b))
+ substs_a.types().zip(substs_b.types()).all(|(a, b)| same_type(a, b))
}
_ => {
a == b
stack.into_iter()
}
+// We push types on the stack in reverse order so as to
+// maintain a pre-order traversal. As of the time of this
+// writing, the fact that the traversal is pre-order is not
+// known to be significant to any code, but it seems like the
+// natural order one would expect (basically, the order of the
+// types as they are written).
fn push_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, parent_ty: Ty<'tcx>) {
match parent_ty.sty {
ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) |
stack.push(mt.ty);
}
ty::TyProjection(ref data) => {
- push_reversed(stack, &data.trait_ref.substs.types);
+ stack.extend(data.trait_ref.substs.types().rev());
}
ty::TyTrait(ref obj) => {
- push_reversed(stack, obj.principal.input_types());
- push_reversed(stack, &obj.projection_bounds.iter().map(|pred| {
+ stack.extend(obj.principal.input_types().rev());
+ stack.extend(obj.projection_bounds.iter().map(|pred| {
pred.0.ty
- }).collect::<Vec<_>>());
+ }).rev());
}
ty::TyEnum(_, ref substs) |
ty::TyStruct(_, ref substs) |
ty::TyAnon(_, ref substs) => {
- push_reversed(stack, &substs.types);
+ stack.extend(substs.types().rev());
}
ty::TyClosure(_, ref substs) => {
- push_reversed(stack, &substs.func_substs.types);
- push_reversed(stack, &substs.upvar_tys);
+ stack.extend(substs.func_substs.types().rev());
+ stack.extend(substs.upvar_tys.iter().cloned().rev());
}
- ty::TyTuple(ref ts) => {
- push_reversed(stack, ts);
+ ty::TyTuple(ts) => {
+ stack.extend(ts.iter().cloned().rev());
}
ty::TyFnDef(_, substs, ref ft) => {
- push_reversed(stack, &substs.types);
+ stack.extend(substs.types().rev());
push_sig_subtypes(stack, &ft.sig);
}
ty::TyFnPtr(ref ft) => {
fn push_sig_subtypes<'tcx>(stack: &mut Vec<Ty<'tcx>>, sig: &ty::PolyFnSig<'tcx>) {
stack.push(sig.0.output);
- push_reversed(stack, &sig.0.inputs);
-}
-
-fn push_reversed<'tcx>(stack: &mut Vec<Ty<'tcx>>, tys: &[Ty<'tcx>]) {
- // We push slices on the stack in reverse order so as to
- // maintain a pre-order traversal. As of the time of this
- // writing, the fact that the traversal is pre-order is not
- // known to be significant to any code, but it seems like the
- // natural order one would expect (basically, the order of the
- // types as they are written).
- for &ty in tys.iter().rev() {
- stack.push(ty);
- }
+ stack.extend(sig.0.inputs.iter().cloned().rev());
}
/// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`.
#[derive(Debug)]
pub enum ImpliedBound<'tcx> {
- RegionSubRegion(ty::Region, ty::Region),
- RegionSubParam(ty::Region, ty::ParamTy),
- RegionSubProjection(ty::Region, ty::ProjectionTy<'tcx>),
+ RegionSubRegion(&'tcx ty::Region, &'tcx ty::Region),
+ RegionSubParam(&'tcx ty::Region, ty::ParamTy),
+ RegionSubProjection(&'tcx ty::Region, ty::ProjectionTy<'tcx>),
}
/// Compute the implied bounds that a callee/impl can assume based on
/// this down to determine what relationships would have to hold for
/// `T: 'a` to hold. We get to assume that the caller has validated
/// those relationships.
-fn implied_bounds_from_components<'tcx>(sub_region: ty::Region,
+fn implied_bounds_from_components<'tcx>(sub_region: &'tcx ty::Region,
sup_components: Vec<Component<'tcx>>)
-> Vec<ImpliedBound<'tcx>>
{
let cause = self.cause(traits::MiscObligation);
self.out.extend(
- trait_ref.substs.types
- .iter()
+ trait_ref.substs.types()
.filter(|ty| !ty.has_escaping_regions())
.map(|ty| traits::Obligation::new(cause.clone(),
ty::Predicate::WellFormed(ty))));
cause,
ty::Predicate::TypeOutlives(
ty::Binder(
- ty::OutlivesPredicate(mt.ty, *r)))));
+ ty::OutlivesPredicate(mt.ty, r)))));
}
}
tcx: TyCtxt<'a, 'gcx, 'tcx>,
principal: ty::PolyExistentialTraitRef<'tcx>,
others: ty::BuiltinBounds)
- -> Vec<ty::Region>
+ -> Vec<&'tcx ty::Region>
{
// Since we don't actually *know* the self type for an object,
// this "open(err)" serves as a kind of dummy standin -- basically
use std::cell::Cell;
use std::fmt;
+use std::usize;
+
use syntax::abi::Abi;
use syntax::parse::token;
use syntax::ast::CRATE_NODE_ID;
verbose = tcx.sess.verbose();
has_self = generics.has_self;
+ let mut child_types = 0;
if let Some(def_id) = generics.parent {
// Methods.
assert_eq!(ns, Ns::Value);
+ child_types = generics.types.len();
generics = tcx.lookup_generics(def_id);
num_regions = generics.regions.len();
num_types = generics.types.len();
if has_self {
- write!(f, "<{} as ", substs.types[0])?;
+ write!(f, "<{} as ", substs.type_at(0))?;
}
item_name = Some(tcx.item_name(did));
if !verbose {
if generics.types.last().map_or(false, |def| def.default.is_some()) {
if let Some(substs) = tcx.lift(&substs) {
- let tps = &substs.types[..num_types];
- for (def, actual) in generics.types.iter().zip(tps).rev() {
+ let tps = substs.types().rev().skip(child_types);
+ for (def, actual) in generics.types.iter().rev().zip(tps) {
if def.default.subst(tcx, substs) != Some(actual) {
break;
}
if !verbose && fn_trait_kind.is_some() && projections.len() == 1 {
let projection_ty = projections[0].ty;
- if let TyTuple(ref args) = substs.types[1].sty {
+ if let TyTuple(ref args) = substs.type_at(1).sty {
return fn_sig(f, args, false, projection_ty);
}
}
}
};
- let print_regions = |f: &mut fmt::Formatter, start: &str, regions: &[ty::Region]| {
+ let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| {
// Don't print any regions if they're all erased.
- if regions.iter().all(|r| *r == ty::ReErased) {
+ let regions = || substs.regions().skip(skip).take(count);
+ if regions().all(|r: &ty::Region| *r == ty::ReErased) {
return Ok(());
}
- for region in regions {
+ for region in regions() {
+ let region: &ty::Region = region;
start_or_continue(f, start, ", ")?;
if verbose {
write!(f, "{:?}", region)?;
Ok(())
};
- print_regions(f, "<", &substs.regions[..num_regions])?;
+ print_regions(f, "<", 0, num_regions)?;
- let tps = &substs.types[..num_types];
+ let tps = substs.types().take(num_types - num_supplied_defaults)
+ .skip(has_self as usize);
- for &ty in &tps[has_self as usize..tps.len() - num_supplied_defaults] {
+ for ty in tps {
start_or_continue(f, "<", ", ")?;
write!(f, "{}", ty)?;
}
write!(f, "::{}", item_name)?;
}
- print_regions(f, "::<", &substs.regions[num_regions..])?;
+ print_regions(f, "::<", num_regions, usize::MAX)?;
// FIXME: consider being smart with defaults here too
- for ty in &substs.types[num_types..] {
+ for ty in substs.types().skip(num_types) {
start_or_continue(f, "::<", ", ")?;
write!(f, "{}", ty)?;
}
let new_value = tcx.replace_late_bound_regions(&value, |br| {
let _ = start_or_continue(f, "for<", ", ");
- ty::ReLateBound(ty::DebruijnIndex::new(1), match br {
+ let br = match br {
ty::BrNamed(_, name, _) => {
let _ = write!(f, "{}", name);
br
name,
ty::Issue32330::WontChange)
}
- })
+ };
+ tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br))
}).0;
start_or_continue(f, "", "> ")?;
}
}
-impl fmt::Debug for ty::RegionParameterDef {
+impl<'tcx> fmt::Debug for ty::RegionParameterDef<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "RegionParameterDef({}, {:?}, {}, {:?})",
self.name,
}
}
-impl<'tcx> fmt::Debug for Substs<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Substs[types={:?}, regions={:?}]",
- self.types, self.regions)
- }
-}
-
impl<'tcx> fmt::Debug for ty::ItemSubsts<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ItemSubsts({:?})", self.substs)
}
}
-impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault {
+impl<'tcx> fmt::Debug for ty::ObjectLifetimeDefault<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ty::ObjectLifetimeDefault::Ambiguous => write!(f, "Ambiguous"),
}
}
-impl fmt::Debug for ty::ItemVariances {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ItemVariances(types={:?}, regions={:?})",
- self.types, self.regions)
- }
-}
-
impl<'tcx> fmt::Debug for ty::GenericPredicates<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "GenericPredicates({:?})", self.predicates)
}
}
-impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, ty::Region>> {
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<Ty<'tcx>, &'tcx ty::Region>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
-impl fmt::Display for ty::Binder<ty::OutlivesPredicate<ty::Region, ty::Region>> {
+impl<'tcx> fmt::Display for ty::Binder<ty::OutlivesPredicate<&'tcx ty::Region,
+ &'tcx ty::Region>> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self)))
}
}
}
-impl fmt::Debug for ty::UpvarBorrow {
+impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "UpvarBorrow({:?}, {:?})",
self.kind, self.region)
}
}
-impl fmt::Display for ty::ExplicitSelfCategory {
+impl<'tcx> fmt::Display for ty::ExplicitSelfCategory<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
ty::ExplicitSelfCategory::Static => "static",
borrow_id: ast::NodeId,
borrow_span: Span,
cmt: mc::cmt<'tcx>,
- loan_region: ty::Region,
+ loan_region: &'tcx ty::Region,
bk: ty::BorrowKind,
loan_cause: euv::LoanCause)
{
span: Span,
cause: euv::LoanCause,
cmt: mc::cmt<'tcx>,
- loan_region: ty::Region,
+ loan_region: &'tcx ty::Region,
_: ty::BorrowKind)
-> Result<(),()> {
//! Reports error if `loan_region` is larger than S
span: Span,
cause: euv::LoanCause,
- loan_region: ty::Region,
+ loan_region: &'tcx ty::Region,
cmt_original: mc::cmt<'tcx>
}
}
}
- fn check_scope(&self, max_scope: ty::Region) -> R {
+ fn check_scope(&self, max_scope: &'tcx ty::Region) -> R {
//! Reports an error if `loan_region` is larger than `max_scope`
if !self.bccx.is_subregion_of(self.loan_region, max_scope) {
}
}
- fn scope(&self, cmt: &mc::cmt) -> ty::Region {
+ fn scope(&self, cmt: &mc::cmt<'tcx>) -> &'tcx ty::Region {
//! Returns the maximal region scope for the which the
//! lvalue `cmt` is guaranteed to be valid without any
//! rooting etc, and presuming `cmt` is not mutated.
temp_scope
}
Categorization::Upvar(..) => {
- ty::ReScope(self.item_scope)
- }
- Categorization::StaticItem => {
- ty::ReStatic
+ self.bccx.tcx.mk_region(ty::ReScope(self.item_scope))
}
Categorization::Local(local_id) => {
- ty::ReScope(self.bccx.tcx.region_maps.var_scope(local_id))
+ self.bccx.tcx.mk_region(ty::ReScope(
+ self.bccx.tcx.region_maps.var_scope(local_id)))
}
+ Categorization::StaticItem |
Categorization::Deref(_, _, mc::UnsafePtr(..)) => {
- ty::ReStatic
+ self.bccx.tcx.mk_region(ty::ReStatic)
}
Categorization::Deref(_, _, mc::BorrowedPtr(_, r)) |
Categorization::Deref(_, _, mc::Implicit(_, r)) => {
}
}
- fn report_error(&self, code: bckerr_code) {
+ fn report_error(&self, code: bckerr_code<'tcx>) {
self.bccx.report(BckError { cmt: self.cmt_original.clone(),
span: self.span,
cause: BorrowViolation(self.cause),
borrow_id: ast::NodeId,
borrow_span: Span,
cmt: mc::cmt<'tcx>,
- loan_region: ty::Region,
+ loan_region: &'tcx ty::Region,
bk: ty::BorrowKind,
loan_cause: euv::LoanCause)
{
borrow_span: Span,
cmt: mc::cmt<'tcx>,
req_kind: ty::BorrowKind,
- loan_region: ty::Region,
+ loan_region: &'tcx ty::Region,
cause: euv::LoanCause) {
debug!("guarantee_valid(borrow_id={}, cmt={:?}, \
req_mutbl={:?}, loan_region={:?})",
// a loan for the empty region can never be dereferenced, so
// it is always safe
- if loan_region == ty::ReEmpty {
+ if *loan_region == ty::ReEmpty {
return;
}
}
RestrictionResult::SafeIf(loan_path, restricted_paths) => {
- let loan_scope = match loan_region {
+ let loan_scope = match *loan_region {
ty::ReScope(scope) => scope,
ty::ReFree(ref fr) => fr.scope,
span: Span,
cause: euv::LoanCause,
cmt: mc::cmt<'tcx>,
- loan_region: ty::Region)
+ loan_region: &'tcx ty::Region)
-> RestrictionResult<'tcx> {
let ctxt = RestrictionsContext {
bccx: bccx,
struct RestrictionsContext<'a, 'tcx: 'a> {
bccx: &'a BorrowckCtxt<'a, 'tcx>,
span: Span,
- loan_region: ty::Region,
+ loan_region: &'tcx ty::Region,
cause: euv::LoanCause,
}
fn extend(&self,
result: RestrictionResult<'tcx>,
cmt: &mc::cmt<'tcx>,
- elem: LoanPathElem) -> RestrictionResult<'tcx> {
+ elem: LoanPathElem<'tcx>) -> RestrictionResult<'tcx> {
match result {
RestrictionResult::Safe => RestrictionResult::Safe,
RestrictionResult::SafeIf(base_lp, mut base_vec) => {
// except according to those terms.
use rustc::ty::TyCtxt;
-use rustc::mir::repr::{self, Mir};
+use rustc::mir::repr::{self, Mir, Location};
use rustc_data_structures::indexed_vec::Idx;
-use super::super::gather_moves::{Location};
use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
use super::super::MoveDataParamEnv;
use super::super::DropFlagState;
{
drop_flag_effects_for_location(
self.tcx, self.mir, ctxt,
- Location { block: bb, index: idx },
+ Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
{
drop_flag_effects_for_location(
self.tcx, self.mir, ctxt,
- Location { block: bb, index: statements_len },
+ Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
{
drop_flag_effects_for_location(
self.tcx, self.mir, ctxt,
- Location { block: bb, index: idx },
+ Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
{
drop_flag_effects_for_location(
self.tcx, self.mir, ctxt,
- Location { block: bb, index: statements_len },
+ Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
{
drop_flag_effects_for_location(
self.tcx, self.mir, ctxt,
- Location { block: bb, index: idx },
+ Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
{
drop_flag_effects_for_location(
self.tcx, self.mir, ctxt,
- Location { block: bb, index: statements_len },
+ Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
let path_map = &move_data.path_map;
let rev_lookup = &move_data.rev_lookup;
- let loc = Location { block: bb, index: idx };
+ let loc = Location { block: bb, statement_index: idx };
debug!("stmt {:?} at loc {:?} moves out of move_indexes {:?}",
stmt, loc, &loc_map[loc]);
for move_index in &loc_map[loc] {
let (mir, move_data) = (self.mir, &ctxt.move_data);
let term = mir[bb].terminator();
let loc_map = &move_data.loc_map;
- let loc = Location { block: bb, index: statements_len };
+ let loc = Location { block: bb, statement_index: statements_len };
debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
term, loc, &loc_map[loc]);
let bits_per_block = self.bits_per_block(ctxt);
// except according to those terms.
use indexed_set::IdxSetBuf;
-use super::gather_moves::{MoveData, MovePathIndex, MovePathContent, Location};
+use super::gather_moves::{MoveData, MovePathIndex, MovePathContent};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
use super::{drop_flag_effects_for_location, on_all_children_bits};
use super::{DropFlagState, MoveDataParamEnv};
use super::patch::MirPatch;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::mir::repr::*;
use rustc::mir::transform::{Pass, MirPass, MirSource};
use rustc::middle::const_val::ConstVal;
use syntax_pos::Span;
use std::fmt;
+use std::iter;
use std::u32;
pub struct ElaborateDrops;
dead: self.flow_uninits.sets().on_entry_set_for(loc.block.index())
.to_owned(),
};
- for stmt in 0..loc.index {
+ for stmt in 0..loc.statement_index {
data.apply_location(self.tcx, self.mir, self.env,
- Location { block: loc.block, index: stmt });
+ Location { block: loc.block, statement_index: stmt });
}
data
}
let init_data = self.initialization_data_at(Location {
block: bb,
- index: data.statements.len()
+ statement_index: data.statements.len()
});
let path = self.move_data().rev_lookup.find(location);
fn elaborate_drops(&mut self)
{
for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
- let loc = Location { block: bb, index: data.statements.len() };
+ let loc = Location { block: bb, statement_index: data.statements.len() };
let terminator = data.terminator();
let resume_block = self.patch.resume_block();
unwind: Some(unwind)
}, bb);
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
- self.set_drop_flag(Location { block: target, index: 0 },
+ self.set_drop_flag(Location { block: target, statement_index: 0 },
child, DropFlagState::Present);
- self.set_drop_flag(Location { block: unwind, index: 0 },
+ self.set_drop_flag(Location { block: unwind, statement_index: 0 },
child, DropFlagState::Present);
});
}
let drop_block = self.drop_block(c);
if update_drop_flag {
self.set_drop_flag(
- Location { block: drop_block, index: 0 },
+ Location { block: drop_block, statement_index: 0 },
c.path,
DropFlagState::Absent
);
let unit_temp = Lvalue::Temp(self.patch.new_temp(tcx.mk_nil()));
let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
.unwrap_or_else(|e| tcx.sess.fatal(&e));
- let substs = Substs::new(tcx, vec![ty], vec![]);
+ let substs = Substs::new(tcx, iter::once(Kind::from(ty)));
let fty = tcx.lookup_item_type(free_func).ty.subst(tcx, substs);
self.patch.new_block(BasicBlockData {
}
fn drop_flags_on_init(&mut self) {
- let loc = Location { block: START_BLOCK, index: 0 };
+ let loc = Location { block: START_BLOCK, statement_index: 0 };
let span = self.patch.source_info_for_location(self.mir, loc).span;
let false_ = self.constant_bool(span, false);
for flag in self.drop_flags.values() {
} = data.terminator().kind {
assert!(!self.patch.is_patched(bb));
- let loc = Location { block: tgt, index: 0 };
+ let loc = Location { block: tgt, statement_index: 0 };
let path = self.move_data().rev_lookup.find(lv);
on_all_children_bits(
self.tcx, self.mir, self.move_data(), path,
}
fn drop_flags_for_args(&mut self) {
- let loc = Location { block: START_BLOCK, index: 0 };
+ let loc = Location { block: START_BLOCK, statement_index: 0 };
super::drop_flag_effects_for_function_entry(
self.tcx, self.mir, self.env, |path, ds| {
self.set_drop_flag(loc, path, ds);
}
}
}
- let loc = Location { block: bb, index: i };
+ let loc = Location { block: bb, statement_index: i };
super::drop_flag_effects_for_location(
self.tcx, self.mir, self.env, loc, |path, ds| {
if ds == DropFlagState::Absent || allow_initializations {
} = data.terminator().kind {
assert!(!self.patch.is_patched(bb));
- let loc = Location { block: bb, index: data.statements.len() };
+ let loc = Location { block: bb, statement_index: data.statements.len() };
let path = self.move_data().rev_lookup.find(lv);
on_all_children_bits(
self.tcx, self.mir, self.move_data(), path,
type Output = [MoveOutIndex];
fn index(&self, index: Location) -> &Self::Output {
assert!(index.block.index() < self.map.len());
- assert!(index.index < self.map[index.block.index()].len());
- &self.map[index.block.index()][index.index]
+ assert!(index.statement_index < self.map[index.block.index()].len());
+ &self.map[index.block.index()][index.statement_index]
}
}
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
-pub struct Location {
- /// block where action is located
- pub block: BasicBlock,
- /// index within above block; statement when < statments.len) or
- /// the terminator (when = statements.len).
- pub index: usize,
-}
-
-impl fmt::Debug for Location {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- write!(fmt, "{:?}[{}]", self.block, self.index)
- }
-}
-
#[derive(Debug)]
pub struct MovePathData<'tcx> {
move_paths: Vec<MovePath<'tcx>>,
};
for (i, stmt) in bb_data.statements.iter().enumerate() {
- let source = Location { block: bb, index: i };
+ let source = Location { block: bb, statement_index: i };
match stmt.kind {
StatementKind::Assign(ref lval, ref rval) => {
bb_ctxt.builder.create_move_path(lval);
TerminatorKind::Return => {
let source = Location { block: bb,
- index: bb_data.statements.len() };
+ statement_index: bb_data.statements.len() };
debug!("gather_moves Return on_move_out_lval return {:?}", source);
bb_ctxt.on_move_out_lval(SK::Return, &Lvalue::ReturnPointer, source);
}
TerminatorKind::If { ref cond, targets: _ } => {
let source = Location { block: bb,
- index: bb_data.statements.len() };
+ statement_index: bb_data.statements.len() };
bb_ctxt.on_operand(SK::If, cond, source);
}
TerminatorKind::Drop { ref location, target: _, unwind: _ } => {
let source = Location { block: bb,
- index: bb_data.statements.len() };
+ statement_index: bb_data.statements.len() };
bb_ctxt.on_move_out_lval(SK::Drop, location, source);
}
TerminatorKind::DropAndReplace { ref location, ref value, .. } => {
bb_ctxt.path_map.fill_to(assigned_path.index());
let source = Location { block: bb,
- index: bb_data.statements.len() };
+ statement_index: bb_data.statements.len() };
bb_ctxt.on_operand(SK::Use, value, source);
}
TerminatorKind::Call { ref func, ref args, ref destination, cleanup: _ } => {
let source = Location { block: bb,
- index: bb_data.statements.len() };
+ statement_index: bb_data.statements.len() };
bb_ctxt.on_operand(SK::CallFn, func, source);
for arg in args {
debug!("gather_moves Call on_operand {:?} {:?}", arg, source);
stmt_kind: StmtKind,
lval: &Lvalue<'tcx>,
source: Location) {
- let i = source.index;
+ let i = source.statement_index;
let index = MoveOutIndex::new(self.moves.len());
let path = self.builder.move_path_for(lval);
use rustc::hir::intravisit::{FnKind};
use rustc::mir::repr;
-use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator};
+use rustc::mir::repr::{BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
use rustc::session::Session;
use rustc::ty::{self, TyCtxt};
use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults};
use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use self::dataflow::{DefinitelyInitializedLvals};
-use self::gather_moves::{MoveData, MovePathIndex, Location};
+use self::gather_moves::{MoveData, MovePathIndex};
use self::gather_moves::{MovePathContent, MovePathData};
fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<P<MetaItem>> {
}
let block = &mir[loc.block];
- match block.statements.get(loc.index) {
+ match block.statements.get(loc.statement_index) {
Some(stmt) => match stmt.kind {
repr::StatementKind::SetDiscriminant{ .. } => {
span_bug!(stmt.source_info.span, "SetDiscrimant should not exist during borrowck");
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::gather_moves::Location;
use rustc::ty::Ty;
use rustc::mir::repr::*;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
};
Location {
block: bb,
- index: offset
+ statement_index: offset
}
}
}
debug!("MirPatch: adding statement {:?} at loc {:?}+{}",
stmt, loc, delta);
- loc.index += delta;
+ loc.statement_index += delta;
let source_info = Self::source_info_for_index(
&mir[loc.block], loc
);
mir[loc.block].statements.insert(
- loc.index, Statement {
+ loc.statement_index, Statement {
source_info: source_info,
kind: stmt
});
}
pub fn source_info_for_index(data: &BasicBlockData, loc: Location) -> SourceInfo {
- match data.statements.get(loc.index) {
+ match data.statements.get(loc.statement_index) {
Some(stmt) => stmt.source_info,
None => data.terminator().source_info
}
use std::fmt;
use std::mem;
use std::rc::Rc;
+use std::hash::{Hash, Hasher};
use syntax::ast;
use syntax::attr::AttrMetaMethods;
use syntax_pos::{MultiSpan, Span};
}
}
-#[derive(Eq, Hash)]
+#[derive(Eq)]
pub struct LoanPath<'tcx> {
kind: LoanPathKind<'tcx>,
ty: ty::Ty<'tcx>,
impl<'tcx> PartialEq for LoanPath<'tcx> {
fn eq(&self, that: &LoanPath<'tcx>) -> bool {
- let r = self.kind == that.kind;
- debug_assert!(self.ty == that.ty || !r,
- "Somehow loan paths are equal though their tys are not.");
- r
+ self.kind == that.kind
+ }
+}
+
+impl<'tcx> Hash for LoanPath<'tcx> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.kind.hash(state);
}
}
LpVar(ast::NodeId), // `x` in README.md
LpUpvar(ty::UpvarId), // `x` captured by-value into closure
LpDowncast(Rc<LoanPath<'tcx>>, DefId), // `x` downcast to particular enum variant
- LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem)
+ LpExtend(Rc<LoanPath<'tcx>>, mc::MutabilityCategory, LoanPathElem<'tcx>)
}
impl<'tcx> LoanPath<'tcx> {
// `enum E { X { foo: u32 }, Y { foo: u32 }}`
// each `foo` is qualified by the definitition id of the variant (`X` or `Y`).
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-pub enum LoanPathElem {
- LpDeref(mc::PointerKind),
+pub enum LoanPathElem<'tcx> {
+ LpDeref(mc::PointerKind<'tcx>),
LpInterior(Option<DefId>, InteriorKind),
}
// Errors that can occur
#[derive(PartialEq)]
-pub enum bckerr_code {
+pub enum bckerr_code<'tcx> {
err_mutbl,
- err_out_of_scope(ty::Region, ty::Region, euv::LoanCause), // superscope, subscope, loan cause
- err_borrowed_pointer_too_short(ty::Region, ty::Region), // loan, ptr
+ /// superscope, subscope, loan cause
+ err_out_of_scope(&'tcx ty::Region, &'tcx ty::Region, euv::LoanCause),
+ err_borrowed_pointer_too_short(&'tcx ty::Region, &'tcx ty::Region), // loan, ptr
}
// Combination of an error code and the categorization of the expression
span: Span,
cause: AliasableViolationKind,
cmt: mc::cmt<'tcx>,
- code: bckerr_code
+ code: bckerr_code<'tcx>
}
#[derive(Copy, Clone, Debug, PartialEq)]
self.free_region_map = old_free_region_map;
}
- pub fn is_subregion_of(&self, r_sub: ty::Region, r_sup: ty::Region)
+ pub fn is_subregion_of(&self, r_sub: &'tcx ty::Region, r_sup: &'tcx ty::Region)
-> bool
{
self.free_region_map.is_subregion_of(self.tcx, r_sub, r_sup)
pub fn report(&self, err: BckError<'tcx>) {
// Catch and handle some particular cases.
match (&err.code, &err.cause) {
- (&err_out_of_scope(ty::ReScope(_), ty::ReStatic, _),
+ (&err_out_of_scope(&ty::ReScope(_), &ty::ReStatic, _),
&BorrowViolation(euv::ClosureCapture(span))) |
- (&err_out_of_scope(ty::ReScope(_), ty::ReFree(..), _),
+ (&err_out_of_scope(&ty::ReScope(_), &ty::ReFree(..), _),
&BorrowViolation(euv::ClosureCapture(span))) => {
return self.report_out_of_scope_escaping_closure_capture(&err, span);
}
err
}
mc::AliasableBorrowed => {
- struct_span_err!(
+ let mut e = struct_span_err!(
self.tcx.sess, span, E0389,
- "{} in a `&` reference", prefix)
+ "{} in a `&` reference", prefix);
+ e.span_label(span, &"assignment into an immutable reference");
+ e
}
};
.emit();
}
- fn region_end_span(&self, region: ty::Region) -> Option<Span> {
- match region {
+ fn region_end_span(&self, region: &'tcx ty::Region) -> Option<Span> {
+ match *region {
ty::ReScope(scope) => {
match scope.span(&self.tcx.region_maps, &self.tcx.map) {
Some(s) => {
}
}
-fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option<Span> {
- match region {
+fn statement_scope_span(tcx: TyCtxt, region: &ty::Region) -> Option<Span> {
+ match *region {
ty::ReScope(scope) => {
match tcx.map.find(scope.node_id(&tcx.region_maps)) {
Some(hir_map::NodeStmt(stmt)) => Some(stmt.span),
_: NodeId,
span: Span,
_: cmt,
- _: Region,
+ _: &'tcx Region,
kind: BorrowKind,
_: LoanCause) {
match kind {
for (name, to) in lints {
let name = name.to_lowercase().replace("_", "-");
let desc = to.into_iter()
- .map(|x| x.as_str().replace("_", "-"))
+ .map(|x| x.to_string().replace("_", "-"))
.collect::<Vec<String>>()
.join(", ");
println!(" {} {}", padded(&name[..]), desc);
use rustc::middle::region::CodeExtentData;
use rustc::middle::resolve_lifetime;
use rustc::middle::stability;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
use rustc_metadata::cstore::CStore;
use rustc::hir::map as hir_map;
use rustc::session::{self, config};
+use std::iter;
use std::rc::Rc;
use syntax::ast;
use syntax::abi::Abi;
pub fn re_early_bound(&self,
index: u32,
name: &'static str)
- -> ty::Region {
+ -> &'tcx ty::Region {
let name = token::intern(name);
- ty::ReEarlyBound(ty::EarlyBoundRegion {
+ self.infcx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
index: index,
name: name,
- })
+ }))
}
- pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex) -> ty::Region {
- ty::ReLateBound(debruijn, ty::BrAnon(id))
+ pub fn re_late_bound_with_debruijn(&self, id: u32, debruijn: ty::DebruijnIndex)
+ -> &'tcx ty::Region {
+ self.infcx.tcx.mk_region(ty::ReLateBound(debruijn, ty::BrAnon(id)))
}
- pub fn t_rptr(&self, r: ty::Region) -> Ty<'tcx> {
- self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+ pub fn t_rptr(&self, r: &'tcx ty::Region) -> Ty<'tcx> {
+ self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
}
pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> {
let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1));
- self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+ self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
}
pub fn t_rptr_late_bound_with_debruijn(&self,
debruijn: ty::DebruijnIndex)
-> Ty<'tcx> {
let r = self.re_late_bound_with_debruijn(id, debruijn);
- self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+ self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
}
pub fn t_rptr_scope(&self, id: ast::NodeId) -> Ty<'tcx> {
self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
}
- pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region {
- ty::ReFree(ty::FreeRegion {
+ pub fn re_free(&self, nid: ast::NodeId, id: u32) -> &'tcx ty::Region {
+ self.infcx.tcx.mk_region(ty::ReFree(ty::FreeRegion {
scope: self.tcx().region_maps.item_extent(nid),
bound_region: ty::BrAnon(id),
- })
+ }))
}
pub fn t_rptr_free(&self, nid: ast::NodeId, id: u32) -> Ty<'tcx> {
let r = self.re_free(nid, id);
- self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(r), self.tcx().types.isize)
+ self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize)
}
pub fn t_rptr_static(&self) -> Ty<'tcx> {
env.t_fn(&[t_param], env.t_nil())
};
- let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]);
+ let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1)));
let t_substituted = t_source.subst(env.infcx.tcx, substs);
// t_expected = fn(&'a isize)
env.t_pair(t_param, env.t_fn(&[t_param], env.t_nil()))
};
- let substs = Substs::new(env.infcx.tcx, vec![t_rptr_bound1], vec![]);
+ let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(t_rptr_bound1)));
let t_substituted = t_source.subst(env.infcx.tcx, substs);
// t_expected = (&'a isize, fn(&'a isize))
env.t_fn(&[env.t_rptr(re_early)], env.t_nil())
};
- let substs = Substs::new(env.infcx.tcx, vec![], vec![re_bound1]);
+ let substs = Substs::new(env.infcx.tcx, iter::once(Kind::from(re_bound1)));
let t_substituted = t_source.subst(env.infcx.tcx, substs);
// t_expected = fn(&'a isize)
}
match write!(&mut self.dst, "\n") {
Err(e) => panic!("failed to emit error: {}", e),
- _ => ()
+ _ => match self.dst.flush() {
+ Err(e) => panic!("failed to emit error: {}", e),
+ _ => ()
+ }
}
}
}
fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
lvl: &Level,
dst: &mut Destination) -> io::Result<()> {
+ use lock;
+
+ // In order to prevent error message interleaving, where multiple error lines get intermixed
+ // when multiple compiler processes error simultaneously, we emit errors with additional
+ // steps.
+ //
+ // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When
+ // the .flush() is called we take the buffer created from the buffered writes and write it at
+ // one shot. Because the Unix systems use ANSI for the colors, which is a text-based styling
+ // scheme, this buffered approach works and maintains the styling.
+ //
+ // On Windows, styling happens through calls to a terminal API. This prevents us from using the
+ // same buffering approach. Instead, we use a global Windows mutex, which we acquire long
+ // enough to output the full error message, then we release.
+ let _buffer_lock = lock::acquire_global_lock("rustc_errors");
for line in rendered_buffer {
for part in line {
dst.apply_style(lvl.clone(), part.style)?;
}
write!(dst, "\n")?;
}
+ dst.flush()?;
Ok(())
}
}
}
+pub type BufferedStderr = term::Terminal<Output = BufferedWriter> + Send;
+
pub enum Destination {
Terminal(Box<term::StderrTerminal>),
+ BufferedTerminal(Box<BufferedStderr>),
Raw(Box<Write + Send>),
}
+/// Buffered writer gives us a way on Unix to buffer up an entire error message before we output
+/// it. This helps to prevent interleaving of multiple error messages when multiple compiler
+/// processes error simultaneously
+pub struct BufferedWriter {
+ buffer: Vec<u8>,
+}
+
+impl BufferedWriter {
+ // note: we use _new because the conditional compilation at its use site may make this
+ // this function unused on some platforms
+ fn _new() -> BufferedWriter {
+ BufferedWriter {
+ buffer: vec![]
+ }
+ }
+}
+
+impl Write for BufferedWriter {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ for b in buf {
+ self.buffer.push(*b);
+ }
+ Ok(buf.len())
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ let mut stderr = io::stderr();
+ let result = (|| {
+ stderr.write_all(&self.buffer)?;
+ stderr.flush()
+ })();
+ self.buffer.clear();
+ result
+ }
+}
+
impl Destination {
+ #[cfg(not(windows))]
+ /// When not on Windows, prefer the buffered terminal so that we can buffer an entire error
+ /// to be emitted at one time.
+ fn from_stderr() -> Destination {
+ let stderr: Option<Box<BufferedStderr>> =
+ term::TerminfoTerminal::new(BufferedWriter::_new())
+ .map(|t| Box::new(t) as Box<BufferedStderr>);
+
+ match stderr {
+ Some(t) => BufferedTerminal(t),
+ None => Raw(Box::new(io::stderr())),
+ }
+ }
+
+ #[cfg(windows)]
+ /// Return a normal, unbuffered terminal when on Windows.
fn from_stderr() -> Destination {
- match term::stderr() {
+ let stderr: Option<Box<term::StderrTerminal>> =
+ term::TerminfoTerminal::new(io::stderr())
+ .map(|t| Box::new(t) as Box<term::StderrTerminal>)
+ .or_else(|| term::WinConsole::new(io::stderr()).ok()
+ .map(|t| Box::new(t) as Box<term::StderrTerminal>));
+
+ match stderr {
Some(t) => Terminal(t),
None => Raw(Box::new(io::stderr())),
}
fn start_attr(&mut self, attr: term::Attr) -> io::Result<()> {
match *self {
Terminal(ref mut t) => { t.attr(attr)?; }
+ BufferedTerminal(ref mut t) => { t.attr(attr)?; }
Raw(_) => { }
}
Ok(())
fn reset_attrs(&mut self) -> io::Result<()> {
match *self {
Terminal(ref mut t) => { t.reset()?; }
+ BufferedTerminal(ref mut t) => { t.reset()?; }
Raw(_) => { }
}
Ok(())
fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
match *self {
Terminal(ref mut t) => t.write(bytes),
+ BufferedTerminal(ref mut t) => t.write(bytes),
Raw(ref mut w) => w.write(bytes),
}
}
fn flush(&mut self) -> io::Result<()> {
match *self {
Terminal(ref mut t) => t.flush(),
+ BufferedTerminal(ref mut t) => t.flush(),
Raw(ref mut w) => w.flush(),
}
}
pub mod snippet;
pub mod registry;
pub mod styled_buffer;
+mod lock;
use syntax_pos::{BytePos, Loc, FileLinesResult, FileName, MultiSpan, Span, NO_EXPANSION };
use syntax_pos::{MacroBacktrace};
--- /dev/null
+// Copyright 2016 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.
+
+//! Bindings to acquire a global named lock.
+//!
+//! This is intended to be used to synchronize multiple compiler processes to
+//! ensure that we can output complete errors without interleaving on Windows.
+//! Note that this is currently only needed for allowing only one 32-bit MSVC
+//! linker to execute at once on MSVC hosts, so this is only implemented for
+//! `cfg(windows)`. Also note that this may not always be used on Windows,
+//! only when targeting 32-bit MSVC.
+//!
+//! For more information about why this is necessary, see where this is called.
+
+use std::any::Any;
+
+#[cfg(windows)]
+#[allow(bad_style)]
+pub fn acquire_global_lock(name: &str) -> Box<Any> {
+ use std::ffi::CString;
+ use std::io;
+
+ type LPSECURITY_ATTRIBUTES = *mut u8;
+ type BOOL = i32;
+ type LPCSTR = *const u8;
+ type HANDLE = *mut u8;
+ type DWORD = u32;
+
+ const INFINITE: DWORD = !0;
+ const WAIT_OBJECT_0: DWORD = 0;
+ const WAIT_ABANDONED: DWORD = 0x00000080;
+
+ extern "system" {
+ fn CreateMutexA(lpMutexAttributes: LPSECURITY_ATTRIBUTES,
+ bInitialOwner: BOOL,
+ lpName: LPCSTR) -> HANDLE;
+ fn WaitForSingleObject(hHandle: HANDLE,
+ dwMilliseconds: DWORD) -> DWORD;
+ fn ReleaseMutex(hMutex: HANDLE) -> BOOL;
+ fn CloseHandle(hObject: HANDLE) -> BOOL;
+ }
+
+ struct Handle(HANDLE);
+
+ impl Drop for Handle {
+ fn drop(&mut self) {
+ unsafe {
+ CloseHandle(self.0);
+ }
+ }
+ }
+
+ struct Guard(Handle);
+
+ impl Drop for Guard {
+ fn drop(&mut self) {
+ unsafe {
+ ReleaseMutex((self.0).0);
+ }
+ }
+ }
+
+ let cname = CString::new(name).unwrap();
+ unsafe {
+ // Create a named mutex, with no security attributes and also not
+ // acquired when we create it.
+ //
+ // This will silently create one if it doesn't already exist, or it'll
+ // open up a handle to one if it already exists.
+ let mutex = CreateMutexA(0 as *mut _, 0, cname.as_ptr() as *const u8);
+ if mutex.is_null() {
+ panic!("failed to create global mutex named `{}`: {}", name,
+ io::Error::last_os_error());
+ }
+ let mutex = Handle(mutex);
+
+ // Acquire the lock through `WaitForSingleObject`.
+ //
+ // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
+ //
+ // A return value of `WAIT_ABANDONED` means that the previous holder of
+ // the thread exited without calling `ReleaseMutex`. This can happen,
+ // for example, when the compiler crashes or is interrupted via ctrl-c
+ // or the like. In this case, however, we are still transferred
+ // ownership of the lock so we continue.
+ //
+ // If an error happens.. well... that's surprising!
+ match WaitForSingleObject(mutex.0, INFINITE) {
+ WAIT_OBJECT_0 | WAIT_ABANDONED => {}
+ code => {
+ panic!("WaitForSingleObject failed on global mutex named \
+ `{}`: {} (ret={:x})", name,
+ io::Error::last_os_error(), code);
+ }
+ }
+
+ // Return a guard which will call `ReleaseMutex` when dropped.
+ Box::new(Guard(mutex))
+ }
+}
+
+#[cfg(unix)]
+pub fn acquire_global_lock(_name: &str) -> Box<Any> {
+ Box::new(())
+}
Col: c_uint)
-> DILexicalBlock;
+ pub fn LLVMRustDIBuilderCreateLexicalBlockFile(Builder: DIBuilderRef,
+ Scope: DIScope,
+ File: DIFile)
+ -> DILexicalBlock;
+
pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef,
Context: DIScope,
Name: *const c_char,
// Encoding and decoding the side tables
trait rbml_writer_helpers<'tcx> {
- fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region);
+ fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region);
fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
fn emit_substs<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
substs: &Substs<'tcx>);
}
impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
- fn emit_region(&mut self, ecx: &e::EncodeContext, r: ty::Region) {
+ fn emit_region(&mut self, ecx: &e::EncodeContext, r: &'tcx ty::Region) {
self.emit_opaque(|this| Ok(tyencode::enc_region(&mut this.cursor,
&ecx.ty_str_ctxt(),
r)));
&adjustment::AutoPtr(r, m) => {
this.emit_enum_variant("AutoPtr", 0, 2, |this| {
this.emit_enum_variant_arg(0,
- |this| Ok(this.emit_region(ecx, *r)));
+ |this| Ok(this.emit_region(ecx, r)));
this.emit_enum_variant_arg(1, |this| m.encode(this))
})
}
f: F) -> R
where F: for<'x> FnOnce(&mut tydecode::TyDecoder<'x, 'tcx>) -> R;
- fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region;
+ fn read_region<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> &'tcx ty::Region;
fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>;
fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>;
fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> ty::Predicate<'tcx>;
fn read_substs<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> &'tcx Substs<'tcx>;
- fn read_upvar_capture(&mut self, dcx: &DecodeContext)
- -> ty::UpvarCapture;
+ fn read_upvar_capture<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
+ -> ty::UpvarCapture<'tcx>;
fn read_auto_adjustment<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
-> adjustment::AutoAdjustment<'tcx>;
fn read_cast_kind<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
str
}
}
- fn read_region(&mut self, dcx: &DecodeContext) -> ty::Region {
+ fn read_region<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> &'tcx ty::Region {
// Note: regions types embed local node ids. In principle, we
// should translate these node ids into the new decode
// context. However, we do not bother, because region types
.parse_substs())
}).unwrap()
}
- fn read_upvar_capture(&mut self, dcx: &DecodeContext) -> ty::UpvarCapture {
+ fn read_upvar_capture<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
+ -> ty::UpvarCapture<'tcx> {
self.read_enum("UpvarCapture", |this| {
let variants = ["ByValue", "ByRef"];
this.read_enum_variant(&variants, |this, i| {
this.read_enum_variant(&variants, |this, i| {
Ok(match i {
0 => {
- let r: ty::Region =
+ let r: &'tcx ty::Region =
this.read_enum_variant_arg(0, |this| {
Ok(this.read_region(dcx))
}).unwrap();
Decodable::decode(this)
}).unwrap();
- adjustment::AutoPtr(dcx.tcx.mk_region(r), m)
+ adjustment::AutoPtr(r, m)
}
1 => {
let m: hir::Mutability =
decoder::closure_ty(&cdata, def_id.index, tcx)
}
- fn item_variances(&self, def: DefId) -> ty::ItemVariances {
+ fn item_variances(&self, def: DefId) -> Vec<ty::Variance> {
self.dep_graph.read(DepNode::MetaData(def));
let cdata = self.get_crate_data(def.krate);
decoder::get_item_variances(&cdata, def.index)
decoder::is_foreign_item(&cdata, did.index)
}
- fn is_static_method(&self, def: DefId) -> bool
- {
- self.dep_graph.read(DepNode::MetaData(def));
- let cdata = self.get_crate_data(def.krate);
- decoder::is_static_method(&cdata, def.index)
- }
-
fn is_statically_included_foreign_item(&self, id: ast::NodeId) -> bool
{
self.do_is_statically_included_foreign_item(id)
use rustc::mir;
use rustc::mir::visit::MutVisitor;
+use rustc::mir::repr::Location;
use std::cell::Cell;
use std::io;
pub fn crate_rustc_version(data: &[u8]) -> Option<String> {
let doc = rbml::Doc::new(data);
- reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.as_str())
+ reader::maybe_get_doc(doc, tag_rustc_version).map(|s| s.to_string())
}
pub fn load_xrefs(data: &[u8]) -> index::DenseIndex {
fn item_sort(item: rbml::Doc) -> Option<char> {
reader::tagged_docs(item, tag_item_trait_item_sort).nth(0).map(|doc| {
- doc.as_str_slice().as_bytes()[0] as char
+ doc.as_str().as_bytes()[0] as char
})
}
fn maybe_item_name(item: rbml::Doc) -> Option<ast::Name> {
reader::maybe_get_doc(item, tag_paths_data_name).map(|name| {
- let string = name.as_str_slice();
+ let string = name.as_str();
token::intern(string)
})
}
fn parse_associated_type_names(item_doc: rbml::Doc) -> Vec<ast::Name> {
let names_doc = reader::get_doc(item_doc, tag_associated_type_names);
reader::tagged_docs(names_doc, tag_associated_type_name)
- .map(|name_doc| token::intern(name_doc.as_str_slice()))
+ .map(|name_doc| token::intern(name_doc.as_str()))
.collect()
}
let name_doc = reader::get_doc(reexport_doc,
tag_items_data_item_reexport_name);
- let name = name_doc.as_str_slice();
+ let name = name_doc.as_str();
// This reexport may be in yet another crate.
let crate_data = if child_def_id.krate == cdata.cnum {
impl<'v, 'cdata, 'codemap> mir::visit::MutVisitor<'v>
for MirDefIdAndSpanTranslator<'cdata, 'codemap>
{
- fn visit_def_id(&mut self, def_id: &mut DefId) {
+ fn visit_def_id(&mut self, def_id: &mut DefId, _: Location) {
*def_id = translate_def_id(self.crate_metadata, *def_id);
}
}
}
-fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory {
+fn get_explicit_self<'a, 'tcx>(item: rbml::Doc, tcx: TyCtxt<'a, 'tcx, 'tcx>)
+ -> ty::ExplicitSelfCategory<'tcx> {
fn get_mutability(ch: u8) -> hir::Mutability {
match ch as char {
'i' => hir::MutImmutable,
}
let explicit_self_doc = reader::get_doc(item, tag_item_trait_method_explicit_self);
- let string = explicit_self_doc.as_str_slice();
+ let string = explicit_self_doc.as_str();
let explicit_self_kind = string.as_bytes()[0];
match explicit_self_kind as char {
// FIXME(#4846) expl. region
'&' => {
ty::ExplicitSelfCategory::ByReference(
- ty::ReEmpty,
+ tcx.mk_region(ty::ReEmpty),
get_mutability(string.as_bytes()[1]))
}
_ => bug!("unknown self type code: `{}`", explicit_self_kind as char)
item_name(doc)
}
-pub fn is_static_method(cdata: Cmd, id: DefIndex) -> bool {
- let doc = cdata.lookup_item(id);
- match item_sort(doc) {
- Some('r') | Some('p') => {
- get_explicit_self(doc) == ty::ExplicitSelfCategory::Static
- }
- _ => false
- }
-}
-
pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> Option<ty::ImplOrTraitItem<'tcx>> {
let item_doc = cdata.lookup_item(id);
"the type {:?} of the method {:?} is not a function?",
ity, name)
};
- let explicit_self = get_explicit_self(item_doc);
+ let explicit_self = get_explicit_self(item_doc, tcx);
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
generics,
}).collect()
}
-pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances {
+pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec<ty::Variance> {
let item_doc = cdata.lookup_item(id);
let variance_doc = reader::get_doc(item_doc, tag_item_variances);
let mut decoder = reader::Decoder::new(variance_doc);
fn get_meta_items(md: rbml::Doc) -> Vec<P<ast::MetaItem>> {
reader::tagged_docs(md, tag_meta_item_word).map(|meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
- let n = token::intern_and_get_ident(nd.as_str_slice());
+ let n = token::intern_and_get_ident(nd.as_str());
attr::mk_word_item(n)
}).chain(reader::tagged_docs(md, tag_meta_item_name_value).map(|meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
let vd = reader::get_doc(meta_item_doc, tag_meta_item_value);
- let n = token::intern_and_get_ident(nd.as_str_slice());
- let v = token::intern_and_get_ident(vd.as_str_slice());
+ let n = token::intern_and_get_ident(nd.as_str());
+ let v = token::intern_and_get_ident(vd.as_str());
// FIXME (#623): Should be able to decode MetaItemKind::NameValue variants,
// but currently the encoder just drops them
attr::mk_name_value_item_str(n, v)
})).chain(reader::tagged_docs(md, tag_meta_item_list).map(|meta_item_doc| {
let nd = reader::get_doc(meta_item_doc, tag_meta_item_name);
- let n = token::intern_and_get_ident(nd.as_str_slice());
+ let n = token::intern_and_get_ident(nd.as_str());
let subitems = get_meta_items(meta_item_doc);
attr::mk_list_item(n, subitems)
})).collect()
fn docstr(doc: rbml::Doc, tag_: usize) -> String {
let d = reader::get_doc(doc, tag_);
- d.as_str_slice().to_string()
+ d.as_str().to_string()
}
reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
let cratedoc = rbml::Doc::new(data);
reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
- doc.as_str_slice()
+ doc.as_str()
})
}
pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str {
let crate_doc = rbml::Doc::new(data);
let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator);
- let slice: &'a str = disambiguator_doc.as_str_slice();
+ let slice: &'a str = disambiguator_doc.as_str();
slice
}
tag_dylib_dependency_formats);
let mut result = Vec::new();
- debug!("found dylib deps: {}", formats.as_str_slice());
- for spec in formats.as_str_slice().split(',') {
+ debug!("found dylib deps: {}", formats.as_str());
+ for spec in formats.as_str().split(',') {
if spec.is_empty() { continue }
- let cnum = spec.split(':').nth(0).unwrap();
- let link = spec.split(':').nth(1).unwrap();
+ let mut split = spec.split(':');
+ let cnum = split.next().unwrap();
+ let link = split.next().unwrap();
let cnum: ast::CrateNum = cnum.parse().unwrap();
let cnum = cdata.cnum_map.borrow()[cnum];
result.push((cnum, if link == "d" {
match reader::maybe_get_doc(method_doc, tag_method_argument_names) {
Some(args_doc) => {
reader::tagged_docs(args_doc, tag_method_argument_name).map(|name_doc| {
- name_doc.as_str_slice().to_string()
+ name_doc.as_str().to_string()
}).collect()
},
None => vec![],
let mut decoder = reader::Decoder::new(def_key_doc);
let simple_key = def_key::DefKey::decode(&mut decoder).unwrap();
let name = reader::maybe_get_doc(item_doc, tag_paths_data_name).map(|name| {
- token::intern(name.as_str_slice()).as_str()
+ token::intern(name.as_str()).as_str()
});
def_key::recover_def_key(simple_key, name)
}
use rustc::hir::def_id::{DefId, DefIndex};
use middle::region;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Kind, Substs};
use rustc::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rbml;
}
pub fn parse_substs(&mut self) -> &'tcx Substs<'tcx> {
- let mut regions = vec![];
- let mut types = vec![];
+ let mut params = vec![];
assert_eq!(self.next(), '[');
- while self.peek() != '|' {
- regions.push(self.parse_region());
- }
- assert_eq!(self.next(), '|');
while self.peek() != ']' {
- types.push(self.parse_ty());
+ let k = match self.next() {
+ 'r' => Kind::from(self.parse_region()),
+ 't' => Kind::from(self.parse_ty()),
+ _ => bug!()
+ };
+ params.push(k);
}
assert_eq!(self.next(), ']');
- Substs::new(self.tcx, types, regions)
+ Substs::new(self.tcx, params)
}
pub fn parse_generics(&mut self) -> &'tcx ty::Generics<'tcx> {
}
}
- pub fn parse_region(&mut self) -> ty::Region {
- match self.next() {
+ pub fn parse_region(&mut self) -> &'tcx ty::Region {
+ self.tcx.mk_region(match self.next() {
'b' => {
assert_eq!(self.next(), '[');
let id = ty::DebruijnIndex::new(self.parse_u32());
'e' => ty::ReEmpty,
'E' => ty::ReErased,
_ => bug!("parse_region: bad input")
- }
+ })
}
fn parse_scope(&mut self) -> region::CodeExtent {
'~' => return tcx.mk_box(self.parse_ty()),
'*' => return tcx.mk_ptr(self.parse_mt()),
'&' => {
- let r = self.parse_region();
- let mt = self.parse_mt();
- return tcx.mk_ref(tcx.mk_region(r), mt);
+ return tcx.mk_ref(self.parse_region(), self.parse_mt());
}
'V' => {
let t = self.parse_ty();
}
}
- fn parse_region_param_def(&mut self) -> ty::RegionParameterDef {
+ fn parse_region_param_def(&mut self) -> ty::RegionParameterDef<'tcx> {
let name = self.parse_name(':');
let def_id = self.parse_def();
let index = self.parse_u32();
}
- fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault {
+ fn parse_object_lifetime_default(&mut self) -> ty::ObjectLifetimeDefault<'tcx> {
match self.next() {
'a' => ty::ObjectLifetimeDefault::Ambiguous,
'b' => ty::ObjectLifetimeDefault::BaseDefault,
ty::TyRawPtr(mt) => { write!(w, "*"); enc_mt(w, cx, mt); }
ty::TyRef(r, mt) => {
write!(w, "&");
- enc_region(w, cx, *r);
+ enc_region(w, cx, r);
enc_mt(w, cx, mt);
}
ty::TyArray(t, sz) => {
pub fn enc_substs<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
substs: &Substs<'tcx>) {
write!(w, "[");
- for &r in &substs.regions {
- enc_region(w, cx, r);
- }
- write!(w, "|");
- for &ty in &substs.types {
- enc_ty(w, cx, ty);
+ for &k in substs.params() {
+ if let Some(ty) = k.as_type() {
+ write!(w, "t");
+ enc_ty(w, cx, ty);
+ } else if let Some(r) = k.as_region() {
+ write!(w, "r");
+ enc_region(w, cx, r);
+ } else {
+ bug!()
+ }
}
write!(w, "]");
}
}
}
-pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: ty::Region) {
- match r {
+pub fn enc_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, r: &ty::Region) {
+ match *r {
ty::ReLateBound(id, br) => {
write!(w, "b[{}|", id.depth);
enc_bound_region(w, cx, br);
//! Routines for manipulating the control-flow graph.
-use build::{CFG, Location};
+use build::CFG;
use rustc::mir::repr::*;
impl<'tcx> CFG<'tcx> {
var_id: NodeId,
var_ty: Ty<'tcx>,
mutability: Mutability,
- binding_mode: BindingMode,
+ binding_mode: BindingMode<'tcx>,
}
#[derive(Clone, Debug)]
assert!(ty.is_slice());
let eq_def_id = self.hir.tcx().lang_items.eq_trait().unwrap();
let ty = mt.ty;
- let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, vec![ty]);
+ let (mty, method) = self.hir.trait_method(eq_def_id, "eq", ty, &[ty]);
let bool_ty = self.hir.bool_ty();
let eq_result = self.temp(bool_ty);
pub postdoms: Vec<Location>,
}
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
-pub struct Location {
- /// the location is within this block
- pub block: BasicBlock,
-
- /// the location is the start of the this statement; or, if `statement_index`
- /// == num-statements, then the start of the terminator.
- pub statement_index: usize,
-}
-
pub type ScopeAuxiliaryVec = IndexVec<ScopeId, ScopeAuxiliary>;
///////////////////////////////////////////////////////////////////////////
use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary, ScopeId};
use rustc::middle::region::{CodeExtent, CodeExtentData};
use rustc::middle::lang_items;
-use rustc::ty::subst::{Substs, Subst};
+use rustc::ty::subst::{Kind, Substs, Subst};
use rustc::ty::{Ty, TyCtxt};
use rustc::mir::repr::*;
use syntax_pos::Span;
use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::fnv::FnvHashMap;
+use std::iter;
+
pub struct Scope<'tcx> {
/// the scope-id within the scope_auxiliary
id: ScopeId,
-> TerminatorKind<'tcx> {
let free_func = tcx.lang_items.require(lang_items::BoxFreeFnLangItem)
.unwrap_or_else(|e| tcx.sess.fatal(&e));
- let substs = Substs::new(tcx, vec![data.item_ty], vec![]);
+ let substs = Substs::new(tcx, iter::once(Kind::from(data.item_ty)));
TerminatorKind::Call {
func: Operand::Constant(Constant {
span: data.span,
region, ty::TypeAndMut { ty: expr.ty, mutbl: mutbl }),
span: expr.span,
kind: ExprKind::Borrow {
- region: *region,
+ region: region,
borrow_kind: to_borrow_kind(mutbl),
arg: expr.to_ref()
}
ty: adjusted_ty,
span: self.span,
kind: ExprKind::Borrow {
- region: *r,
+ region: r,
borrow_kind: to_borrow_kind(m),
arg: expr.to_ref(),
},
ty: cx.tcx.mk_ref(region, ty::TypeAndMut { ty: expr.ty, mutbl: m }),
span: self.span,
kind: ExprKind::Borrow {
- region: *region,
+ region: region,
borrow_kind: to_borrow_kind(m),
arg: expr.to_ref(),
},
_ => span_bug!(expr.span, "type of & not region"),
};
ExprKind::Borrow {
- region: *region,
+ region: region,
borrow_kind: to_borrow_kind(mutbl),
arg: expr.to_ref(),
}
ExprKind::Deref {
arg: Expr {
temp_lifetime: temp_lifetime,
- ty: cx.tcx.mk_ref(
- cx.tcx.mk_region(borrow.region),
+ ty: cx.tcx.mk_ref(borrow.region,
ty::TypeAndMut {
ty: var_ty,
mutbl: borrow.kind.to_mutbl_lossy()
}
PassArgs::ByRef => {
- let scope = cx.tcx.region_maps.node_extent(expr.id);
- let region = cx.tcx.mk_region(ty::ReScope(scope));
+ let region = cx.tcx.node_scope_region(expr.id);
let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
argrefs.extend(
args.iter()
temp_lifetime: temp_lifetime,
ty: adjusted_ty,
span: expr.span,
- kind: ExprKind::Borrow { region: *region,
+ kind: ExprKind::Borrow { region: region,
borrow_kind: BorrowKind::Shared,
arg: arg.to_ref() }
}.to_ref()
trait_def_id: DefId,
method_name: &str,
self_ty: Ty<'tcx>,
- params: Vec<Ty<'tcx>>)
+ params: &[Ty<'tcx>])
-> (Ty<'tcx>, Literal<'tcx>) {
let method_name = token::intern(method_name);
- let substs = Substs::new_trait(self.tcx, params, vec![], self_ty);
+ let substs = Substs::new_trait(self.tcx, self_ty, params);
for trait_item in self.tcx.trait_items(trait_def_id).iter() {
match *trait_item {
ty::ImplOrTraitItem::MethodTraitItem(ref method) => {
let id = self.cx.tcx.expect_def(pat.id).var_id();
let var_ty = self.cx.tcx.node_id_to_type(pat.id);
let region = match var_ty.sty {
- ty::TyRef(&r, _) => Some(r),
+ ty::TyRef(r, _) => Some(r),
_ => None,
};
let (mutability, mode) = match bm {
id: DefId,
},
Borrow {
- region: Region,
+ region: &'tcx Region,
borrow_kind: BorrowKind,
arg: ExprRef<'tcx>,
},
Binding {
mutability: Mutability,
name: ast::Name,
- mode: BindingMode,
+ mode: BindingMode<'tcx>,
var: ast::NodeId,
ty: Ty<'tcx>,
subpattern: Option<Pattern<'tcx>>,
}
#[derive(Copy, Clone, Debug)]
-pub enum BindingMode {
+pub enum BindingMode<'tcx> {
ByValue,
- ByRef(Region, BorrowKind),
+ ByRef(&'tcx Region, BorrowKind),
}
#[derive(Clone, Debug)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use build::{Location, ScopeAuxiliaryVec, ScopeId};
+use build::{ScopeAuxiliaryVec, ScopeId};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::mir::repr::*;
pub struct NoLandingPads;
impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
- fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) {
+ fn visit_terminator(&mut self,
+ bb: BasicBlock,
+ terminator: &mut Terminator<'tcx>,
+ location: Location) {
match terminator.kind {
TerminatorKind::Goto { .. } |
TerminatorKind::Resume |
unwind.take();
},
}
- self.super_terminator(bb, terminator);
+ self.super_terminator(bb, terminator, location);
}
}
use rustc::ty::TyCtxt;
use syntax_pos::Span;
-use build::Location;
-
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
use std::mem;
+use std::usize;
/// State of a temporary during collection and promotion.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct TempCollector {
temps: IndexVec<Temp, TempState>,
- location: Location,
span: Span
}
impl<'tcx> Visitor<'tcx> for TempCollector {
- fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
- self.super_lvalue(lvalue, context);
+ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
+ self.super_lvalue(lvalue, context, location);
if let Lvalue::Temp(index) = *lvalue {
// Ignore drops, if the temp gets promoted,
// then it's constant and thus drop is noop.
LvalueContext::Store |
LvalueContext::Call => {
*temp = TempState::Defined {
- location: self.location,
+ location: location,
uses: 0
};
return;
fn visit_source_info(&mut self, source_info: &SourceInfo) {
self.span = source_info.span;
}
-
- fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
- assert_eq!(self.location.block, bb);
- self.super_statement(bb, statement);
- self.location.statement_index += 1;
- }
-
- fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
- self.location.statement_index = 0;
- self.location.block = bb;
- self.super_basic_block_data(bb, data);
- }
}
pub fn collect_temps(mir: &Mir, rpo: &mut ReversePostorder) -> IndexVec<Temp, TempState> {
let mut collector = TempCollector {
temps: IndexVec::from_elem(TempState::Undefined, &mir.temp_decls),
- location: Location {
- block: START_BLOCK,
- statement_index: 0
- },
span: mir.span
};
for (bb, data) in rpo {
// Then, recurse for components in the Rvalue or Call.
if stmt_idx < no_stmts {
- self.visit_rvalue(rvalue.as_mut().unwrap());
+ self.visit_rvalue(rvalue.as_mut().unwrap(), Location {
+ block: bb,
+ statement_index: stmt_idx
+ });
} else {
- self.visit_terminator_kind(bb, call.as_mut().unwrap());
+ self.visit_terminator_kind(bb, call.as_mut().unwrap(), Location {
+ block: bb,
+ statement_index: no_stmts
+ });
}
let new_temp = self.promoted.temp_decls.push(TempDecl {
}
}
};
- self.visit_rvalue(&mut rvalue);
+ self.visit_rvalue(&mut rvalue, Location{
+ block: BasicBlock::new(0),
+ statement_index: usize::MAX
+ });
self.assign(Lvalue::ReturnPointer, rvalue, span);
self.source.promoted.push(self.promoted);
}
/// Replaces all temporaries with their promoted counterparts.
impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
- fn visit_lvalue(&mut self, lvalue: &mut Lvalue<'tcx>, context: LvalueContext) {
+ fn visit_lvalue(&mut self,
+ lvalue: &mut Lvalue<'tcx>,
+ context: LvalueContext,
+ location: Location) {
if let Lvalue::Temp(ref mut temp) = *lvalue {
*temp = self.promote_temp(*temp);
}
- self.super_lvalue(lvalue, context);
+ self.super_lvalue(lvalue, context, location);
}
}
use std::collections::hash_map::Entry;
use std::fmt;
-
-use build::Location;
+use std::usize;
use super::promote_consts::{self, Candidate, TempState};
return_qualif: Option<Qualif>,
qualif: Qualif,
const_fn_arg_vars: BitVector,
- location: Location,
temp_promotion_state: IndexVec<Temp, TempState>,
promotion_candidates: Vec<Candidate>
}
return_qualif: None,
qualif: Qualif::empty(),
const_fn_arg_vars: BitVector::new(mir.var_decls.len()),
- location: Location {
- block: START_BLOCK,
- statement_index: 0
- },
temp_promotion_state: temps,
promotion_candidates: vec![]
}
}
/// Assign the current qualification to the given destination.
- fn assign(&mut self, dest: &Lvalue<'tcx>) {
+ fn assign(&mut self, dest: &Lvalue<'tcx>, location: Location) {
let qualif = self.qualif;
let span = self.span;
let store = |slot: &mut Option<Qualif>| {
// This must be an explicit assignment.
_ => {
// Catch more errors in the destination.
- self.visit_lvalue(dest, LvalueContext::Store);
+ self.visit_lvalue(dest, LvalueContext::Store, location);
self.statement_like();
}
}
self.qualif = Qualif::NOT_CONST;
for index in 0..mir.var_decls.len() {
if !self.const_fn_arg_vars.contains(index) {
- self.assign(&Lvalue::Var(Var::new(index)));
+ self.assign(&Lvalue::Var(Var::new(index)), Location {
+ block: bb,
+ statement_index: usize::MAX,
+ });
}
}
/// For functions (constant or not), it also records
/// candidates for promotion in promotion_candidates.
impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
- fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) {
+ fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext, location: Location) {
match *lvalue {
Lvalue::Arg(_) => {
self.add(Qualif::FN_ARGUMENT);
}
Lvalue::Projection(ref proj) => {
self.nest(|this| {
- this.super_lvalue(lvalue, context);
+ this.super_lvalue(lvalue, context, location);
match proj.elem {
ProjectionElem::Deref => {
if !this.try_consume() {
}
}
- fn visit_operand(&mut self, operand: &Operand<'tcx>) {
+ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
match *operand {
Operand::Consume(_) => {
self.nest(|this| {
- this.super_operand(operand);
+ this.super_operand(operand, location);
this.try_consume();
});
}
if let Literal::Item { def_id, substs } = constant.literal {
// Don't peek inside generic (associated) constants.
- if !substs.types.is_empty() {
+ if substs.types().next().is_some() {
self.add_type(constant.ty);
} else {
let qualif = qualify_const_item_cached(self.tcx,
}
}
- fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
+ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
// Recurse through operands and lvalues.
- self.super_rvalue(rvalue);
+ self.super_rvalue(rvalue, location);
match *rvalue {
Rvalue::Use(_) |
}
// We might have a candidate for promotion.
- let candidate = Candidate::Ref(self.location);
+ let candidate = Candidate::Ref(location);
if self.mode == Mode::Fn || self.mode == Mode::ConstFn {
if !self.qualif.intersects(Qualif::NEVER_PROMOTE) {
// We can only promote direct borrows of temps.
}
}
- fn visit_terminator_kind(&mut self, bb: BasicBlock, kind: &TerminatorKind<'tcx>) {
+ fn visit_terminator_kind(&mut self,
+ bb: BasicBlock,
+ kind: &TerminatorKind<'tcx>,
+ location: Location) {
if let TerminatorKind::Call { ref func, ref args, ref destination, .. } = *kind {
- self.visit_operand(func);
+ self.visit_operand(func, location);
let fn_ty = func.ty(self.mir, self.tcx);
let (is_shuffle, is_const_fn) = match fn_ty.sty {
for (i, arg) in args.iter().enumerate() {
self.nest(|this| {
- this.visit_operand(arg);
+ this.visit_operand(arg, location);
if is_shuffle && i == 2 && this.mode == Mode::Fn {
let candidate = Candidate::ShuffleIndices(bb);
if !this.qualif.intersects(Qualif::NEVER_PROMOTE) {
self.deny_drop();
}
}
- self.assign(dest);
+ self.assign(dest, location);
}
} else {
// Qualify any operands inside other terminators.
- self.super_terminator_kind(bb, kind);
+ self.super_terminator_kind(bb, kind, location);
}
}
- fn visit_assign(&mut self, _: BasicBlock, dest: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) {
- self.visit_rvalue(rvalue);
+ fn visit_assign(&mut self,
+ _: BasicBlock,
+ dest: &Lvalue<'tcx>,
+ rvalue: &Rvalue<'tcx>,
+ location: Location) {
+ self.visit_rvalue(rvalue, location);
// Check the allowed const fn argument forms.
if let (Mode::ConstFn, &Lvalue::Var(index)) = (self.mode, dest) {
}
}
- self.assign(dest);
+ self.assign(dest, location);
}
fn visit_source_info(&mut self, source_info: &SourceInfo) {
self.span = source_info.span;
}
- fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>) {
- assert_eq!(self.location.block, bb);
+ fn visit_statement(&mut self, bb: BasicBlock, statement: &Statement<'tcx>, location: Location) {
self.nest(|this| {
this.visit_source_info(&statement.source_info);
match statement.kind {
StatementKind::Assign(ref lvalue, ref rvalue) => {
- this.visit_assign(bb, lvalue, rvalue);
+ this.visit_assign(bb, lvalue, rvalue, location);
}
StatementKind::SetDiscriminant { .. } |
StatementKind::StorageLive(_) |
StatementKind::StorageDead(_) => {}
}
});
- self.location.statement_index += 1;
- }
-
- fn visit_terminator(&mut self, bb: BasicBlock, terminator: &Terminator<'tcx>) {
- assert_eq!(self.location.block, bb);
- self.nest(|this| this.super_terminator(bb, terminator));
}
- fn visit_basic_block_data(&mut self, bb: BasicBlock, data: &BasicBlockData<'tcx>) {
- self.location.statement_index = 0;
- self.location.block = bb;
- self.super_basic_block_data(bb, data);
+ fn visit_terminator(&mut self,
+ bb: BasicBlock,
+ terminator: &Terminator<'tcx>,
+ location: Location) {
+ self.nest(|this| this.super_terminator(bb, terminator, location));
}
}
}
}
- fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: visit::LvalueContext) {
- self.sanitize_lvalue(lvalue);
+ fn visit_lvalue(&mut self,
+ lvalue: &Lvalue<'tcx>,
+ _context: visit::LvalueContext,
+ location: Location) {
+ self.sanitize_lvalue(lvalue, location);
}
- fn visit_constant(&mut self, constant: &Constant<'tcx>) {
- self.super_constant(constant);
+ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
+ self.super_constant(constant, location);
self.sanitize_type(constant, constant.ty);
}
- fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
- self.super_rvalue(rvalue);
+ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+ self.super_rvalue(rvalue, location);
if let Some(ty) = rvalue.ty(self.mir, self.tcx()) {
self.sanitize_type(rvalue, ty);
}
}
}
- fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>) -> LvalueTy<'tcx> {
+ fn sanitize_lvalue(&mut self, lvalue: &Lvalue<'tcx>, location: Location) -> LvalueTy<'tcx> {
debug!("sanitize_lvalue: {:?}", lvalue);
match *lvalue {
Lvalue::Var(index) => LvalueTy::Ty { ty: self.mir.var_decls[index].ty },
LvalueTy::Ty { ty: self.mir.return_ty }
}
Lvalue::Projection(ref proj) => {
- let base_ty = self.sanitize_lvalue(&proj.base);
+ let base_ty = self.sanitize_lvalue(&proj.base, location);
if let LvalueTy::Ty { ty } = base_ty {
if ty.references_error() {
assert!(self.errors_reported);
return LvalueTy::Ty { ty: self.tcx().types.err };
}
}
- self.sanitize_projection(base_ty, &proj.elem, lvalue)
+ self.sanitize_projection(base_ty, &proj.elem, lvalue, location)
}
}
}
fn sanitize_projection(&mut self,
base: LvalueTy<'tcx>,
pi: &LvalueElem<'tcx>,
- lvalue: &Lvalue<'tcx>)
+ lvalue: &Lvalue<'tcx>,
+ location: Location)
-> LvalueTy<'tcx> {
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, lvalue);
let tcx = self.tcx();
}
}
ProjectionElem::Index(ref i) => {
- self.visit_operand(i);
+ self.visit_operand(i, location);
let index_ty = i.ty(self.mir, tcx);
if index_ty != tcx.types.usize {
LvalueTy::Ty {
borrow_id: ast::NodeId,
_borrow_span: Span,
cmt: mc::cmt<'tcx>,
- _loan_region: ty::Region,
+ _loan_region: &'tcx ty::Region,
bk: ty::BorrowKind,
loan_cause: euv::LoanCause) {
// Kind of hacky, but we allow Unsafe coercions in constants.
_borrow_id: ast::NodeId,
_borrow_span: Span,
_cmt: mc::cmt,
- _loan_region: ty::Region,
+ _loan_region: &'tcx ty::Region,
_bk: ty::BorrowKind,
_loan_cause: euv::LoanCause) {
}
use rustc::middle::{cstore, weak_lang_items};
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
-use rustc::ty::{self, TyCtxt, TypeFoldable};
+use rustc::ty::{Ty, TyCtxt, TypeFoldable};
use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
+use rustc::ty::subst::Substs;
use rustc::hir::map::definitions::{DefPath, DefPathData};
use syntax::attr;
// parameters substituted; this is
// included in the hash as a kind of
// safeguard.
- item_type: ty::Ty<'tcx>,
+ item_type: Ty<'tcx>,
// values for generic type parameters,
// if any.
- parameters: &[ty::Ty<'tcx>])
+ substs: Option<&Substs<'tcx>>)
-> String {
debug!("get_symbol_hash(def_path={:?}, parameters={:?})",
- def_path, parameters);
+ def_path, substs);
let tcx = scx.tcx();
hash_state.input(&encoded_item_type[..]);
// also include any type parameters (for generic items)
- for t in parameters {
- assert!(!t.has_erasable_regions());
- assert!(!t.needs_subst());
- let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
- hash_state.input(&encoded_type[..]);
+ if let Some(substs) = substs {
+ for t in substs.types() {
+ assert!(!t.has_erasable_regions());
+ assert!(!t.needs_subst());
+ let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
+ hash_state.input(&encoded_type[..]);
+ }
}
return format!("h{}", truncated_hash_result(&mut *hash_state));
// and should not matter anyhow.
let instance_ty = scx.tcx().erase_regions(&instance_ty.ty);
- let hash = get_symbol_hash(scx, &def_path, instance_ty, &substs.types);
+ let hash = get_symbol_hash(scx, &def_path, instance_ty, Some(substs));
let mut buffer = SymbolPathBuffer {
names: Vec::with_capacity(def_path.data.len())
}
pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- t: ty::Ty<'tcx>,
+ t: Ty<'tcx>,
prefix: &str)
-> String {
let empty_def_path = DefPath {
data: vec![],
krate: cstore::LOCAL_CRATE,
};
- let hash = get_symbol_hash(scx, &empty_def_path, t, &[]);
+ let hash = get_symbol_hash(scx, &empty_def_path, t, None);
let path = [token::intern_and_get_ident(prefix)];
mangle(path.iter().cloned(), Some(&hash[..]))
}
/// Only symbols that are invisible outside their compilation unit should use a
/// name generated by this function.
pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- t: ty::Ty<'tcx>,
+ t: Ty<'tcx>,
suffix: &str)
-> String {
let path = [token::intern(&t.to_string()).as_str(),
data: vec![],
krate: cstore::LOCAL_CRATE,
};
- let hash = get_symbol_hash(ccx.shared(), &def_path, t, &[]);
+ let hash = get_symbol_hash(ccx.shared(), &def_path, t, None);
mangle(path.iter().cloned(), Some(&hash[..]))
}
-> CustomCoerceUnsized {
let trait_ref = ty::Binder(ty::TraitRef {
def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(),
- substs: Substs::new_trait(scx.tcx(), vec![target_ty], vec![], source_ty)
+ substs: Substs::new_trait(scx.tcx(), source_ty, &[target_ty])
});
match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
debug!("get_fn(def_id={:?}, substs={:?})", def_id, substs);
- assert!(!substs.types.needs_infer());
- assert!(!substs.types.has_escaping_regions());
- assert!(!substs.types.has_param_types());
+ assert!(!substs.needs_infer());
+ assert!(!substs.has_escaping_regions());
+ assert!(!substs.has_param_types());
let substs = tcx.normalize_associated_type(&substs);
let instance = Instance::new(def_id, substs);
use rustc::mir::repr as mir;
use rustc::mir::visit as mir_visit;
use rustc::mir::visit::Visitor as MirVisitor;
+use rustc::mir::repr::Location;
use rustc_const_eval as const_eval;
impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
- fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>) {
+ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
debug!("visiting rvalue {:?}", *rvalue);
match *rvalue {
_ => { /* not interesting */ }
}
- self.super_rvalue(rvalue);
+ self.super_rvalue(rvalue, location);
}
fn visit_lvalue(&mut self,
lvalue: &mir::Lvalue<'tcx>,
- context: mir_visit::LvalueContext) {
+ context: mir_visit::LvalueContext,
+ location: Location) {
debug!("visiting lvalue {:?}", *lvalue);
if let mir_visit::LvalueContext::Drop = context {
self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
}
- self.super_lvalue(lvalue, context);
+ self.super_lvalue(lvalue, context, location);
}
- fn visit_operand(&mut self, operand: &mir::Operand<'tcx>) {
+ fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: Location) {
debug!("visiting operand {:?}", *operand);
let callee = match *operand {
}
}
- self.super_operand(operand);
+ self.super_operand(operand, location);
fn can_result_in_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
// we would not register drop-glues.
fn visit_terminator_kind(&mut self,
block: mir::BasicBlock,
- kind: &mir::TerminatorKind<'tcx>) {
+ kind: &mir::TerminatorKind<'tcx>,
+ location: Location) {
let tcx = self.scx.tcx();
match *kind {
mir::TerminatorKind::Call {
_ => { /* Nothing to do. */ }
}
- self.super_terminator_kind(block, kind);
+ self.super_terminator_kind(block, kind, location);
fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
.drop_trait()
.unwrap();
- let self_type_substs = Substs::new_trait(scx.tcx(), vec![], vec![], ty);
+ let self_type_substs = Substs::new_trait(scx.tcx(), ty, &[]);
let trait_ref = ty::TraitRef {
def_id: drop_trait_def_id,
// The substitutions we have are on the impl, so we grab
// the method type from the impl to substitute into.
let impl_substs = Substs::for_item(tcx, impl_def_id,
- |_, _| ty::ReErased,
+ |_, _| tcx.mk_region(ty::ReErased),
|_, _| tcx.types.err);
let mth = meth::get_impl_method(tcx,
callee_substs,
}
pub fn validate_substs(substs: &Substs) {
- assert!(!substs.types.needs_infer());
+ assert!(!substs.needs_infer());
}
// Function context. Every LLVM function we create will have one of
/// Given the def-id of some item that has no type parameters, make
/// a suitable "empty substs" for it.
pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> {
- Substs::for_item(self.tcx(), item_def_id, |_, _| ty::ReErased, |_, _| {
+ Substs::for_item(self.tcx(), item_def_id,
+ |_, _| self.tcx().mk_region(ty::ReErased),
+ |_, _| {
bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
})
}
use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use syntax_pos::BytePos;
+
+#[derive(Clone, Copy, Debug)]
+pub struct MirDebugScope {
+ pub scope_metadata: DIScope,
+ // Start and end offsets of the file to which this DIScope belongs.
+ // These are used to quickly determine whether some span refers to the same file.
+ pub file_start_pos: BytePos,
+ pub file_end_pos: BytePos,
+}
+
+impl MirDebugScope {
+ pub fn is_valid(&self) -> bool {
+ !self.scope_metadata.is_null()
+ }
+}
+
/// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
/// If debuginfo is disabled, the returned vector is empty.
-pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, DIScope> {
+pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, MirDebugScope> {
let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
- let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes);
+ let null_scope = MirDebugScope {
+ scope_metadata: ptr::null_mut(),
+ file_start_pos: BytePos(0),
+ file_end_pos: BytePos(0)
+ };
+ let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);
let fn_metadata = match fcx.debug_context {
FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
has_variables: &BitVector,
fn_metadata: DISubprogram,
scope: VisibilityScope,
- scopes: &mut IndexVec<VisibilityScope, DIScope>) {
- if !scopes[scope].is_null() {
+ scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
+ if scopes[scope].is_valid() {
return;
}
scopes[parent]
} else {
// The root is the function itself.
- scopes[scope] = fn_metadata;
+ let loc = span_start(ccx, mir.span);
+ scopes[scope] = MirDebugScope {
+ scope_metadata: fn_metadata,
+ file_start_pos: loc.file.start_pos,
+ file_end_pos: loc.file.end_pos,
+ };
return;
};
// However, we don't skip creating a nested scope if
// our parent is the root, because we might want to
// put arguments in the root and not have shadowing.
- if parent_scope != fn_metadata {
+ if parent_scope.scope_metadata != fn_metadata {
scopes[scope] = parent_scope;
return;
}
}
let loc = span_start(ccx, scope_data.span);
- scopes[scope] = unsafe {
let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
+ let scope_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(ccx),
- parent_scope,
+ parent_scope.scope_metadata,
file_metadata,
loc.line as c_uint,
loc.col.to_usize() as c_uint)
};
+ scopes[scope] = MirDebugScope {
+ scope_metadata: scope_metadata,
+ file_start_pos: loc.file.start_pos,
+ file_end_pos: loc.file.end_pos,
+ };
}
use session::Session;
use llvm::{self, ValueRef};
-use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType};
+use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock};
use rustc::hir::def_id::DefId;
use rustc::ty::subst::Substs;
// Add the def-index as the second part
output.push_str(&format!("{:x}", def_id.index.as_usize()));
- let tps = &substs.types;
- if !tps.is_empty() {
+ if substs.types().next().is_some() {
output.push('<');
- for &type_parameter in tps {
+ for type_parameter in substs.types() {
let param_type_id =
type_map.get_unique_type_id_of_type(cx, type_parameter);
let param_type_id =
ptr::null_mut());
}
}
+
+// Creates an "extension" of an existing DIScope into another file.
+pub fn extend_scope_to_file(ccx: &CrateContext,
+ scope_metadata: DIScope,
+ file: &syntax_pos::FileMap)
+ -> DILexicalBlock {
+ let file_metadata = file_metadata(ccx, &file.name, &file.abs_path);
+ unsafe {
+ llvm::LLVMRustDIBuilderCreateLexicalBlockFile(
+ DIB(ccx),
+ scope_metadata,
+ file_metadata)
+ }
+}
\ No newline at end of file
mod create_scope_map;
mod source_loc;
-pub use self::create_scope_map::create_mir_scopes;
+pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
pub use self::source_loc::start_emitting_source_locations;
pub use self::metadata::create_global_var_metadata;
+pub use self::metadata::extend_scope_to_file;
#[allow(non_upper_case_globals)]
const DW_TAG_auto_variable: c_uint = 0x100;
fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
generics: &ty::Generics<'tcx>,
- param_substs: &Substs<'tcx>,
+ substs: &Substs<'tcx>,
file_metadata: DIFile,
name_to_append_suffix_to: &mut String)
-> DIArray
{
- let actual_types = ¶m_substs.types;
-
- if actual_types.is_empty() {
+ if substs.types().next().is_none() {
return create_DIArray(DIB(cx), &[]);
}
name_to_append_suffix_to.push('<');
- for (i, &actual_type) in actual_types.iter().enumerate() {
+ for (i, actual_type) in substs.types().enumerate() {
+ if i != 0 {
+ name_to_append_suffix_to.push_str(",");
+ }
+
let actual_type = cx.tcx().normalize_associated_type(&actual_type);
// Add actual type name to <...> clause of function name
let actual_type_name = compute_debuginfo_type_name(cx,
actual_type,
true);
name_to_append_suffix_to.push_str(&actual_type_name[..]);
-
- if i != actual_types.len() - 1 {
- name_to_append_suffix_to.push_str(",");
- }
}
name_to_append_suffix_to.push('>');
// Again, only create type information if full debuginfo is enabled
let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo {
let names = get_type_parameter_names(cx, generics);
- actual_types.iter().zip(names).map(|(ty, name)| {
- let actual_type = cx.tcx().normalize_associated_type(ty);
+ substs.types().zip(names).map(|(ty, name)| {
+ let actual_type = cx.tcx().normalize_associated_type(&ty);
let actual_type_metadata = type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
let name = CString::new(name.as_str().as_bytes()).unwrap();
unsafe {
let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(),
instance.substs,
&impl_self_ty);
- Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
+
+ // Only "class" methods are generally understood by LLVM,
+ // so avoid methods on other types (e.g. `<*mut T>::null`).
+ match impl_self_ty.sty {
+ ty::TyStruct(..) | ty::TyEnum(..) => {
+ Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
+ }
+ _ => None
+ }
} else {
// For trait method impls we still use the "parallel namespace"
// strategy
fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
substs: &Substs<'tcx>,
output: &mut String) {
- if substs.types.is_empty() {
+ if substs.types().next().is_none() {
return;
}
output.push('<');
- for &type_parameter in &substs.types {
+ for type_parameter in substs.types() {
push_debuginfo_type_name(cx, type_parameter, true, output);
output.push_str(", ");
}
let trait_ref = ty::Binder(ty::TraitRef {
def_id: tcx.lang_items.drop_trait().unwrap(),
- substs: Substs::new_trait(tcx, vec![], vec![], t)
+ substs: Substs::new_trait(tcx, t, &[])
});
let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) {
traits::VtableImpl(data) => data,
Call(bcx, llfn, &[], call_debug_location)
}
(_, "size_of") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
C_uint(ccx, machine::llsize_of_alloc(ccx, lltp_ty))
}
(_, "size_of_val") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
if !type_is_sized(tcx, tp_ty) {
let (llsize, _) =
glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
}
}
(_, "min_align_of") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
C_uint(ccx, type_of::align_of(ccx, tp_ty))
}
(_, "min_align_of_val") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
if !type_is_sized(tcx, tp_ty) {
let (_, llalign) =
glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
}
}
(_, "pref_align_of") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
let lltp_ty = type_of::type_of(ccx, tp_ty);
C_uint(ccx, machine::llalign_of_pref(ccx, lltp_ty))
}
(_, "drop_in_place") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
let is_sized = type_is_sized(tcx, tp_ty);
let ptr = if is_sized {
llargs[0]
C_nil(ccx)
}
(_, "type_name") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
let ty_name = token::intern_and_get_ident(&tp_ty.to_string());
C_str_slice(ccx, ty_name)
}
(_, "type_id") => {
- C_u64(ccx, ccx.tcx().type_id_hash(substs.types[0]))
+ C_u64(ccx, ccx.tcx().type_id_hash(substs.type_at(0)))
}
(_, "init") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
if !type_is_zero_size(ccx, tp_ty) {
// Just zero out the stack slot. (See comment on base::memzero for explanation)
init_zero_mem(bcx, llresult, tp_ty);
C_nil(ccx)
}
(_, "needs_drop") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
C_bool(ccx, bcx.fcx.type_needs_drop(tp_ty))
}
copy_intrinsic(bcx,
false,
false,
- substs.types[0],
+ substs.type_at(0),
llargs[1],
llargs[0],
llargs[2],
copy_intrinsic(bcx,
true,
false,
- substs.types[0],
+ substs.type_at(0),
llargs[1],
llargs[0],
llargs[2],
(_, "write_bytes") => {
memset_intrinsic(bcx,
false,
- substs.types[0],
+ substs.type_at(0),
llargs[0],
llargs[1],
llargs[2],
copy_intrinsic(bcx,
false,
true,
- substs.types[0],
+ substs.type_at(0),
llargs[0],
llargs[1],
llargs[2],
copy_intrinsic(bcx,
true,
true,
- substs.types[0],
+ substs.type_at(0),
llargs[0],
llargs[1],
llargs[2],
(_, "volatile_set_memory") => {
memset_intrinsic(bcx,
true,
- substs.types[0],
+ substs.type_at(0),
llargs[0],
llargs[1],
llargs[2],
call_debug_location)
}
(_, "volatile_load") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
let mut ptr = llargs[0];
if let Some(ty) = fn_ty.ret.cast {
ptr = PointerCast(bcx, ptr, ty.ptr_to());
to_immediate(bcx, load, tp_ty)
},
(_, "volatile_store") => {
- let tp_ty = substs.types[0];
+ let tp_ty = substs.type_at(0);
if type_is_fat_ptr(bcx.tcx(), tp_ty) {
VolatileStore(bcx, llargs[1], get_dataptr(bcx, llargs[0]));
VolatileStore(bcx, llargs[2], get_meta(bcx, llargs[0]));
},
(_, "discriminant_value") => {
- let val_ty = substs.types[0];
+ let val_ty = substs.type_at(0);
match val_ty.sty {
ty::TyEnum(..) => {
let repr = adt::represent_type(ccx, val_ty);
match split[1] {
"cxchg" | "cxchgweak" => {
- let sty = &substs.types[0].sty;
+ let sty = &substs.type_at(0).sty;
if int_type_width_signed(sty, ccx).is_some() {
let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False };
let val = AtomicCmpXchg(bcx, llargs[0], llargs[1], llargs[2],
}
"load" => {
- let sty = &substs.types[0].sty;
+ let sty = &substs.type_at(0).sty;
if int_type_width_signed(sty, ccx).is_some() {
AtomicLoad(bcx, llargs[0], order)
} else {
}
"store" => {
- let sty = &substs.types[0].sty;
+ let sty = &substs.type_at(0).sty;
if int_type_width_signed(sty, ccx).is_some() {
AtomicStore(bcx, llargs[1], llargs[0], order);
} else {
_ => ccx.sess().fatal("unknown atomic operation")
};
- let sty = &substs.types[0].sty;
+ let sty = &substs.type_at(0).sty;
if int_type_width_signed(sty, ccx).is_some() {
AtomicRMW(bcx, atom_op, llargs[0], llargs[1], order)
} else {
// the method may have some early-bound lifetimes, add
// regions for those
let method_substs = Substs::for_item(tcx, trait_method_def_id,
- |_, _| ty::ReErased,
+ |_, _| tcx.mk_region(ty::ReErased),
|_, _| tcx.types.err);
// The substitutions we have are on the impl, so we grab
name: Name)
-> ImplMethod<'tcx>
{
- assert!(!substs.types.needs_infer());
+ assert!(!substs.needs_infer());
let trait_def_id = tcx.trait_id_of_impl(impl_def_id).unwrap();
let trait_def = tcx.lookup_trait_def(trait_def_id);
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::mir::repr as mir;
use rustc::mir::repr::TerminatorKind;
+use rustc::mir::repr::Location;
use rustc::mir::visit::{Visitor, LvalueContext};
use rustc::mir::traversal;
use common::{self, Block, BlockAndBuilder};
common::type_is_fat_ptr(bcx.tcx(), ty));
} else if common::type_is_imm_pair(bcx.ccx(), ty) {
// We allow pairs and uses of any of their 2 fields.
+ } else if !analyzer.seen_assigned.contains(index) {
+ // No assignment has been seen, which means that
+ // either the local has been marked as lvalue
+ // already, or there is no possible initialization
+ // for the local, making any reads invalid.
+ // This is useful in weeding out dead temps.
} else {
// These sorts of types require an alloca. Note that
// type_is_immediate() may *still* be true, particularly
fn visit_assign(&mut self,
block: mir::BasicBlock,
lvalue: &mir::Lvalue<'tcx>,
- rvalue: &mir::Rvalue<'tcx>) {
+ rvalue: &mir::Rvalue<'tcx>,
+ location: Location) {
debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue);
if let Some(index) = self.mir.local_index(lvalue) {
self.mark_as_lvalue(index);
}
} else {
- self.visit_lvalue(lvalue, LvalueContext::Store);
+ self.visit_lvalue(lvalue, LvalueContext::Store, location);
}
- self.visit_rvalue(rvalue);
+ self.visit_rvalue(rvalue, location);
}
fn visit_terminator_kind(&mut self,
block: mir::BasicBlock,
- kind: &mir::TerminatorKind<'tcx>) {
+ kind: &mir::TerminatorKind<'tcx>,
+ location: Location) {
match *kind {
mir::TerminatorKind::Call {
func: mir::Operand::Constant(mir::Constant {
// is not guaranteed to be statically dominated by the
// definition of x, so x must always be in an alloca.
if let mir::Operand::Consume(ref lvalue) = args[0] {
- self.visit_lvalue(lvalue, LvalueContext::Drop);
+ self.visit_lvalue(lvalue, LvalueContext::Drop, location);
}
}
_ => {}
}
- self.super_terminator_kind(block, kind);
+ self.super_terminator_kind(block, kind, location);
}
fn visit_lvalue(&mut self,
lvalue: &mir::Lvalue<'tcx>,
- context: LvalueContext) {
+ context: LvalueContext,
+ location: Location) {
debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context);
// Allow uses of projections of immediate pair fields.
// A deref projection only reads the pointer, never needs the lvalue.
if let mir::Lvalue::Projection(ref proj) = *lvalue {
if let mir::ProjectionElem::Deref = proj.elem {
- return self.visit_lvalue(&proj.base, LvalueContext::Consume);
+ return self.visit_lvalue(&proj.base, LvalueContext::Consume, location);
}
}
- self.super_lvalue(lvalue, context);
+ self.super_lvalue(lvalue, context, location);
}
}
use libc::c_uint;
use llvm::{self, ValueRef};
-use llvm::debuginfo::DIScope;
use rustc::ty;
use rustc::mir::repr as mir;
use rustc::mir::tcx::LvalueTy;
use session::config::FullDebugInfo;
use base;
use common::{self, Block, BlockAndBuilder, CrateContext, FunctionContext, C_null};
-use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind};
+use debuginfo::{self, declare_local, DebugLoc, VariableAccess, VariableKind, FunctionDebugContext};
use machine;
use type_of;
-use syntax_pos::DUMMY_SP;
+use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos};
use syntax::parse::token::keywords;
use std::ops::Deref;
locals: IndexVec<mir::Local, LocalRef<'tcx>>,
/// Debug information for MIR scopes.
- scopes: IndexVec<mir::VisibilityScope, DIScope>
+ scopes: IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
}
impl<'blk, 'tcx> MirContext<'blk, 'tcx> {
- pub fn debug_loc(&self, source_info: mir::SourceInfo) -> DebugLoc {
- DebugLoc::ScopeAt(self.scopes[source_info.scope], source_info.span)
+ pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> DebugLoc {
+ // Bail out if debug info emission is not enabled.
+ match self.fcx.debug_context {
+ FunctionDebugContext::DebugInfoDisabled |
+ FunctionDebugContext::FunctionWithoutDebugInfo => {
+ // Can't return DebugLoc::None here because intrinsic::trans_intrinsic_call()
+ // relies on debug location to obtain span of the call site.
+ return DebugLoc::ScopeAt(self.scopes[source_info.scope].scope_metadata,
+ source_info.span);
+ }
+ FunctionDebugContext::RegularContext(_) =>{}
+ }
+
+ // In order to have a good line stepping behavior in debugger, we overwrite debug
+ // locations of macro expansions with that of the outermost expansion site
+ // (unless the crate is being compiled with `-Z debug-macros`).
+ if source_info.span.expn_id == NO_EXPANSION ||
+ source_info.span.expn_id == COMMAND_LINE_EXPN ||
+ self.fcx.ccx.sess().opts.debugging_opts.debug_macros {
+
+ let scope_metadata = self.scope_metadata_for_loc(source_info.scope,
+ source_info.span.lo);
+ DebugLoc::ScopeAt(scope_metadata, source_info.span)
+ } else {
+ let cm = self.fcx.ccx.sess().codemap();
+ // Walk up the macro expansion chain until we reach a non-expanded span.
+ let mut span = source_info.span;
+ while span.expn_id != NO_EXPANSION && span.expn_id != COMMAND_LINE_EXPN {
+ if let Some(callsite_span) = cm.with_expn_info(span.expn_id,
+ |ei| ei.map(|ei| ei.call_site.clone())) {
+ span = callsite_span;
+ } else {
+ break;
+ }
+ }
+ let scope_metadata = self.scope_metadata_for_loc(source_info.scope, span.lo);
+ // Use span of the outermost call site, while keeping the original lexical scope
+ DebugLoc::ScopeAt(scope_metadata, span)
+ }
+ }
+
+ // DILocations inherit source file name from the parent DIScope. Due to macro expansions
+ // it may so happen that the current span belongs to a different file than the DIScope
+ // corresponding to span's containing visibility scope. If so, we need to create a DIScope
+ // "extension" into that file.
+ fn scope_metadata_for_loc(&self, scope_id: mir::VisibilityScope, pos: BytePos)
+ -> llvm::debuginfo::DIScope {
+ let scope_metadata = self.scopes[scope_id].scope_metadata;
+ if pos < self.scopes[scope_id].file_start_pos ||
+ pos >= self.scopes[scope_id].file_end_pos {
+ let cm = self.fcx.ccx.sess().codemap();
+ debuginfo::extend_scope_to_file(self.fcx.ccx,
+ scope_metadata,
+ &cm.lookup_char_pos(pos).file)
+ } else {
+ scope_metadata
+ }
}
}
analyze::cleanup_kinds(bcx, &mir))
});
+ // Allocate a `Block` for every basic block
+ let block_bcxs: IndexVec<mir::BasicBlock, Block<'blk,'tcx>> =
+ mir.basic_blocks().indices().map(|bb| {
+ if bb == mir::START_BLOCK {
+ fcx.new_block("start")
+ } else {
+ fcx.new_block(&format!("{:?}", bb))
+ }
+ }).collect();
+
// Compute debuginfo scopes from MIR scopes.
let scopes = debuginfo::create_mir_scopes(fcx);
+ let mut mircx = MirContext {
+ mir: mir.clone(),
+ fcx: fcx,
+ llpersonalityslot: None,
+ blocks: block_bcxs,
+ unreachable_block: None,
+ cleanup_kinds: cleanup_kinds,
+ landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
+ scopes: scopes,
+ locals: IndexVec::new(),
+ };
+
// Allocate variable and temp allocas
- let locals = {
- let args = arg_local_refs(&bcx, &mir, &scopes, &lvalue_locals);
+ mircx.locals = {
+ let args = arg_local_refs(&bcx, &mir, &mircx.scopes, &lvalue_locals);
let vars = mir.var_decls.iter().enumerate().map(|(i, decl)| {
let ty = bcx.monomorphize(&decl.ty);
- let scope = scopes[decl.source_info.scope];
- let dbg = !scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo;
+ let debug_scope = mircx.scopes[decl.source_info.scope];
+ let dbg = debug_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo;
let local = mir.local_index(&mir::Lvalue::Var(mir::Var::new(i))).unwrap();
if !lvalue_locals.contains(local.index()) && !dbg {
let lvalue = LvalueRef::alloca(&bcx, ty, &decl.name.as_str());
if dbg {
- bcx.with_block(|bcx| {
- declare_local(bcx, decl.name, ty, scope,
- VariableAccess::DirectVariable { alloca: lvalue.llval },
- VariableKind::LocalVariable, decl.source_info.span);
- });
+ let dbg_loc = mircx.debug_loc(decl.source_info);
+ if let DebugLoc::ScopeAt(scope, span) = dbg_loc {
+ bcx.with_block(|bcx| {
+ declare_local(bcx, decl.name, ty, scope,
+ VariableAccess::DirectVariable { alloca: lvalue.llval },
+ VariableKind::LocalVariable, span);
+ });
+ } else {
+ panic!("Unexpected");
+ }
}
LocalRef::Lvalue(lvalue)
});
})).collect()
};
- // Allocate a `Block` for every basic block
- let block_bcxs: IndexVec<mir::BasicBlock, Block<'blk,'tcx>> =
- mir.basic_blocks().indices().map(|bb| {
- if bb == mir::START_BLOCK {
- fcx.new_block("start")
- } else {
- fcx.new_block(&format!("{:?}", bb))
- }
- }).collect();
-
// Branch to the START block
- let start_bcx = block_bcxs[mir::START_BLOCK];
+ let start_bcx = mircx.blocks[mir::START_BLOCK];
bcx.br(start_bcx.llbb);
// Up until here, IR instructions for this function have explicitly not been annotated with
// emitting should be enabled.
debuginfo::start_emitting_source_locations(fcx);
- let mut mircx = MirContext {
- mir: mir.clone(),
- fcx: fcx,
- llpersonalityslot: None,
- blocks: block_bcxs,
- unreachable_block: None,
- cleanup_kinds: cleanup_kinds,
- landing_pads: IndexVec::from_elem(None, mir.basic_blocks()),
- locals: locals,
- scopes: scopes
- };
-
let mut visited = BitVector::new(mir.basic_blocks().len());
let mut rpo = traversal::reverse_postorder(&mir);
/// indirect.
fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
mir: &mir::Mir<'tcx>,
- scopes: &IndexVec<mir::VisibilityScope, DIScope>,
+ scopes: &IndexVec<mir::VisibilityScope, debuginfo::MirDebugScope>,
lvalue_locals: &BitVector)
-> Vec<LocalRef<'tcx>> {
let fcx = bcx.fcx();
// Get the argument scope, if it exists and if we need it.
let arg_scope = scopes[mir::ARGUMENT_VISIBILITY_SCOPE];
- let arg_scope = if !arg_scope.is_null() && bcx.sess().opts.debuginfo == FullDebugInfo {
- Some(arg_scope)
+ let arg_scope = if arg_scope.is_valid() && bcx.sess().opts.debuginfo == FullDebugInfo {
+ Some(arg_scope.scope_metadata)
} else {
None
};
impl<'tcx> Instance<'tcx> {
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Instance<'tcx> {
- assert!(substs.regions.iter().all(|&r| r == ty::ReErased));
+ assert!(substs.regions().all(|&r| r == ty::ReErased));
Instance { def: def_id, substs: substs }
}
pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
TransItem::DropGlue(..) => unreachable!(),
// Is there any benefit to using ExternalLinkage?:
TransItem::Fn(ref instance) => {
- if instance.substs.types.is_empty() {
+ if instance.substs.types().next().is_none() {
// This is a non-generic functions, we always
// make it visible externally on the chance that
// it might be used in another codegen unit.
// DefId, we use the location of the impl after all.
if tcx.trait_of_item(instance.def).is_some() {
- let self_ty = instance.substs.types[0];
+ let self_ty = instance.substs.type_at(0);
// This is an implementation of a trait method.
return characteristic_def_id_of_type(self_ty).or(Some(instance.def));
}
instance: Instance<'tcx>,
linkage: llvm::Linkage,
symbol_name: &str) {
- assert!(!instance.substs.types.needs_infer() &&
- !instance.substs.types.has_param_types());
+ assert!(!instance.substs.needs_infer() &&
+ !instance.substs.has_param_types());
let item_ty = ccx.tcx().lookup_item_type(instance.def).ty;
let item_ty = ccx.tcx().erase_regions(&item_ty);
pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
match *self {
TransItem::Fn(ref instance) => {
- !instance.substs.types.is_empty() || {
+ instance.substs.types().next().is_some() || {
let attributes = tcx.get_attrs(instance.def);
attr::requests_inline(&attributes[..])
}
pub fn is_instantiated_only_on_demand(&self) -> bool {
match *self {
- TransItem::Fn(ref instance) => !instance.def.is_local() ||
- !instance.substs.types.is_empty(),
+ TransItem::Fn(ref instance) => {
+ !instance.def.is_local() || instance.substs.types().next().is_some()
+ }
TransItem::DropGlue(..) => true,
TransItem::Static(..) => false,
}
pub fn is_generic_fn(&self) -> bool {
match *self {
- TransItem::Fn(ref instance) => !instance.substs.types.is_empty(),
+ TransItem::Fn(ref instance) => {
+ instance.substs.types().next().is_some()
+ }
TransItem::DropGlue(..) |
TransItem::Static(..) => false,
}
/// Same as `unique_type_name()` but with the result pushed onto the given
/// `output` parameter.
pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- t: ty::Ty<'tcx>,
+ t: Ty<'tcx>,
output: &mut String) {
match t.sty {
ty::TyBool => output.push_str("bool"),
ty::TyStruct(adt_def, substs) |
ty::TyEnum(adt_def, substs) => {
push_item_name(tcx, adt_def.did, output);
- push_type_params(tcx, &substs.types, &[], output);
+ push_type_params(tcx, substs, &[], output);
},
ty::TyTuple(component_types) => {
output.push('(');
ty::TyTrait(ref trait_data) => {
push_item_name(tcx, trait_data.principal.def_id(), output);
push_type_params(tcx,
- &trait_data.principal.skip_binder().substs.types,
+ trait_data.principal.skip_binder().substs,
&trait_data.projection_bounds,
output);
},
output.push_str("{");
output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
output.push_str("}");
- push_type_params(tcx, &closure_substs.func_substs.types, &[], output);
+ push_type_params(tcx, closure_substs.func_substs, &[], output);
}
ty::TyError |
ty::TyInfer(_) |
}
fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- types: &[Ty<'tcx>],
+ substs: &Substs<'tcx>,
projections: &[ty::PolyExistentialProjection<'tcx>],
output: &mut String) {
- if types.is_empty() && projections.is_empty() {
+ if substs.types().next().is_none() && projections.is_empty() {
return;
}
output.push('<');
- for &type_parameter in types {
+ for type_parameter in substs.types() {
push_unique_type_name(tcx, type_parameter, output);
output.push_str(", ");
}
instance: Instance<'tcx>,
output: &mut String) {
push_item_name(tcx, instance.def, output);
- push_type_params(tcx, &instance.substs.types, &[], output);
+ push_type_params(tcx, instance.substs, &[], output);
}
pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String {
}
pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty: ty::Ty<'tcx>)
+ ty: Ty<'tcx>)
-> String {
let mut output = String::new();
push_unique_type_name(tcx, ty, &mut output);
use machine;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::subst::Substs;
use type_::Type;
// avoids creating more than one copy of the enum when one
// of the enum's variants refers to the enum itself.
let repr = adt::represent_type(cx, t);
- let name = llvm_type_name(cx, def.did, &substs.types);
+ let name = llvm_type_name(cx, def.did, substs);
adt::incomplete_type_of(cx, &repr, &name[..])
}
ty::TyClosure(..) => {
// in *after* placing it into the type cache. This prevents
// infinite recursion with recursive struct types.
let repr = adt::represent_type(cx, t);
- let name = llvm_type_name(cx, def.did, &substs.types);
+ let name = llvm_type_name(cx, def.did, substs);
adt::incomplete_type_of(cx, &repr, &name[..])
}
}
fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
did: DefId,
- tps: &[Ty<'tcx>])
+ substs: &Substs<'tcx>)
-> String {
let base = cx.tcx().item_path_str(did);
- let strings: Vec<String> = tps.iter().map(|t| t.to_string()).collect();
+ let strings: Vec<String> = substs.types().map(|t| t.to_string()).collect();
let tstr = if strings.is_empty() {
base
} else {
/// This type must not appear anywhere in other converted types.
const TRAIT_OBJECT_DUMMY_SELF: ty::TypeVariants<'static> = ty::TyInfer(ty::FreshTy(0));
-pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime)
- -> ty::Region {
+pub fn ast_region_to_region<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ lifetime: &hir::Lifetime)
+ -> &'tcx ty::Region {
let r = match tcx.named_region_map.defs.get(&lifetime.id) {
None => {
// should have been recorded by the `resolve_lifetime` pass
lifetime.id,
r);
- r
+ tcx.mk_region(r)
}
fn report_elision_failure(
pub fn opt_ast_region_to_region(&self,
rscope: &RegionScope,
default_span: Span,
- opt_lifetime: &Option<hir::Lifetime>) -> ty::Region
+ opt_lifetime: &Option<hir::Lifetime>) -> &'tcx ty::Region
{
let r = match *opt_lifetime {
Some(ref lifetime) => {
ast_region_to_region(self.tcx(), lifetime)
}
- None => match rscope.anon_regions(default_span, 1) {
+ None => self.tcx().mk_region(match rscope.anon_regions(default_span, 1) {
Ok(rs) => rs[0],
Err(params) => {
let ampersand_span = Span { hi: default_span.lo, ..default_span};
err.emit();
ty::ReStatic
}
- }
+ })
};
debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}",
.emit();
return Substs::for_item(tcx, def_id, |_, _| {
- ty::ReStatic
+ tcx.mk_region(ty::ReStatic)
}, |_, _| {
tcx.types.err
});
let expected_num_region_params = decl_generics.regions.len();
let supplied_num_region_params = lifetimes.len();
let regions = if expected_num_region_params == supplied_num_region_params {
- lifetimes.iter().map(|l| ast_region_to_region(tcx, l)).collect()
+ lifetimes.iter().map(|l| *ast_region_to_region(tcx, l)).collect()
} else {
let anon_regions =
rscope.anon_regions(span, expected_num_region_params);
let mut output_assoc_binding = None;
let substs = Substs::for_item(tcx, def_id, |def, _| {
- regions[def.index as usize]
+ let i = def.index as usize - self_ty.is_some() as usize;
+ tcx.mk_region(regions[i])
}, |def, substs| {
let i = def.index as usize;
return ty;
}
- let i = i - self_ty.is_some() as usize;
+ let i = i - self_ty.is_some() as usize - decl_generics.regions.len();
if num_types_provided.map_or(false, |n| i < n) {
// A provided type parameter.
match *parameters {
}
if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::<usize>() == 1 {
- Ok(possible_implied_output_region.unwrap())
+ Ok(*possible_implied_output_region.unwrap())
} else {
Err(Some(lifetimes_for_params))
}
// FIXME(#12938): This is a hack until we have full support for DST.
if Some(did) == self.tcx().lang_items.owned_box() {
- assert_eq!(substs.types.len(), 1);
- return self.tcx().mk_box(substs.types[0]);
+ assert_eq!(substs.types().count(), 1);
+ return self.tcx().mk_box(substs.type_at(0));
}
decl_ty.subst(self.tcx(), substs)
let region_bound = match region_bound {
Some(r) => r,
None => {
- match rscope.object_lifetime_default(span) {
+ tcx.mk_region(match rscope.object_lifetime_default(span) {
Some(r) => r,
None => {
span_err!(self.tcx().sess, span, E0228,
from context; please supply an explicit bound");
ty::ReStatic
}
- }
+ })
}
};
rscope,
ty::ObjectLifetimeDefault::Specific(r));
let t = self.ast_ty_to_ty(rscope1, &mt.ty);
- tcx.mk_ref(tcx.mk_region(r), ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
+ tcx.mk_ref(r, ty::TypeAndMut {ty: t, mutbl: mt.mutbl})
}
hir::TyNever => {
tcx.types.never
sig: &hir::MethodSig,
untransformed_self_ty: Ty<'tcx>,
anon_scope: Option<AnonTypeScope>)
- -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) {
+ -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) {
self.ty_of_method_or_bare_fn(sig.unsafety,
sig.abi,
Some(untransformed_self_ty),
decl: &hir::FnDecl,
arg_anon_scope: Option<AnonTypeScope>,
ret_anon_scope: Option<AnonTypeScope>)
- -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory)
+ -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>)
{
debug!("ty_of_method_or_bare_fn");
// reference) in the arguments, then any anonymous regions in the output
// have that lifetime.
let implied_output_region = match explicit_self_category {
- ty::ExplicitSelfCategory::ByReference(region, _) => Ok(region),
+ ty::ExplicitSelfCategory::ByReference(region, _) => Ok(*region),
_ => self.find_implied_output_region(&arg_tys, arg_pats)
};
rscope: &RegionScope,
untransformed_self_ty: Ty<'tcx>,
explicit_self: &hir::ExplicitSelf)
- -> (Ty<'tcx>, ty::ExplicitSelfCategory)
+ -> (Ty<'tcx>, ty::ExplicitSelfCategory<'tcx>)
{
return match explicit_self.node {
SelfKind::Value(..) => {
rscope,
explicit_self.span,
lifetime);
- (self.tcx().mk_ref(
- self.tcx().mk_region(region),
+ (self.tcx().mk_ref(region,
ty::TypeAndMut {
ty: untransformed_self_ty,
mutbl: mutability
ty::ExplicitSelfCategory::ByValue
} else {
match explicit_type.sty {
- ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(*r, mt.mutbl),
+ ty::TyRef(r, mt) => ty::ExplicitSelfCategory::ByReference(r, mt.mutbl),
ty::TyBox(_) => ty::ExplicitSelfCategory::ByBox,
_ => ty::ExplicitSelfCategory::ByValue,
}
explicit_region_bounds: &[&hir::Lifetime],
principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>,
builtin_bounds: ty::BuiltinBounds)
- -> Option<ty::Region> // if None, use the default
+ -> Option<&'tcx ty::Region> // if None, use the default
{
let tcx = self.tcx();
if let Err(ErrorReported) =
self.ensure_super_predicates(span, principal_trait_ref.def_id()) {
- return Some(ty::ReStatic);
+ return Some(tcx.mk_region(ty::ReStatic));
}
// No explicit region bound specified. Therefore, examine trait
// If any of the derived region bounds are 'static, that is always
// the best choice.
- if derived_region_bounds.iter().any(|r| ty::ReStatic == *r) {
- return Some(ty::ReStatic);
+ if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) {
+ return Some(tcx.mk_region(ty::ReStatic));
}
// Determine whether there is exactly one unique region in the set
// and return from functions in multiple places.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Bounds<'tcx> {
- pub region_bounds: Vec<ty::Region>,
+ pub region_bounds: Vec<&'tcx ty::Region>,
pub builtin_bounds: ty::BuiltinBounds,
pub trait_bounds: Vec<ty::PolyTraitRef<'tcx>>,
pub projection_bounds: Vec<ty::PolyProjectionPredicate<'tcx>>,
for ®ion_bound in &self.region_bounds {
// account for the binder being introduced below; no need to shift `param_ty`
// because, at present at least, it can only refer to early-bound regions
- let region_bound = ty::fold::shift_region(region_bound, 1);
+ let region_bound = tcx.mk_region(ty::fold::shift_region(*region_bound, 1));
vec.push(ty::Binder(ty::OutlivesPredicate(param_ty, region_bound)).to_predicate());
}
// and T is the expected type.
let region_var = self.next_region_var(infer::PatternRegion(pat.span));
let mt = ty::TypeAndMut { ty: expected, mutbl: mutbl };
- let region_ty = tcx.mk_ref(tcx.mk_region(region_var), mt);
+ let region_ty = tcx.mk_ref(region_var, mt);
// `x` is assigned a value of type `&M T`, hence `&M T <: typeof(x)` is
// required. However, we use equality, which is stronger. See (*) for
let inner_ty = self.next_ty_var();
let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
let region = self.next_region_var(infer::PatternRegion(pat.span));
- let rptr_ty = tcx.mk_ref(tcx.mk_region(region), mt);
+ let rptr_ty = tcx.mk_ref(region, mt);
self.demand_eqtype(pat.span, expected, rptr_ty);
(rptr_ty, inner_ty)
}
Some(f) => f,
None => return None
},
- substs: Substs::new_trait(tcx, vec![], vec![], self.cur_ty)
+ substs: Substs::new_trait(tcx, self.cur_ty, &[])
};
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
return None;
}
- let arg_param_ty = trait_ref.substs().types[1];
+ let arg_param_ty = trait_ref.substs().type_at(1);
let arg_param_ty = self.resolve_type_vars_if_possible(&arg_param_ty);
debug!("deduce_sig_from_projection: arg_param_ty {:?}", arg_param_ty);
if r_borrow_var.is_none() { // create var lazilly, at most once
let coercion = Coercion(span);
let r = self.next_region_var(coercion);
- r_borrow_var = Some(self.tcx.mk_region(r)); // [4] above
+ r_borrow_var = Some(r); // [4] above
}
r_borrow_var.unwrap()
};
let coercion = Coercion(self.origin.span());
let r_borrow = self.next_region_var(coercion);
- let region = self.tcx.mk_region(r_borrow);
- (mt_a.ty, Some(AutoPtr(region, mt_b.mutbl)))
+ (mt_a.ty, Some(AutoPtr(r_borrow, mt_b.mutbl)))
}
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) => {
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
coerce_unsized_did,
0,
source,
- vec![target]));
+ &[target]));
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
impl_m_span,
impl_m_body_id,
&impl_sig);
- let impl_args = impl_sig.inputs.clone();
let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
unsafety: impl_m.fty.unsafety,
abi: impl_m.fty.abi,
- sig: ty::Binder(impl_sig)
+ sig: ty::Binder(impl_sig.clone())
}));
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
impl_m_span,
impl_m_body_id,
&trait_sig);
- let trait_args = trait_sig.inputs.clone();
let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
unsafety: trait_m.fty.unsafety,
abi: trait_m.fty.abi,
- sig: ty::Binder(trait_sig)
+ sig: ty::Binder(trait_sig.clone())
}));
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
impl_fty,
trait_fty);
- let impl_m_iter = match tcx.map.expect_impl_item(impl_m_node_id).node {
- ImplItemKind::Method(ref impl_m_sig, _) => impl_m_sig.decl.inputs.iter(),
- _ => bug!("{:?} is not a method", impl_m)
- };
-
- let (impl_err_span, trait_err_span) = match terr {
- TypeError::Mutability => {
- if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
- let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
- trait_m_sig.decl.inputs.iter(),
- _ => bug!("{:?} is not a MethodTraitItem", trait_m)
- };
-
- impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
- match (&impl_arg.ty.node, &trait_arg.ty.node) {
- (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
- (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
- impl_mt.mutbl != trait_mt.mutbl,
- _ => false
- }
- }).map(|(ref impl_arg, ref trait_arg)| {
- match (impl_arg.to_self(), trait_arg.to_self()) {
- (Some(impl_self), Some(trait_self)) =>
- (impl_self.span, Some(trait_self.span)),
- (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
- _ => bug!("impl and trait fns have different first args, \
- impl: {:?}, trait: {:?}", impl_arg, trait_arg)
- }
- }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
- } else {
- (origin.span(), tcx.map.span_if_local(trait_m.def_id))
- }
- }
- TypeError::Sorts(ExpectedFound { expected, found }) => {
- if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
- let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
- trait_m_sig.decl.inputs.iter(),
- _ => bug!("{:?} is not a MethodTraitItem", trait_m)
- };
- let impl_iter = impl_args.iter();
- let trait_iter = trait_args.iter();
- let arg_idx = impl_iter.zip(trait_iter)
- .position(|(impl_arg_ty, trait_arg_ty)| {
- *impl_arg_ty == found && *trait_arg_ty == expected
- }).unwrap();
- impl_m_iter.zip(trait_m_iter)
- .nth(arg_idx)
- .map(|(impl_arg, trait_arg)|
- (impl_arg.ty.span, Some(trait_arg.ty.span)))
- .unwrap_or(
- (origin.span(), tcx.map.span_if_local(trait_m.def_id)))
- } else {
- (origin.span(), tcx.map.span_if_local(trait_m.def_id))
- }
- }
- _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
- };
+ let (impl_err_span, trait_err_span) =
+ extract_spans_for_error_reporting(&infcx, &terr, origin, impl_m,
+ impl_sig, trait_m, trait_sig);
let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
return true;
}
+
+ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
+ terr: &TypeError,
+ origin: TypeOrigin,
+ impl_m: &ty::Method,
+ impl_sig: ty::FnSig<'tcx>,
+ trait_m: &ty::Method,
+ trait_sig: ty::FnSig<'tcx>)
+ -> (Span, Option<Span>) {
+ let tcx = infcx.tcx;
+ let impl_m_node_id = tcx.map.as_local_node_id(impl_m.def_id).unwrap();
+ let (impl_m_output, impl_m_iter) = match tcx.map.expect_impl_item(impl_m_node_id).node {
+ ImplItemKind::Method(ref impl_m_sig, _) =>
+ (&impl_m_sig.decl.output, impl_m_sig.decl.inputs.iter()),
+ _ => bug!("{:?} is not a method", impl_m)
+ };
+
+ match *terr {
+ TypeError::Mutability => {
+ if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+ let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
+ TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
+ trait_m_sig.decl.inputs.iter(),
+ _ => bug!("{:?} is not a MethodTraitItem", trait_m)
+ };
+
+ impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
+ match (&impl_arg.ty.node, &trait_arg.ty.node) {
+ (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
+ (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) =>
+ impl_mt.mutbl != trait_mt.mutbl,
+ _ => false
+ }
+ }).map(|(ref impl_arg, ref trait_arg)| {
+ match (impl_arg.to_self(), trait_arg.to_self()) {
+ (Some(impl_self), Some(trait_self)) =>
+ (impl_self.span, Some(trait_self.span)),
+ (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
+ _ => bug!("impl and trait fns have different first args, \
+ impl: {:?}, trait: {:?}", impl_arg, trait_arg)
+ }
+ }).unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
+ } else {
+ (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+ }
+ }
+ TypeError::Sorts(ExpectedFound { .. }) => {
+ if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
+ let (trait_m_output, trait_m_iter) =
+ match tcx.map.expect_trait_item(trait_m_node_id).node {
+ TraitItem_::MethodTraitItem(ref trait_m_sig, _) =>
+ (&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter()),
+ _ => bug!("{:?} is not a MethodTraitItem", trait_m)
+ };
+
+ let impl_iter = impl_sig.inputs.iter();
+ let trait_iter = trait_sig.inputs.iter();
+ impl_iter.zip(trait_iter).zip(impl_m_iter).zip(trait_m_iter)
+ .filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
+ match infcx.sub_types(true, origin, trait_arg_ty, impl_arg_ty) {
+ Ok(_) => None,
+ Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span)))
+ }
+ })
+ .next()
+ .unwrap_or_else(|| {
+ if infcx.sub_types(false, origin, impl_sig.output,
+ trait_sig.output).is_err() {
+ (impl_m_output.span(), Some(trait_m_output.span()))
+ } else {
+ (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+ }
+ })
+ } else {
+ (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+ }
+ }
+ _ => (origin.span(), tcx.map.span_if_local(trait_m.def_id))
+ }
+ }
}
pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
ty);
cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
- ty, ty::ReScope(cx.parent_scope));
+ ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
return Ok(());
}
ty::TyStruct(def, substs) if def.is_phantom_data() => {
// PhantomData<T> - behaves identically to T
- let ity = substs.types[0];
+ let ity = substs.type_at(0);
iterate_over_potentially_unsafe_regions_in_type(
cx, context, ity, depth+1)
}
let i_ty = tcx.lookup_item_type(def_id);
let substs = Substs::for_item(tcx, def_id,
- |_, _| ty::ReErased,
+ |_, _| tcx.mk_region(ty::ReErased),
|def, _| tcx.mk_param_from_def(def));
let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
}));
let i_n_tps = i_ty.generics.types.len();
if i_n_tps != n_tps {
- struct_span_err!(tcx.sess, it.span, E0094,
- "intrinsic has wrong number of type \
- parameters: found {}, expected {}",
- i_n_tps, n_tps)
- .span_label(it.span, &format!("expected {} type parameter", n_tps))
- .emit();
+ let span = match it.node {
+ hir::ForeignItemFn(_, ref generics) => generics.span().unwrap_or(it.span),
+ hir::ForeignItemStatic(_, _) => it.span
+ };
+
+ struct_span_err!(tcx.sess, span, E0094,
+ "intrinsic has wrong number of type \
+ parameters: found {}, expected {}",
+ i_n_tps, n_tps)
+ .span_label(span, &format!("expected {} type parameter", n_tps))
+ .emit();
} else {
require_same_types(ccx,
TypeOrigin::IntrinsicType(it.span),
{
let (autoref, unsize) = if let Some(mutbl) = pick.autoref {
let region = self.next_region_var(infer::Autoref(self.span));
- let autoref = AutoPtr(self.tcx.mk_region(region), mutbl);
+ let autoref = AutoPtr(region, mutbl);
(Some(autoref), pick.unsize.map(|target| {
target.adjust_for_autoref(self.tcx, Some(autoref))
}))
// parameters from the type and those from the method.
//
// FIXME -- permit users to manually specify lifetimes
+ let supplied_start = substs.params().len() + method.generics.regions.len();
Substs::for_item(self.tcx, method.def_id, |def, _| {
- if let Some(&r) = substs.regions.get(def.index as usize) {
- r
+ let i = def.index as usize;
+ if i < substs.params().len() {
+ substs.region_at(i)
} else {
self.region_var_for_def(self.span, def)
}
}, |def, cur_substs| {
- if let Some(&ty) = substs.types.get(def.index as usize) {
- ty
+ let i = def.index as usize;
+ if i < substs.params().len() {
+ substs.type_at(i)
} else if supplied_method_types.is_empty() {
self.type_var_for_def(self.span, def, cur_substs)
} else {
- supplied_method_types[def.index as usize - substs.types.len()]
+ supplied_method_types[i - supplied_start]
}
})
}
trait_ref.substs,
m);
assert_eq!(m.generics.parent_types as usize,
- trait_ref.substs.types.len());
+ trait_ref.substs.types().count());
assert_eq!(m.generics.parent_regions as usize,
- trait_ref.substs.regions.len());
+ trait_ref.substs.regions().count());
}
// Because this trait derives from a where-clause, it
// artifacts. This means it is safe to put into the
// `WhereClauseCandidate` and (eventually) into the
// `WhereClausePick`.
- assert!(!trait_ref.substs.types.needs_infer());
+ assert!(!trait_ref.substs.needs_infer());
this.inherent_candidates.push(Candidate {
xform_self_ty: xform_self_ty,
// are given do not include type/lifetime parameters for the
// method yet. So create fresh variables here for those too,
// if there are any.
- assert_eq!(substs.types.len(), method.generics.parent_types as usize);
- assert_eq!(substs.regions.len(), method.generics.parent_regions as usize);
+ assert_eq!(substs.types().count(), method.generics.parent_types as usize);
+ assert_eq!(substs.regions().count(), method.generics.parent_regions as usize);
if self.mode == Mode::Path {
return impl_ty;
xform_self_ty.subst(self.tcx, substs)
} else {
let substs = Substs::for_item(self.tcx, method.def_id, |def, _| {
- if let Some(&r) = substs.regions.get(def.index as usize) {
- r
+ let i = def.index as usize;
+ if i < substs.params().len() {
+ substs.region_at(i)
} else {
// In general, during probe we erase regions. See
// `impl_self_ty()` for an explanation.
- ty::ReErased
+ self.tcx.mk_region(ty::ReErased)
}
}, |def, cur_substs| {
- if let Some(&ty) = substs.types.get(def.index as usize) {
- ty
+ let i = def.index as usize;
+ if i < substs.params().len() {
+ substs.type_at(i)
} else {
self.type_var_for_def(self.span, def, cur_substs)
}
let impl_ty = self.tcx.lookup_item_type(impl_def_id).ty;
let substs = Substs::for_item(self.tcx, impl_def_id,
- |_, _| ty::ReErased,
+ |_, _| self.tcx.mk_region(ty::ReErased),
|_, _| self.next_ty_var());
(impl_ty, substs)
// inference variables or other artifacts. This
// means they are safe to put into the
// `WhereClausePick`.
- assert!(!trait_ref.substs().types.needs_infer());
+ assert!(!trait_ref.substs().needs_infer());
WhereClausePick(trait_ref.clone())
}
self.autoderef(span, ty).any(|(ty, _)| self.probe(|_| {
let fn_once_substs =
- Substs::new_trait(tcx, vec![self.next_ty_var()], vec![], ty);
+ Substs::new_trait(tcx, ty, &[self.next_ty_var()]);
let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
let poly_trait_ref = trait_ref.to_poly_trait_ref();
let obligation = Obligation::misc(span,
}
hir::ItemTy(_, ref generics) => {
let pty_ty = ccx.tcx.node_id_to_type(it.id);
- check_bounds_are_used(ccx, &generics.ty_params, pty_ty);
+ check_bounds_are_used(ccx, generics, pty_ty);
}
hir::ItemForeignMod(ref m) => {
if m.abi == Abi::RustIntrinsic {
// (and anyway, within a fn body the right region may not even
// be something the user can write explicitly, since it might
// be some expression).
- self.next_region_var(infer::MiscVariable(span))
+ *self.next_region_var(infer::MiscVariable(span))
}
fn anon_regions(&self, span: Span, count: usize)
-> Result<Vec<ty::Region>, Option<Vec<ElisionFailureInfo>>> {
Ok((0..count).map(|_| {
- self.next_region_var(infer::MiscVariable(span))
+ *self.next_region_var(infer::MiscVariable(span))
}).collect())
}
}
/// outlive the region `r`.
pub fn register_region_obligation(&self,
ty: Ty<'tcx>,
- region: ty::Region,
+ region: &'tcx ty::Region,
cause: traits::ObligationCause<'tcx>)
{
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
//
// FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually
let cause = traits::ObligationCause::new(span, self.body_id, code);
- self.register_region_obligation(ty, ty::ReEmpty, cause);
+ self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause);
}
/// Registers obligations that all types appearing in `substs` are well-formed.
pub fn add_wf_bounds(&self, substs: &Substs<'tcx>, expr: &hir::Expr)
{
- for &ty in &substs.types {
+ for ty in substs.types() {
self.register_wf_obligation(ty, expr.span, traits::MiscObligation);
}
}
// value whose address was taken can actually be made to live
// as long as it needs to live.
let region = self.next_region_var(infer::AddrOfRegion(expr.span));
- tcx.mk_ref(tcx.mk_region(region), tm)
+ tcx.mk_ref(region, tm)
};
self.write_ty(id, oprnd_t);
}
self.check_path_parameter_count(span, !require_type_space, &mut type_segment);
self.check_path_parameter_count(span, true, &mut fn_segment);
+ let (fn_start, has_self) = match (type_segment, fn_segment) {
+ (_, Some((_, generics))) => {
+ (generics.parent_count(), generics.has_self)
+ }
+ (Some((_, generics)), None) => {
+ (generics.own_count(), generics.has_self)
+ }
+ (None, None) => (0, false)
+ };
let substs = Substs::for_item(self.tcx, def.def_id(), |def, _| {
let mut i = def.index as usize;
- let type_regions = match (type_segment, fn_segment) {
- (_, Some((_, generics))) => generics.parent_regions as usize,
- (Some((_, generics)), None) => generics.regions.len(),
- (None, None) => 0
- };
- let segment = if i < type_regions {
+ let segment = if i < fn_start {
+ i -= has_self as usize;
type_segment
} else {
- i -= type_regions;
+ i -= fn_start;
fn_segment
};
let lifetimes = match segment.map(|(s, _)| &s.parameters) {
}
}, |def, substs| {
let mut i = def.index as usize;
- let (type_types, has_self) = match (type_segment, fn_segment) {
- (_, Some((_, generics))) => {
- (generics.parent_types as usize, generics.has_self)
- }
- (Some((_, generics)), None) => {
- (generics.types.len(), generics.has_self)
- }
- (None, None) => (0, false)
- };
- let can_omit = i >= type_types || !require_type_space;
- let segment = if i < type_types {
+ let can_omit = i >= fn_start || !require_type_space;
+ let segment = if i < fn_start {
// Handle Self first, so we can adjust the index to match the AST.
if has_self && i == 0 {
return opt_self_ty.unwrap_or_else(|| {
i -= has_self as usize;
type_segment
} else {
- i -= type_types;
+ i -= fn_start;
fn_segment
};
let types = match segment.map(|(s, _)| &s.parameters) {
None => &[]
};
+ // Skip over the lifetimes in the same segment.
+ if let Some((_, generics)) = segment {
+ i -= generics.regions.len();
+ }
+
let omitted = can_omit && types.is_empty();
if let Some(ast_ty) = types.get(i) {
// A provided type parameter.
}
pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- tps: &[hir::TyParam],
+ generics: &hir::Generics,
ty: Ty<'tcx>) {
debug!("check_bounds_are_used(n_tps={}, ty={:?})",
- tps.len(), ty);
+ generics.ty_params.len(), ty);
// make a vector of booleans initially false, set to true when used
- if tps.is_empty() { return; }
- let mut tps_used = vec![false; tps.len()];
+ if generics.ty_params.is_empty() { return; }
+ let mut tps_used = vec![false; generics.ty_params.len()];
for leaf_ty in ty.walk() {
if let ty::TyParam(ParamTy {idx, ..}) = leaf_ty.sty {
debug!("Found use of ty param num {}", idx);
- tps_used[idx as usize] = true;
+ tps_used[idx as usize - generics.lifetimes.len()] = true;
}
}
- for (i, b) in tps_used.iter().enumerate() {
- if !*b {
- struct_span_err!(ccx.tcx.sess, tps[i].span, E0091,
+ for (&used, param) in tps_used.iter().zip(&generics.ty_params) {
+ if !used {
+ struct_span_err!(ccx.tcx.sess, param.span, E0091,
"type parameter `{}` is unused",
- tps[i].name)
- .span_label(tps[i].span, &format!("unused type parameter"))
+ param.name)
+ .span_label(param.span, &format!("unused type parameter"))
.emit();
}
}
pub struct RegionCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
pub fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
- region_bound_pairs: Vec<(ty::Region, GenericKind<'tcx>)>,
+ region_bound_pairs: Vec<(&'tcx ty::Region, GenericKind<'tcx>)>,
free_region_map: FreeRegionMap,
let call_site_scope = self.call_site_scope.unwrap();
debug!("visit_fn_body body.id {} call_site_scope: {:?}",
body.id, call_site_scope);
+ let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
self.type_of_node_must_outlive(infer::CallReturn(span),
body.id,
- ty::ReScope(call_site_scope));
+ call_site_region);
self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
for implication in implied_bounds {
debug!("implication: {:?}", implication);
match implication {
- ImpliedBound::RegionSubRegion(ty::ReFree(free_a),
- ty::ReVar(vid_b)) => {
+ ImpliedBound::RegionSubRegion(&ty::ReFree(free_a),
+ &ty::ReVar(vid_b)) => {
self.add_given(free_a, vid_b);
}
ImpliedBound::RegionSubParam(r_a, param_b) => {
// variable's type enclose at least the variable's scope.
let var_scope = tcx.region_maps.var_scope(id);
+ let var_region = self.tcx.mk_region(ty::ReScope(var_scope));
let origin = infer::BindingTypeIsNotValidAtDecl(span);
- self.type_of_node_must_outlive(origin, id, ty::ReScope(var_scope));
+ self.type_of_node_must_outlive(origin, id, var_region);
let typ = self.resolve_node_type(id);
dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope);
// scope of that expression. This also guarantees basic WF.
let expr_ty = self.resolve_node_type(expr.id);
// the region corresponding to this expression
- let expr_region = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
+ let expr_region = self.tcx.node_scope_region(expr.id);
self.type_must_outlive(infer::ExprTypeIsNotInScope(expr_ty, expr.span),
expr_ty, expr_region);
None => self.resolve_node_type(base.id)
};
if let ty::TyRef(r_ptr, _) = base_ty.sty {
- self.mk_subregion_due_to_dereference(expr.span, expr_region, *r_ptr);
+ self.mk_subregion_due_to_dereference(expr.span, expr_region, r_ptr);
}
intravisit::walk_expr(self, expr);
let call_site_scope = self.call_site_scope;
debug!("visit_expr ExprRet ret_expr.id {} call_site_scope: {:?}",
ret_expr.id, call_site_scope);
+ let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope.unwrap()));
self.type_of_node_must_outlive(infer::CallReturn(ret_expr.span),
ret_expr.id,
- ty::ReScope(call_site_scope.unwrap()));
+ call_site_region);
intravisit::walk_expr(self, expr);
}
/*From:*/ (&ty::TyRef(from_r, ref from_mt),
/*To: */ &ty::TyRef(to_r, ref to_mt)) => {
// Target cannot outlive source, naturally.
- self.sub_regions(infer::Reborrow(cast_expr.span), *to_r, *from_r);
+ self.sub_regions(infer::Reborrow(cast_expr.span), to_r, from_r);
self.walk_cast(cast_expr, from_mt.ty, to_mt.ty);
}
//
// FIXME(#6268) to support nested method calls, should be callee_id
let callee_scope = self.tcx.region_maps.node_extent(call_expr.id);
- let callee_region = ty::ReScope(callee_scope);
+ let callee_region = self.tcx.mk_region(ty::ReScope(callee_scope));
debug!("callee_region={:?}", callee_region);
derefs,
derefd_ty);
- let s_deref_expr = self.tcx.region_maps.node_extent(deref_expr.id);
- let r_deref_expr = ty::ReScope(s_deref_expr);
+ let r_deref_expr = self.tcx.node_scope_region(deref_expr.id);
for i in 0..derefs {
let method_call = MethodCall::autoderef(deref_expr.id, i as u32);
debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
if let ty::TyRef(r_ptr, _) = derefd_ty.sty {
self.mk_subregion_due_to_dereference(deref_expr.span,
- r_deref_expr, *r_ptr);
+ r_deref_expr, r_ptr);
}
match derefd_ty.builtin_deref(true, ty::NoPreference) {
pub fn mk_subregion_due_to_dereference(&mut self,
deref_span: Span,
- minimum_lifetime: ty::Region,
- maximum_lifetime: ty::Region) {
+ minimum_lifetime: &'tcx ty::Region,
+ maximum_lifetime: &'tcx ty::Region) {
self.sub_regions(infer::DerefPointer(deref_span),
minimum_lifetime, maximum_lifetime)
}
span: Span) {
match cmt.cat {
Categorization::Rvalue(region) => {
- match region {
+ match *region {
ty::ReScope(rvalue_scope) => {
let typ = self.resolve_type(cmt.ty);
dropck::check_safety_of_destructor_if_necessary(self,
rvalue_scope);
}
ty::ReStatic => {}
- region => {
+ _ => {
span_bug!(span,
"unexpected rvalue region in rvalue \
destructor safety checking: `{:?}`",
match mt.ty.sty {
ty::TySlice(_) | ty::TyStr => {
self.sub_regions(infer::IndexSlice(index_expr.span),
- r_index_expr, *r_ptr);
+ self.tcx.mk_region(r_index_expr), r_ptr);
}
_ => {}
}
fn type_of_node_must_outlive(&mut self,
origin: infer::SubregionOrigin<'tcx>,
id: ast::NodeId,
- minimum_lifetime: ty::Region)
+ minimum_lifetime: &'tcx ty::Region)
{
let tcx = self.tcx;
let mc = mc::MemCategorizationContext::new(self);
for arg in args {
let arg_ty = self.node_ty(arg.id);
- let re_scope = ty::ReScope(body_scope);
+ let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
arg_ty,
fn link_autoref(&self,
expr: &hir::Expr,
autoderefs: usize,
- autoref: &adjustment::AutoRef)
+ autoref: &adjustment::AutoRef<'tcx>)
{
debug!("link_autoref(autoref={:?})", autoref);
let mc = mc::MemCategorizationContext::new(self);
}
adjustment::AutoUnsafe(m) => {
- let r = ty::ReScope(self.tcx.region_maps.node_extent(expr.id));
- self.link_region(expr.span, &r, ty::BorrowKind::from_mutbl(m), expr_cmt);
+ let r = self.tcx.node_scope_region(expr.id);
+ self.link_region(expr.span, r, ty::BorrowKind::from_mutbl(m), expr_cmt);
}
}
}
expr, callee_scope);
let mc = mc::MemCategorizationContext::new(self);
let expr_cmt = ignore_err!(mc.cat_expr(expr));
- let borrow_region = ty::ReScope(callee_scope);
- self.link_region(expr.span, &borrow_region, ty::ImmBorrow, expr_cmt);
+ let borrow_region = self.tcx.mk_region(ty::ReScope(callee_scope));
+ self.link_region(expr.span, borrow_region, ty::ImmBorrow, expr_cmt);
}
/// Like `link_region()`, except that the region is extracted from the type of `id`,
id, mutbl, cmt_borrowed);
let rptr_ty = self.resolve_node_type(id);
- if let ty::TyRef(&r, _) = rptr_ty.sty {
+ if let ty::TyRef(r, _) = rptr_ty.sty {
debug!("rptr_ty={}", rptr_ty);
- self.link_region(span, &r, ty::BorrowKind::from_mutbl(mutbl),
+ self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl),
cmt_borrowed);
}
}
/// between regions, as explained in `link_reborrowed_region()`.
fn link_region(&self,
span: Span,
- borrow_region: &ty::Region,
+ borrow_region: &'tcx ty::Region,
borrow_kind: ty::BorrowKind,
borrow_cmt: mc::cmt<'tcx>) {
let mut borrow_cmt = borrow_cmt;
let mut borrow_kind = borrow_kind;
let origin = infer::DataBorrowed(borrow_cmt.ty, span);
- self.type_must_outlive(origin, borrow_cmt.ty, *borrow_region);
+ self.type_must_outlive(origin, borrow_cmt.ty, borrow_region);
loop {
debug!("link_region(borrow_region={:?}, borrow_kind={:?}, borrow_cmt={:?})",
/// recurse and process `ref_cmt` (see case 2 above).
fn link_reborrowed_region(&self,
span: Span,
- borrow_region: &ty::Region,
+ borrow_region: &'tcx ty::Region,
borrow_kind: ty::BorrowKind,
ref_cmt: mc::cmt<'tcx>,
- ref_region: ty::Region,
+ ref_region: &'tcx ty::Region,
mut ref_kind: ty::BorrowKind,
note: mc::Note)
-> Option<(mc::cmt<'tcx>, ty::BorrowKind)>
debug!("link_reborrowed_region: {:?} <= {:?}",
borrow_region,
ref_region);
- self.sub_regions(cause, *borrow_region, ref_region);
+ self.sub_regions(cause, borrow_region, ref_region);
// If we end up needing to recurse and establish a region link
// with `ref_cmt`, calculate what borrow kind we will end up
origin: infer::ParameterOrigin,
substs: &Substs<'tcx>,
expr_span: Span,
- expr_region: ty::Region) {
+ expr_region: &'tcx ty::Region) {
debug!("substs_wf_in_scope(substs={:?}, \
expr_region={:?}, \
origin={:?}, \
let origin = infer::ParameterInScope(origin, expr_span);
- for ®ion in &substs.regions {
+ for region in substs.regions() {
self.sub_regions(origin.clone(), expr_region, region);
}
- for &ty in &substs.types {
+ for ty in substs.types() {
let ty = self.resolve_type(ty);
self.type_must_outlive(origin.clone(), ty, expr_region);
}
pub fn type_must_outlive(&self,
origin: infer::SubregionOrigin<'tcx>,
ty: Ty<'tcx>,
- region: ty::Region)
+ region: &'tcx ty::Region)
{
let ty = self.resolve_type(ty);
fn components_must_outlive(&self,
origin: infer::SubregionOrigin<'tcx>,
components: Vec<ty::outlives::Component<'tcx>>,
- region: ty::Region)
+ region: &'tcx ty::Region)
{
for component in components {
let origin = origin.clone();
fn param_ty_must_outlive(&self,
origin: infer::SubregionOrigin<'tcx>,
- region: ty::Region,
+ region: &'tcx ty::Region,
param_ty: ty::ParamTy) {
debug!("param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})",
region, param_ty, origin);
fn projection_must_outlive(&self,
origin: infer::SubregionOrigin<'tcx>,
- region: ty::Region,
+ region: &'tcx ty::Region,
projection_ty: ty::ProjectionTy<'tcx>)
{
debug!("projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})",
// If we know that the projection outlives 'static, then we're
// done here.
- if env_bounds.contains(&ty::ReStatic) {
+ if env_bounds.contains(&&ty::ReStatic) {
debug!("projection_must_outlive: 'static as declared bound");
return;
}
if env_bounds.is_empty() && needs_infer {
debug!("projection_must_outlive: no declared bounds");
- for &component_ty in &projection_ty.trait_ref.substs.types {
+ for component_ty in projection_ty.trait_ref.substs.types() {
self.type_must_outlive(origin.clone(), component_ty, region);
}
- for &r in &projection_ty.trait_ref.substs.regions {
+ for r in projection_ty.trait_ref.substs.regions() {
self.sub_regions(origin.clone(), region, r);
}
if !env_bounds.is_empty() && env_bounds[1..].iter().all(|b| *b == env_bounds[0]) {
let unique_bound = env_bounds[0];
debug!("projection_must_outlive: unique declared bound = {:?}", unique_bound);
- if projection_ty.trait_ref.substs.regions
- .iter()
- .any(|r| env_bounds.contains(r))
- {
+ if projection_ty.trait_ref.substs.regions().any(|r| env_bounds.contains(&r)) {
debug!("projection_must_outlive: unique declared bound appears in trait ref");
self.sub_regions(origin.clone(), region, unique_bound);
return;
self.verify_generic_bound(origin, generic.clone(), region, verify_bound);
}
- fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
+ fn type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
match ty.sty {
ty::TyParam(p) => {
self.param_bound(p)
}
}
- fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound {
+ fn param_bound(&self, param_ty: ty::ParamTy) -> VerifyBound<'tcx> {
let param_env = &self.parameter_environment;
debug!("param_bound(param_ty={:?})",
fn projection_declared_bounds(&self,
span: Span,
projection_ty: ty::ProjectionTy<'tcx>)
- -> Vec<ty::Region>
+ -> Vec<&'tcx ty::Region>
{
// First assemble bounds from where clauses and traits.
fn projection_bound(&self,
span: Span,
- declared_bounds: Vec<ty::Region>,
+ declared_bounds: Vec<&'tcx ty::Region>,
projection_ty: ty::ProjectionTy<'tcx>)
- -> VerifyBound {
+ -> VerifyBound<'tcx> {
debug!("projection_bound(declared_bounds={:?}, projection_ty={:?})",
declared_bounds, projection_ty);
VerifyBound::AnyRegion(declared_bounds).or(recursive_bound)
}
- fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound {
+ fn recursive_type_bound(&self, span: Span, ty: Ty<'tcx>) -> VerifyBound<'tcx> {
let mut bounds = vec![];
for subty in ty.walk_shallow() {
}
fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>)
- -> Vec<ty::Region>
+ -> Vec<&'tcx ty::Region>
{
let param_env = &self.parameter_environment;
fn declared_projection_bounds_from_trait(&self,
span: Span,
projection_ty: ty::ProjectionTy<'tcx>)
- -> Vec<ty::Region>
+ -> Vec<&'tcx ty::Region>
{
debug!("projection_bounds(projection_ty={:?})",
projection_ty);
match capture {
ty::UpvarCapture::ByValue => freevar_ty,
ty::UpvarCapture::ByRef(borrow) =>
- tcx.mk_ref(tcx.mk_region(borrow.region),
+ tcx.mk_ref(borrow.region,
ty::TypeAndMut {
ty: freevar_ty,
mutbl: borrow.kind.to_mutbl_lossy(),
borrow_id: ast::NodeId,
_borrow_span: Span,
cmt: mc::cmt<'tcx>,
- _loan_region: ty::Region,
+ _loan_region: &'tcx ty::Region,
bk: ty::BorrowKind,
_loan_cause: euv::LoanCause)
{
ty::ExplicitSelfCategory::Static => return,
ty::ExplicitSelfCategory::ByValue => self_ty,
ty::ExplicitSelfCategory::ByReference(region, mutability) => {
- fcx.tcx.mk_ref(fcx.tcx.mk_region(region), ty::TypeAndMut {
+ fcx.tcx.mk_ref(region, ty::TypeAndMut {
ty: self_ty,
mutbl: mutability
})
let variances = self.tcx().item_variances(item_def_id);
let mut constrained_parameters: HashSet<_> =
- variances.types
+ variances[ast_generics.lifetimes.len()..]
.iter().enumerate()
.filter(|&(_, &variance)| variance != ty::Bivariant)
.map(|(index, _)| self.param_ty(ast_generics, index))
None,
&mut constrained_parameters);
- for (index, _) in variances.types.iter().enumerate() {
- let param_ty = self.param_ty(ast_generics, index);
- if constrained_parameters.contains(&Parameter::Type(param_ty)) {
- continue;
- }
- let span = ast_generics.ty_params[index].span;
- self.report_bivariance(span, param_ty.name);
- }
-
- for (index, &variance) in variances.regions.iter().enumerate() {
- if variance != ty::Bivariant {
- continue;
- }
+ for (index, &variance) in variances.iter().enumerate() {
+ let (span, name) = if index < ast_generics.lifetimes.len() {
+ if variance != ty::Bivariant {
+ continue;
+ }
- let span = ast_generics.lifetimes[index].lifetime.span;
- let name = ast_generics.lifetimes[index].lifetime.name;
+ (ast_generics.lifetimes[index].lifetime.span,
+ ast_generics.lifetimes[index].lifetime.name)
+ } else {
+ let index = index - ast_generics.lifetimes.len();
+ let param_ty = self.param_ty(ast_generics, index);
+ if constrained_parameters.contains(&Parameter::Type(param_ty)) {
+ continue;
+ }
+ (ast_generics.ty_params[index].span, param_ty.name)
+ };
self.report_bivariance(span, name);
}
}
// Trait impl: take implied bounds from all types that
// appear in the trait reference.
let trait_ref = self.instantiate_type_scheme(span, free_substs, trait_ref);
- trait_ref.substs.types.to_vec()
+ trait_ref.substs.types().collect()
}
None => {
// early-bound versions of them, visible from the
// outside of the function. This is needed by, and
// only populated if there are any `impl Trait`.
- free_to_bound_regions: DefIdMap<ty::Region>
+ free_to_bound_regions: DefIdMap<&'gcx ty::Region>
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
return wbcx;
}
+ let gcx = fcx.tcx.global_tcx();
let free_substs = fcx.parameter_environment.free_substs;
- for (i, r) in free_substs.regions.iter().enumerate() {
+ for (i, k) in free_substs.params().iter().enumerate() {
+ let r = if let Some(r) = k.as_region() {
+ r
+ } else {
+ continue;
+ };
match *r {
ty::ReFree(ty::FreeRegion {
bound_region: ty::BoundRegion::BrNamed(def_id, name, _), ..
}) => {
- let bound_region = ty::ReEarlyBound(ty::EarlyBoundRegion {
+ let bound_region = gcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
index: i as u32,
name: name,
- });
+ }));
wbcx.free_to_bound_regions.insert(def_id, bound_region);
}
_ => {
// Convert the type from the function into a type valid outside
// the function, by replacing free regions with early-bound ones.
let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
- match r {
+ match *r {
// 'static is valid everywhere.
- ty::ReStatic => ty::ReStatic,
+ ty::ReStatic => gcx.mk_region(ty::ReStatic),
// Free regions that come from early-bound regions are valid.
ty::ReFree(ty::FreeRegion {
span_err!(self.tcx().sess, span, E0564,
"only named lifetimes are allowed in `impl Trait`, \
but `{}` was found in the type `{}`", r, inside_ty);
- ty::ReStatic
+ gcx.mk_region(ty::ReStatic)
}
ty::ReVar(_) |
}
}
- fn fold_region(&mut self, r: ty::Region) -> ty::Region {
+ fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
match self.infcx.fully_resolve(&r) {
Ok(r) => r,
Err(e) => {
self.report_error(e);
- ty::ReStatic
+ self.tcx.mk_region(ty::ReStatic)
}
}
}
let source = tcx.lookup_item_type(impl_did).ty;
let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
- let target = trait_ref.substs.types[1];
+ let target = trait_ref.substs.type_at(1);
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
source, target);
(&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
(&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
- infcx.sub_regions(infer::RelateObjectBound(span), *r_b, *r_a);
+ infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
}
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_node_id);
let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0,
- source, vec![target]);
+ source, &[target]);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
let has_self = opt_self.is_some();
let mut parent_has_self = false;
+ let mut own_start = has_self as u32;
let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
let generics = generics_of_def_id(ccx, def_id);
assert_eq!(generics.parent, None);
assert_eq!(generics.parent_types, 0);
assert_eq!(has_self, false);
parent_has_self = generics.has_self;
+ own_start = generics.count() as u32;
(generics.regions.len() as u32, generics.types.len() as u32)
});
let regions = early_lifetimes.iter().enumerate().map(|(i, l)| {
ty::RegionParameterDef {
name: l.lifetime.name,
- index: parent_regions + i as u32,
+ index: own_start + i as u32,
def_id: tcx.map.local_def_id(l.lifetime.id),
bounds: l.bounds.iter().map(|l| {
ast_region_to_region(tcx, l)
}).collect()
}
- }).collect();
+ }).collect::<Vec<_>>();
// Now create the real type parameters.
+ let type_start = own_start + regions.len() as u32;
let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
- let i = parent_types + has_self as u32 + i as u32;
+ let i = type_start + i as u32;
get_or_create_type_parameter_def(ccx, ast_generics, i, p, allow_defaults)
});
let types: Vec<_> = opt_self.into_iter().chain(types).collect();
tcx.alloc_generics(ty::Generics {
parent: parent_def_id,
- parent_regions: parent_regions as u32,
- parent_types: parent_types as u32,
+ parent_regions: parent_regions,
+ parent_types: parent_types,
regions: regions,
types: types,
has_self: has_self || parent_has_self
-> ty::GenericPredicates<'tcx>
{
let tcx = ccx.tcx;
- let (parent_regions, parent_types) = parent.map_or((0, 0), |def_id| {
+ let parent_count = parent.map_or(0, |def_id| {
let generics = generics_of_def_id(ccx, def_id);
assert_eq!(generics.parent, None);
assert_eq!(generics.parent_regions, 0);
assert_eq!(generics.parent_types, 0);
- (generics.regions.len() as u32, generics.types.len() as u32)
+ generics.count() as u32
});
let ref base_predicates = match parent {
Some(def_id) => {
};
let mut predicates = super_predicates;
+ // Collect the region predicates that were declared inline as
+ // well. In the case of parameters declared on a fn or method, we
+ // have to be careful to only iterate over early-bound regions.
+ let own_start = parent_count + has_self as u32;
+ let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
+ for (index, param) in early_lifetimes.iter().enumerate() {
+ let index = own_start + index as u32;
+ let region = ccx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+ index: index,
+ name: param.lifetime.name
+ }));
+ for bound in ¶m.bounds {
+ let bound_region = ast_region_to_region(ccx.tcx, bound);
+ let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
+ predicates.push(outlives.to_predicate());
+ }
+ }
+
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T:Foo>`).
+ let type_start = own_start + early_lifetimes.len() as u32;
for (index, param) in ast_generics.ty_params.iter().enumerate() {
- let index = parent_types + has_self as u32 + index as u32;
+ let index = type_start + index as u32;
let param_ty = ty::ParamTy::new(index, param.name).to_ty(ccx.tcx);
let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)),
param_ty,
predicates.extend(bounds.predicates(ccx.tcx, param_ty));
}
- // Collect the region predicates that were declared inline as
- // well. In the case of parameters declared on a fn or method, we
- // have to be careful to only iterate over early-bound regions.
- let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
- for (index, param) in early_lifetimes.iter().enumerate() {
- let index = parent_regions + index as u32;
- let region =
- ty::ReEarlyBound(ty::EarlyBoundRegion {
- index: index,
- name: param.lifetime.name
- });
- for bound in ¶m.bounds {
- let bound_region = ast_region_to_region(ccx.tcx, bound);
- let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
- predicates.push(outlives.to_predicate());
- }
- }
-
// Add in the bounds that appear in the where-clause
let where_clause = &ast_generics.where_clause;
for predicate in &where_clause.predicates {
param_id: ast::NodeId,
param_bounds: &[hir::TyParamBound],
where_clause: &hir::WhereClause)
- -> ty::ObjectLifetimeDefault
+ -> ty::ObjectLifetimeDefault<'tcx>
{
let inline_bounds = from_bounds(ccx, param_bounds);
let where_bounds = from_predicates(ccx, param_id, &where_clause.predicates);
fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
bounds: &[hir::TyParamBound])
- -> Vec<ty::Region>
+ -> Vec<&'tcx ty::Region>
{
bounds.iter()
.filter_map(|bound| {
fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
param_id: ast::NodeId,
predicates: &[hir::WherePredicate])
- -> Vec<ty::Region>
+ -> Vec<&'tcx ty::Region>
{
predicates.iter()
.flat_map(|predicate| {
}
Substs::for_item(tcx, def_id,
- |def, _| def.to_early_bound_region(),
+ |def, _| tcx.mk_region(def.to_early_bound_region()),
|def, _| tcx.mk_param_from_def(def))
}
t.super_visit_with(self)
}
- fn visit_region(&mut self, r: ty::Region) -> bool {
- match r {
+ fn visit_region(&mut self, r: &'tcx ty::Region) -> bool {
+ match *r {
ty::ReEarlyBound(data) => {
self.parameters.push(Parameter::Region(data));
}
node_id,
item_substs);
- assert!(!item_substs.substs.types.needs_infer());
+ assert!(!item_substs.substs.needs_infer());
ccx.tcx.tables.borrow_mut().item_substs.insert(node_id, item_substs);
}
/// A scope which overrides the default object lifetime but has no other effect.
pub struct ObjectLifetimeDefaultRscope<'r> {
base_scope: &'r (RegionScope+'r),
- default: ty::ObjectLifetimeDefault,
+ default: ty::ObjectLifetimeDefault<'r>,
}
impl<'r> ObjectLifetimeDefaultRscope<'r> {
pub fn new(base_scope: &'r (RegionScope+'r),
- default: ty::ObjectLifetimeDefault)
+ default: ty::ObjectLifetimeDefault<'r>)
-> ObjectLifetimeDefaultRscope<'r>
{
ObjectLifetimeDefaultRscope {
Some(self.base_object_lifetime_default(span)),
ty::ObjectLifetimeDefault::Specific(r) =>
- Some(r),
+ Some(*r),
}
}
use super::terms::*;
use super::terms::VarianceTerm::*;
-use super::terms::ParamKind::*;
use super::xform::*;
pub struct ConstraintContext<'a, 'tcx: 'a> {
fn declared_variance(&self,
param_def_id: DefId,
item_def_id: DefId,
- kind: ParamKind,
index: usize)
-> VarianceTermPtr<'a> {
assert_eq!(param_def_id.krate, item_def_id.krate);
// Parameter on an item defined within another crate:
// variance already inferred, just look it up.
let variances = self.tcx().item_variances(item_def_id);
- let variance = match kind {
- TypeParam => variances.types[index],
- RegionParam => variances.regions[index],
- };
- self.constant_term(variance)
+ self.constant_term(variances[index])
}
}
ty::TyRef(region, ref mt) => {
let contra = self.contravariant(variance);
- self.add_constraints_from_region(generics, *region, contra);
+ self.add_constraints_from_region(generics, region, contra);
self.add_constraints_from_mt(generics, mt, variance);
}
ty::TyParam(ref data) => {
assert_eq!(generics.parent, None);
- assert!((data.idx as usize) < generics.types.len());
- let def_id = generics.types[data.idx as usize].def_id;
+ let mut i = data.idx as usize;
+ if !generics.has_self || i > 0 {
+ i -= generics.regions.len();
+ }
+ let def_id = generics.types[i].def_id;
let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
match self.terms_cx.inferred_map.get(&node_id) {
Some(&index) => {
for p in type_param_defs {
let variance_decl =
- self.declared_variance(p.def_id, def_id, TypeParam, p.index as usize);
+ self.declared_variance(p.def_id, def_id, p.index as usize);
let variance_i = self.xform(variance, variance_decl);
let substs_ty = substs.type_for_def(p);
debug!("add_constraints_from_substs: variance_decl={:?} variance_i={:?}",
for p in region_param_defs {
let variance_decl =
- self.declared_variance(p.def_id, def_id, RegionParam, p.index as usize);
+ self.declared_variance(p.def_id, def_id, p.index as usize);
let variance_i = self.xform(variance, variance_decl);
let substs_r = substs.region_for_def(p);
self.add_constraints_from_region(generics, substs_r, variance_i);
/// context with ambient variance `variance`
fn add_constraints_from_region(&mut self,
generics: &ty::Generics<'tcx>,
- region: ty::Region,
+ region: &'tcx ty::Region,
variance: VarianceTermPtr<'a>) {
- match region {
+ match *region {
ty::ReEarlyBound(ref data) => {
assert_eq!(generics.parent, None);
- assert!((data.index as usize) < generics.regions.len());
- let def_id = generics.regions[data.index as usize].def_id;
+ let i = data.index as usize - generics.has_self as usize;
+ let def_id = generics.regions[i].def_id;
let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
if self.is_to_be_inferred(node_id) {
let index = self.inferred_index(node_id);
use super::constraints::*;
use super::terms::*;
use super::terms::VarianceTerm::*;
-use super::terms::ParamKind::*;
use super::xform::*;
struct SolveContext<'a, 'tcx: 'a> {
while index < num_inferred {
let item_id = inferred_infos[index].item_id;
- let mut item_variances = ty::ItemVariances::empty();
+ let mut item_variances = vec![];
while index < num_inferred && inferred_infos[index].item_id == item_id {
let info = &inferred_infos[index];
let variance = solutions[index];
- debug!("Index {} Info {} / {:?} Variance {:?}",
- index, info.index, info.kind, variance);
- match info.kind {
- TypeParam => {
- assert_eq!(item_variances.types.len(), info.index);
- item_variances.types.push(variance);
- }
- RegionParam => {
- assert_eq!(item_variances.regions.len(), info.index);
- item_variances.regions.push(variance);
- }
- }
+ debug!("Index {} Info {} Variance {:?}",
+ index, info.index, variance);
+ assert_eq!(item_variances.len(), info.index);
+ item_variances.push(variance);
index += 1;
}
use util::nodemap::NodeMap;
use self::VarianceTerm::*;
-use self::ParamKind::*;
pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub arena: &'a TypedArena<VarianceTerm<'a>>,
- pub empty_variances: Rc<ty::ItemVariances>,
+ pub empty_variances: Rc<Vec<ty::Variance>>,
// For marker types, UnsafeCell, and other lang items where
// variance is hardcoded, records the item-id and the hardcoded
pub inferred_infos: Vec<InferredInfo<'a>> ,
}
-#[derive(Copy, Clone, Debug, PartialEq)]
-pub enum ParamKind {
- TypeParam,
- RegionParam,
-}
-
pub struct InferredInfo<'a> {
pub item_id: ast::NodeId,
- pub kind: ParamKind,
pub index: usize,
pub param_id: ast::NodeId,
pub term: VarianceTermPtr<'a>,
// cache and share the variance struct used for items with
// no type/region parameters
- empty_variances: Rc::new(ty::ItemVariances::empty())
+ empty_variances: Rc::new(vec![])
};
// See README.md for a discussion on dep-graph management.
let inferreds_on_entry = self.num_inferred();
+ if has_self {
+ self.add_inferred(item_id, 0, item_id);
+ }
+
for (i, p) in generics.lifetimes.iter().enumerate() {
let id = p.lifetime.id;
- self.add_inferred(item_id, RegionParam, i, id);
+ let i = has_self as usize + i;
+ self.add_inferred(item_id, i, id);
}
- if has_self {
- self.add_inferred(item_id, TypeParam, 0, item_id);
- }
for (i, p) in generics.ty_params.iter().enumerate() {
- let i = has_self as usize + i;
- self.add_inferred(item_id, TypeParam, i, p.id);
+ let i = has_self as usize + generics.lifetimes.len() + i;
+ self.add_inferred(item_id, i, p.id);
}
// If this item has no type or lifetime parameters,
fn add_inferred(&mut self,
item_id: ast::NodeId,
- kind: ParamKind,
index: usize,
param_id: ast::NodeId) {
let inf_index = InferredIndex(self.inferred_infos.len());
let term = self.arena.alloc(InferredTerm(inf_index));
let initial_variance = self.pick_initial_variance(item_id, index);
self.inferred_infos.push(InferredInfo { item_id: item_id,
- kind: kind,
index: index,
param_id: param_id,
term: term,
debug!("add_inferred(item_path={}, \
item_id={}, \
- kind={:?}, \
index={}, \
param_id={}, \
inf_index={:?}, \
initial_variance={:?})",
self.tcx.item_path_str(self.tcx.map.local_def_id(item_id)),
- item_id, kind, index, param_id, inf_index,
+ item_id, index, param_id, inf_index,
initial_variance);
}
//! that clean them.
pub use self::Type::*;
-pub use self::PrimitiveType::*;
pub use self::TypeKind::*;
pub use self::VariantKind::*;
pub use self::Mutability::*;
}
}
pub fn is_mod(&self) -> bool {
- ItemType::from_item(self) == ItemType::Module
+ ItemType::from(self) == ItemType::Module
}
pub fn is_trait(&self) -> bool {
- ItemType::from_item(self) == ItemType::Trait
+ ItemType::from(self) == ItemType::Trait
}
pub fn is_struct(&self) -> bool {
- ItemType::from_item(self) == ItemType::Struct
+ ItemType::from(self) == ItemType::Struct
}
pub fn is_enum(&self) -> bool {
- ItemType::from_item(self) == ItemType::Module
+ ItemType::from(self) == ItemType::Module
}
pub fn is_fn(&self) -> bool {
- ItemType::from_item(self) == ItemType::Function
+ ItemType::from(self) == ItemType::Function
}
pub fn is_associated_type(&self) -> bool {
- ItemType::from_item(self) == ItemType::AssociatedType
+ ItemType::from(self) == ItemType::AssociatedType
}
pub fn is_associated_const(&self) -> bool {
- ItemType::from_item(self) == ItemType::AssociatedConst
+ ItemType::from(self) == ItemType::AssociatedConst
}
pub fn is_method(&self) -> bool {
- ItemType::from_item(self) == ItemType::Method
+ ItemType::from(self) == ItemType::Method
}
pub fn is_ty_method(&self) -> bool {
- ItemType::from_item(self) == ItemType::TyMethod
+ ItemType::from(self) == ItemType::TyMethod
}
pub fn is_primitive(&self) -> bool {
- ItemType::from_item(self) == ItemType::Primitive
+ ItemType::from(self) == ItemType::Primitive
}
pub fn is_stripped(&self) -> bool {
match self.inner { StrippedItem(..) => true, _ => false }
StrippedItem(Box<ItemEnum>),
}
+impl ItemEnum {
+ pub fn generics(&self) -> Option<&Generics> {
+ Some(match *self {
+ ItemEnum::StructItem(ref s) => &s.generics,
+ ItemEnum::EnumItem(ref e) => &e.generics,
+ ItemEnum::FunctionItem(ref f) => &f.generics,
+ ItemEnum::TypedefItem(ref t, _) => &t.generics,
+ ItemEnum::TraitItem(ref t) => &t.generics,
+ ItemEnum::ImplItem(ref i) => &i.generics,
+ ItemEnum::TyMethodItem(ref i) => &i.generics,
+ ItemEnum::MethodItem(ref i) => &i.generics,
+ ItemEnum::ForeignFunctionItem(ref f) => &f.generics,
+ _ => return None,
+ })
+ }
+}
+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Module {
pub items: Vec<Item>,
fn external_path_params(cx: &DocContext, trait_did: Option<DefId>, has_self: bool,
bindings: Vec<TypeBinding>, substs: &Substs) -> PathParameters {
- let lifetimes = substs.regions.iter().filter_map(|v| v.clean(cx)).collect();
- let types = substs.types[has_self as usize..].to_vec();
+ let lifetimes = substs.regions().filter_map(|v| v.clean(cx)).collect();
+ let types = substs.types().skip(has_self as usize).collect::<Vec<_>>();
match (trait_did, cx.tcx_opt()) {
// Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C
let path = external_path(cx, &tcx.item_name(self.def_id).as_str(),
Some(self.def_id), true, vec![], self.substs);
- debug!("ty::TraitRef\n substs.types: {:?}\n",
- &self.input_types()[1..]);
+ debug!("ty::TraitRef\n subst: {:?}\n", self.substs);
// collect any late bound regions
let mut late_bounds = vec![];
- for &ty_s in &self.input_types()[1..] {
+ for ty_s in self.input_types().skip(1) {
if let ty::TyTuple(ts) = ty_s.sty {
for &ty_s in ts {
if let ty::TyRef(ref reg, _) = ty_s.sty {
impl<'tcx> Clean<Option<Vec<TyParamBound>>> for Substs<'tcx> {
fn clean(&self, cx: &DocContext) -> Option<Vec<TyParamBound>> {
let mut v = Vec::new();
- v.extend(self.regions.iter().filter_map(|r| r.clean(cx))
+ v.extend(self.regions().filter_map(|r| r.clean(cx))
.map(RegionBound));
- v.extend(self.types.iter().map(|t| TraitBound(PolyTrait {
+ v.extend(self.types().map(|t| TraitBound(PolyTrait {
trait_: t.clean(cx),
lifetimes: vec![]
}, hir::TraitBoundModifier::None)));
}
}
-impl Clean<Lifetime> for ty::RegionParameterDef {
+impl<'tcx> Clean<Lifetime> for ty::RegionParameterDef<'tcx> {
fn clean(&self, _: &DocContext) -> Lifetime {
Lifetime(self.name.to_string())
}
}
}
-impl Clean<WherePredicate> for ty::OutlivesPredicate<ty::Region, ty::Region> {
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<&'tcx ty::Region, &'tcx ty::Region> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref a, ref b) = *self;
WherePredicate::RegionPredicate {
}
}
-impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, ty::Region> {
+impl<'tcx> Clean<WherePredicate> for ty::OutlivesPredicate<ty::Ty<'tcx>, &'tcx ty::Region> {
fn clean(&self, cx: &DocContext) -> WherePredicate {
let ty::OutlivesPredicate(ref ty, ref lt) = *self;
Str,
Slice,
Array,
- PrimitiveTuple,
- PrimitiveRawPointer,
+ Tuple,
+ RawPointer,
}
#[derive(Clone, RustcEncodable, RustcDecodable, Copy, Debug)]
pub fn primitive_type(&self) -> Option<PrimitiveType> {
match *self {
Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
- Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(Slice),
+ Vector(..) | BorrowedRef{ type_: box Vector(..), .. } => Some(PrimitiveType::Slice),
FixedVector(..) | BorrowedRef { type_: box FixedVector(..), .. } => {
- Some(Array)
+ Some(PrimitiveType::Array)
}
- Tuple(..) => Some(PrimitiveTuple),
- RawPointer(..) => Some(PrimitiveRawPointer),
+ Tuple(..) => Some(PrimitiveType::Tuple),
+ RawPointer(..) => Some(PrimitiveType::RawPointer),
_ => None,
}
}
impl PrimitiveType {
fn from_str(s: &str) -> Option<PrimitiveType> {
match s {
- "isize" => Some(Isize),
- "i8" => Some(I8),
- "i16" => Some(I16),
- "i32" => Some(I32),
- "i64" => Some(I64),
- "usize" => Some(Usize),
- "u8" => Some(U8),
- "u16" => Some(U16),
- "u32" => Some(U32),
- "u64" => Some(U64),
- "bool" => Some(Bool),
- "char" => Some(Char),
- "str" => Some(Str),
- "f32" => Some(F32),
- "f64" => Some(F64),
- "array" => Some(Array),
- "slice" => Some(Slice),
- "tuple" => Some(PrimitiveTuple),
- "pointer" => Some(PrimitiveRawPointer),
+ "isize" => Some(PrimitiveType::Isize),
+ "i8" => Some(PrimitiveType::I8),
+ "i16" => Some(PrimitiveType::I16),
+ "i32" => Some(PrimitiveType::I32),
+ "i64" => Some(PrimitiveType::I64),
+ "usize" => Some(PrimitiveType::Usize),
+ "u8" => Some(PrimitiveType::U8),
+ "u16" => Some(PrimitiveType::U16),
+ "u32" => Some(PrimitiveType::U32),
+ "u64" => Some(PrimitiveType::U64),
+ "bool" => Some(PrimitiveType::Bool),
+ "char" => Some(PrimitiveType::Char),
+ "str" => Some(PrimitiveType::Str),
+ "f32" => Some(PrimitiveType::F32),
+ "f64" => Some(PrimitiveType::F64),
+ "array" => Some(PrimitiveType::Array),
+ "slice" => Some(PrimitiveType::Slice),
+ "tuple" => Some(PrimitiveType::Tuple),
+ "pointer" => Some(PrimitiveType::RawPointer),
_ => None,
}
}
pub fn to_string(&self) -> &'static str {
match *self {
- Isize => "isize",
- I8 => "i8",
- I16 => "i16",
- I32 => "i32",
- I64 => "i64",
- Usize => "usize",
- U8 => "u8",
- U16 => "u16",
- U32 => "u32",
- U64 => "u64",
- F32 => "f32",
- F64 => "f64",
- Str => "str",
- Bool => "bool",
- Char => "char",
- Array => "array",
- Slice => "slice",
- PrimitiveTuple => "tuple",
- PrimitiveRawPointer => "pointer",
+ PrimitiveType::Isize => "isize",
+ PrimitiveType::I8 => "i8",
+ PrimitiveType::I16 => "i16",
+ PrimitiveType::I32 => "i32",
+ PrimitiveType::I64 => "i64",
+ PrimitiveType::Usize => "usize",
+ PrimitiveType::U8 => "u8",
+ PrimitiveType::U16 => "u16",
+ PrimitiveType::U32 => "u32",
+ PrimitiveType::U64 => "u64",
+ PrimitiveType::F32 => "f32",
+ PrimitiveType::F64 => "f64",
+ PrimitiveType::Str => "str",
+ PrimitiveType::Bool => "bool",
+ PrimitiveType::Char => "char",
+ PrimitiveType::Array => "array",
+ PrimitiveType::Slice => "slice",
+ PrimitiveType::Tuple => "tuple",
+ PrimitiveType::RawPointer => "pointer",
}
}
}
}
+impl From<ast::IntTy> for PrimitiveType {
+ fn from(int_ty: ast::IntTy) -> PrimitiveType {
+ match int_ty {
+ ast::IntTy::Is => PrimitiveType::Isize,
+ ast::IntTy::I8 => PrimitiveType::I8,
+ ast::IntTy::I16 => PrimitiveType::I16,
+ ast::IntTy::I32 => PrimitiveType::I32,
+ ast::IntTy::I64 => PrimitiveType::I64,
+ }
+ }
+}
+
+impl From<ast::UintTy> for PrimitiveType {
+ fn from(uint_ty: ast::UintTy) -> PrimitiveType {
+ match uint_ty {
+ ast::UintTy::Us => PrimitiveType::Usize,
+ ast::UintTy::U8 => PrimitiveType::U8,
+ ast::UintTy::U16 => PrimitiveType::U16,
+ ast::UintTy::U32 => PrimitiveType::U32,
+ ast::UintTy::U64 => PrimitiveType::U64,
+ }
+ }
+}
+
+impl From<ast::FloatTy> for PrimitiveType {
+ fn from(float_ty: ast::FloatTy) -> PrimitiveType {
+ match float_ty {
+ ast::FloatTy::F32 => PrimitiveType::F32,
+ ast::FloatTy::F64 => PrimitiveType::F64,
+ }
+ }
+}
// Poor man's type parameter substitution at HIR level.
// Used to replace private type aliases in public signatures with their aliased types.
fn clean(&self, cx: &DocContext) -> Type {
match self.sty {
ty::TyNever => Never,
- ty::TyBool => Primitive(Bool),
- ty::TyChar => Primitive(Char),
- ty::TyInt(ast::IntTy::Is) => Primitive(Isize),
- ty::TyInt(ast::IntTy::I8) => Primitive(I8),
- ty::TyInt(ast::IntTy::I16) => Primitive(I16),
- ty::TyInt(ast::IntTy::I32) => Primitive(I32),
- ty::TyInt(ast::IntTy::I64) => Primitive(I64),
- ty::TyUint(ast::UintTy::Us) => Primitive(Usize),
- ty::TyUint(ast::UintTy::U8) => Primitive(U8),
- ty::TyUint(ast::UintTy::U16) => Primitive(U16),
- ty::TyUint(ast::UintTy::U32) => Primitive(U32),
- ty::TyUint(ast::UintTy::U64) => Primitive(U64),
- ty::TyFloat(ast::FloatTy::F32) => Primitive(F32),
- ty::TyFloat(ast::FloatTy::F64) => Primitive(F64),
- ty::TyStr => Primitive(Str),
+ ty::TyBool => Primitive(PrimitiveType::Bool),
+ ty::TyChar => Primitive(PrimitiveType::Char),
+ ty::TyInt(int_ty) => Primitive(int_ty.into()),
+ ty::TyUint(uint_ty) => Primitive(uint_ty.into()),
+ ty::TyFloat(float_ty) => Primitive(float_ty.into()),
+ ty::TyStr => Primitive(PrimitiveType::Str),
ty::TyBox(t) => {
let box_did = cx.tcx_opt().and_then(|tcx| {
tcx.lang_items.owned_box()
}
};
let did = match primitive {
- Isize => tcx.lang_items.isize_impl(),
- I8 => tcx.lang_items.i8_impl(),
- I16 => tcx.lang_items.i16_impl(),
- I32 => tcx.lang_items.i32_impl(),
- I64 => tcx.lang_items.i64_impl(),
- Usize => tcx.lang_items.usize_impl(),
- U8 => tcx.lang_items.u8_impl(),
- U16 => tcx.lang_items.u16_impl(),
- U32 => tcx.lang_items.u32_impl(),
- U64 => tcx.lang_items.u64_impl(),
- F32 => tcx.lang_items.f32_impl(),
- F64 => tcx.lang_items.f64_impl(),
- Char => tcx.lang_items.char_impl(),
- Bool => None,
- Str => tcx.lang_items.str_impl(),
- Slice => tcx.lang_items.slice_impl(),
- Array => tcx.lang_items.slice_impl(),
- PrimitiveTuple => None,
- PrimitiveRawPointer => tcx.lang_items.const_ptr_impl(),
+ PrimitiveType::Isize => tcx.lang_items.isize_impl(),
+ PrimitiveType::I8 => tcx.lang_items.i8_impl(),
+ PrimitiveType::I16 => tcx.lang_items.i16_impl(),
+ PrimitiveType::I32 => tcx.lang_items.i32_impl(),
+ PrimitiveType::I64 => tcx.lang_items.i64_impl(),
+ PrimitiveType::Usize => tcx.lang_items.usize_impl(),
+ PrimitiveType::U8 => tcx.lang_items.u8_impl(),
+ PrimitiveType::U16 => tcx.lang_items.u16_impl(),
+ PrimitiveType::U32 => tcx.lang_items.u32_impl(),
+ PrimitiveType::U64 => tcx.lang_items.u64_impl(),
+ PrimitiveType::F32 => tcx.lang_items.f32_impl(),
+ PrimitiveType::F64 => tcx.lang_items.f64_impl(),
+ PrimitiveType::Char => tcx.lang_items.char_impl(),
+ PrimitiveType::Bool => None,
+ PrimitiveType::Str => tcx.lang_items.str_impl(),
+ PrimitiveType::Slice => tcx.lang_items.slice_impl(),
+ PrimitiveType::Array => tcx.lang_items.slice_impl(),
+ PrimitiveType::Tuple => None,
+ PrimitiveType::RawPointer => tcx.lang_items.const_ptr_impl(),
};
if let Some(did) = did {
if !did.is_local() {
let is_generic = match def {
Def::PrimTy(p) => match p {
- hir::TyStr => return Primitive(Str),
- hir::TyBool => return Primitive(Bool),
- hir::TyChar => return Primitive(Char),
- hir::TyInt(ast::IntTy::Is) => return Primitive(Isize),
- hir::TyInt(ast::IntTy::I8) => return Primitive(I8),
- hir::TyInt(ast::IntTy::I16) => return Primitive(I16),
- hir::TyInt(ast::IntTy::I32) => return Primitive(I32),
- hir::TyInt(ast::IntTy::I64) => return Primitive(I64),
- hir::TyUint(ast::UintTy::Us) => return Primitive(Usize),
- hir::TyUint(ast::UintTy::U8) => return Primitive(U8),
- hir::TyUint(ast::UintTy::U16) => return Primitive(U16),
- hir::TyUint(ast::UintTy::U32) => return Primitive(U32),
- hir::TyUint(ast::UintTy::U64) => return Primitive(U64),
- hir::TyFloat(ast::FloatTy::F32) => return Primitive(F32),
- hir::TyFloat(ast::FloatTy::F64) => return Primitive(F64),
+ hir::TyStr => return Primitive(PrimitiveType::Str),
+ hir::TyBool => return Primitive(PrimitiveType::Bool),
+ hir::TyChar => return Primitive(PrimitiveType::Char),
+ hir::TyInt(int_ty) => return Primitive(int_ty.into()),
+ hir::TyUint(uint_ty) => return Primitive(uint_ty.into()),
+ hir::TyFloat(float_ty) => return Primitive(float_ty.into()),
},
Def::SelfTy(..) if path.segments.len() == 1 => {
return Generic(keywords::SelfType.name().to_string());
use syntax::abi::Abi;
use rustc::hir;
-use clean;
+use clean::{self, PrimitiveType};
use core::DocAccessLevels;
use html::item_type::ItemType;
use html::escape::Escape;
}
clean::Tuple(ref typs) => {
match &typs[..] {
- &[] => primitive_link(f, clean::PrimitiveTuple, "()"),
+ &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
&[ref one] => {
- primitive_link(f, clean::PrimitiveTuple, "(")?;
+ primitive_link(f, PrimitiveType::Tuple, "(")?;
write!(f, "{},", one)?;
- primitive_link(f, clean::PrimitiveTuple, ")")
+ primitive_link(f, PrimitiveType::Tuple, ")")
}
many => {
- primitive_link(f, clean::PrimitiveTuple, "(")?;
+ primitive_link(f, PrimitiveType::Tuple, "(")?;
write!(f, "{}", CommaSep(&many))?;
- primitive_link(f, clean::PrimitiveTuple, ")")
+ primitive_link(f, PrimitiveType::Tuple, ")")
}
}
}
clean::Vector(ref t) => {
- primitive_link(f, clean::Slice, &format!("["))?;
+ primitive_link(f, PrimitiveType::Slice, &format!("["))?;
write!(f, "{}", t)?;
- primitive_link(f, clean::Slice, &format!("]"))
+ primitive_link(f, PrimitiveType::Slice, &format!("]"))
}
clean::FixedVector(ref t, ref s) => {
- primitive_link(f, clean::PrimitiveType::Array, "[")?;
+ primitive_link(f, PrimitiveType::Array, "[")?;
write!(f, "{}", t)?;
- primitive_link(f, clean::PrimitiveType::Array,
+ primitive_link(f, PrimitiveType::Array,
&format!("; {}]", Escape(s)))
}
clean::Never => f.write_str("!"),
clean::RawPointer(m, ref t) => {
match **t {
clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
- primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
+ primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}{}", RawMutableSpace(m), t))
}
_ => {
- primitive_link(f, clean::PrimitiveType::PrimitiveRawPointer,
+ primitive_link(f, clean::PrimitiveType::RawPointer,
&format!("*{}", RawMutableSpace(m)))?;
write!(f, "{}", t)
}
clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
match **bt {
clean::Generic(_) =>
- primitive_link(f, clean::Slice,
+ primitive_link(f, PrimitiveType::Slice,
&format!("&{}{}[{}]", lt, m, **bt)),
_ => {
- primitive_link(f, clean::Slice, &format!("&{}{}[", lt, m))?;
+ primitive_link(f, PrimitiveType::Slice,
+ &format!("&{}{}[", lt, m))?;
write!(f, "{}", **bt)?;
- primitive_link(f, clean::Slice, "]")
+ primitive_link(f, PrimitiveType::Slice, "]")
}
}
}
Macro,
}
-impl ItemType {
- pub fn from_item(item: &clean::Item) -> ItemType {
+impl<'a> From<&'a clean::Item> for ItemType {
+ fn from(item: &'a clean::Item) -> ItemType {
let inner = match item.inner {
clean::StrippedItem(box ref item) => item,
ref inner@_ => inner,
clean::StrippedItem(..) => unreachable!(),
}
}
+}
- pub fn from_type_kind(kind: clean::TypeKind) -> ItemType {
+impl From<clean::TypeKind> for ItemType {
+ fn from(kind: clean::TypeKind) -> ItemType {
match kind {
clean::TypeStruct => ItemType::Struct,
clean::TypeEnum => ItemType::Enum,
clean::TypeTypedef => ItemType::Typedef,
}
}
+}
+impl ItemType {
pub fn css_class(&self) -> &'static str {
match *self {
ItemType::Module => "mod",
} = renderinfo;
let external_paths = external_paths.into_iter()
- .map(|(k, (v, t))| (k, (v, ItemType::from_type_kind(t))))
+ .map(|(k, (v, t))| (k, (v, ItemType::from(t))))
.collect();
let mut cache = Cache {
/// Returns a documentation-level item type from the item.
fn item_type(item: &clean::Item) -> ItemType {
- ItemType::from_item(item)
+ ItemType::from(item)
}
/// Takes a path to a source file and cleans the path to it. This canonicalizes
// Register any generics to their corresponding string. This is used
// when pretty-printing types
- match item.inner {
- clean::StructItem(ref s) => self.generics(&s.generics),
- clean::EnumItem(ref e) => self.generics(&e.generics),
- clean::FunctionItem(ref f) => self.generics(&f.generics),
- clean::TypedefItem(ref t, _) => self.generics(&t.generics),
- clean::TraitItem(ref t) => self.generics(&t.generics),
- clean::ImplItem(ref i) => self.generics(&i.generics),
- clean::TyMethodItem(ref i) => self.generics(&i.generics),
- clean::MethodItem(ref i) => self.generics(&i.generics),
- clean::ForeignFunctionItem(ref f) => self.generics(&f.generics),
- _ => {}
+ if let Some(generics) = item.inner.generics() {
+ self.generics(generics);
}
if !self.seen_mod {
// these modules are recursed into, but not rendered normally
// (a flag on the context).
if !self.render_redirect_pages {
- self.render_redirect_pages = self.maybe_ignore_item(&item);
+ self.render_redirect_pages = maybe_ignore_item(&item);
}
if item.is_mod() {
// BTreeMap instead of HashMap to get a sorted output
let mut map = BTreeMap::new();
for item in &m.items {
- if self.maybe_ignore_item(item) { continue }
+ if maybe_ignore_item(item) { continue }
let short = item_type(item).css_class();
let myname = match item.name {
}
return map;
}
-
- fn maybe_ignore_item(&self, it: &clean::Item) -> bool {
- match it.inner {
- clean::StrippedItem(..) => true,
- clean::ModuleItem(ref m) => {
- it.doc_value().is_none() && m.items.is_empty()
- && it.visibility != Some(clean::Public)
- },
- _ => false,
- }
- }
}
impl<'a> Item<'a> {
if let clean::DefaultImplItem(..) = items[*i].inner {
return false;
}
- !cx.maybe_ignore_item(&items[*i])
+ !maybe_ignore_item(&items[*i])
}).collect::<Vec<usize>>();
// the order of item types in the listing
Ok(())
}
+fn maybe_ignore_item(it: &clean::Item) -> bool {
+ match it.inner {
+ clean::StrippedItem(..) => true,
+ clean::ModuleItem(ref m) => {
+ it.doc_value().is_none() && m.items.is_empty()
+ && it.visibility != Some(clean::Public)
+ },
+ _ => false,
+ }
+}
+
fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<String> {
let mut stability = vec![];
#![stable(feature = "rust1", since = "1.0.0")]
-use prelude::v1::*;
-
use mem;
use ops::Range;
use iter::FusedIterator;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use super::*;
use char::from_u32;
#[cfg(test)]
mod test_map {
- use prelude::v1::*;
-
use super::HashMap;
use super::Entry::{Occupied, Vacant};
use cell::RefCell;
#[cfg(test)]
mod test_set {
- use prelude::v1::*;
-
use super::HashSet;
#[test]
#![stable(feature = "env", since = "1.0.0")]
-use prelude::v1::*;
-
use error::Error;
use ffi::{OsStr, OsString};
use fmt;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use super::*;
use iter::repeat;
// reconsider what crate these items belong in.
use any::TypeId;
-use boxed::Box;
use cell;
use char;
use fmt::{self, Debug, Display};
-use marker::{Send, Sync, Reflect};
+use marker::Reflect;
use mem::transmute;
use num;
-use raw::TraitObject;
use str;
-use string::{self, String};
+use string;
/// Base functionality for all errors in Rust.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
if self.is::<T>() {
unsafe {
- // Get the raw representation of the trait object
- let to: TraitObject = transmute(self);
-
- // Extract the data pointer
- Some(&*(to.data as *const T))
+ Some(&*(self as *const Error as *const T))
}
} else {
None
pub fn downcast_mut<T: Error + 'static>(&mut self) -> Option<&mut T> {
if self.is::<T>() {
unsafe {
- // Get the raw representation of the trait object
- let to: TraitObject = transmute(self);
-
- // Extract the data pointer
- Some(&mut *(to.data as *const T as *mut T))
+ Some(&mut *(self as *mut Error as *mut T))
}
} else {
None
pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Error>> {
if self.is::<T>() {
unsafe {
- // Get the raw representation of the trait object
- let raw = Box::into_raw(self);
- let to: TraitObject =
- transmute::<*mut Error, TraitObject>(raw);
-
- // Extract the data pointer
- Ok(Box::from_raw(to.data as *mut T))
+ let raw: *mut Error = Box::into_raw(self);
+ Ok(Box::from_raw(raw as *mut T))
}
} else {
Err(self)
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use super::Error;
use fmt;
// except according to those terms.
use ascii;
-use borrow::{Cow, ToOwned, Borrow};
-use boxed::Box;
-use convert::{Into, From};
-use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering};
+use borrow::{Cow, Borrow};
+use cmp::Ordering;
use error::Error;
use fmt::{self, Write};
use io;
-use iter::Iterator;
use libc;
use mem;
use memchr;
use ops;
-use option::Option::{self, Some, None};
use os::raw::c_char;
-use result::Result::{self, Ok, Err};
use slice;
use str::{self, Utf8Error};
-use string::String;
-use vec::Vec;
/// A type representing an owned C-compatible string
///
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use super::*;
use os::raw::c_char;
use borrow::Cow::{Borrowed, Owned};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use borrow::{Borrow, Cow, ToOwned};
+use borrow::{Borrow, Cow};
use fmt::{self, Debug};
use mem;
-use string::String;
use ops;
use cmp;
use hash::{Hash, Hasher};
-use vec::Vec;
use sys::os_str::{Buf, Slice};
use sys_common::{AsInner, IntoInner, FromInner};
use path::{Path, PathBuf};
use sys::fs as fs_imp;
use sys_common::{AsInnerMut, FromInner, AsInner, IntoInner};
-use vec::Vec;
use time::SystemTime;
/// A reference to an open file on the filesystem.
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use io::prelude::*;
use fs::{self, File, OpenOptions};
//! Buffering wrappers for I/O traits
-use prelude::v1::*;
use io::prelude::*;
use marker::Reflect;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use io::prelude::*;
use io::{self, BufReader, BufWriter, LineWriter, SeekFrom};
use sync::atomic::{AtomicUsize, Ordering};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use io::prelude::*;
use cmp;
mod tests {
use io::prelude::*;
use io::{Cursor, SeekFrom};
- use vec::Vec;
#[test]
fn test_vec_writer() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use boxed::Box;
-use convert::Into;
use error;
use fmt;
-use marker::{Send, Sync};
-use option::Option::{self, Some, None};
use result;
use sys;
#[cfg(test)]
mod test {
- use prelude::v1::*;
use super::{Error, ErrorKind};
use error;
use fmt;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use boxed::Box;
use cmp;
use io::{self, SeekFrom, Read, Write, Seek, BufRead, Error, ErrorKind};
use fmt;
use mem;
-use string::String;
-use vec::Vec;
// =============================================================================
// Forwarding implementations
#[cfg(test)]
mod tests {
use io::prelude::*;
- use vec::Vec;
use test;
#[bench]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use cell::Cell;
use ptr;
use sync::Arc;
use rustc_unicode::str as core_str;
use error as std_error;
use fmt;
-use iter::{Iterator};
-use marker::Sized;
-use ops::{Drop, FnOnce};
-use option::Option::{self, Some, None};
-use result::Result::{Ok, Err};
use result;
-use string::String;
use str;
-use vec::Vec;
use memchr;
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use io::prelude::*;
use io;
use super::Cursor;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use io::prelude::*;
use cell::{RefCell, BorrowState};
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use io::prelude::*;
use io::{copy, sink, empty, repeat};
#![feature(optin_builtin_traits)]
#![feature(panic_unwind)]
#![feature(placement_in_syntax)]
+#![feature(prelude_import)]
#![feature(question_mark)]
#![feature(rand)]
#![feature(raw)]
#![allow(unused_features)] // std may use features in a platform-specific way
#![cfg_attr(not(stage0), deny(warnings))]
+#[prelude_import]
+#[allow(unused)]
+use prelude::v1::*;
+
#[cfg(test)] extern crate test;
// We want to reexport a few macros from core but libcore has already been
let end_align = (ptr as usize + len) & (usize_bytes - 1);
let mut offset;
if end_align > 0 {
- offset = len - cmp::min(usize_bytes - end_align, len);
+ offset = if end_align >= len { 0 } else { len - end_align };
if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) {
return Some(offset + index);
}
fn no_match_reversed() {
assert_eq!(None, memrchr(b'a', b"xyz"));
}
+
+ #[test]
+ fn each_alignment_reversed() {
+ let mut data = [1u8; 64];
+ let needle = 2;
+ let pos = 40;
+ data[pos] = needle;
+ for start in 0..16 {
+ assert_eq!(Some(pos - start), memrchr(needle, &data[start..]));
+ }
+ }
}
#[cfg(test)]
fn no_match_reversed() {
assert_eq!(None, memrchr(b'a', b"xyz"));
}
+
+ #[test]
+ fn each_alignment() {
+ let mut data = [1u8; 64];
+ let needle = 2;
+ let pos = 40;
+ data[pos] = needle;
+ for start in 0..16 {
+ assert_eq!(Some(pos - start), memchr(needle, &data[start..]));
+ }
+ }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use fmt;
use hash;
use io;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use net::*;
use net::test::{tsa, sa6, sa4};
// Tests for this module
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use net::*;
use net::Ipv6MulticastScope::*;
use net::test::{tsa, sa6, sa4};
#![stable(feature = "rust1", since = "1.0.0")]
-use prelude::v1::*;
-
use io::{self, Error, ErrorKind};
use sys_common::net as net_imp;
//! This module is "publicly exported" through the `FromStr` implementations
//! below.
-use prelude::v1::*;
-
use error::Error;
use fmt;
use net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use io::prelude::*;
use fmt;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use io::ErrorKind;
use io::prelude::*;
use net::*;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use env;
use net::{SocketAddr, SocketAddrV4, SocketAddrV6, Ipv4Addr, Ipv6Addr, ToSocketAddrs};
use sync::atomic::{AtomicUsize, Ordering};
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use io::ErrorKind;
use net::*;
use net::test::{next_test_ip4, next_test_ip6};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::num::Wrapping;
-#[cfg(test)] use cmp::PartialEq;
#[cfg(test)] use fmt;
-#[cfg(test)] use marker::Copy;
#[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem};
/// Helper function for testing numeric operations
use u32;
use u64;
use usize;
- use string::ToString;
use ops::Mul;
#[test]
mod bench {
extern crate test;
use self::test::Bencher;
- use prelude::v1::*;
#[bench]
fn bench_pow_function(b: &mut Bencher) {
#![stable(feature = "std_panic", since = "1.9.0")]
use any::Any;
-use boxed::Box;
use cell::UnsafeCell;
use ops::{Deref, DerefMut};
use panicking;
//! * Executing a panic up to doing the actual implementation
//! * Shims around "try"
-use prelude::v1::*;
use io::prelude::*;
use any::Any;
#![stable(feature = "rust1", since = "1.0.0")]
use ascii::*;
-use borrow::{Borrow, ToOwned, Cow};
+use borrow::{Borrow, Cow};
use cmp;
use error::Error;
use fmt;
use iter::{self, FusedIterator};
use mem;
use ops::{self, Deref};
-use string::String;
-use vec::Vec;
use ffi::{OsStr, OsString};
#[cfg(test)]
mod tests {
use super::*;
- use string::{ToString, String};
- use vec::Vec;
macro_rules! t(
($path:expr, iter: $iter:expr) => (
#![stable(feature = "process", since = "1.0.0")]
-use prelude::v1::*;
use io::prelude::*;
use ffi::OsStr;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use io::prelude::*;
use io::ErrorKind;
#[cfg(not(test))]
#[lang = "start"]
fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize {
- use borrow::ToOwned;
use mem;
use panic;
use sys;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use sync::{Arc, Barrier};
use sync::mpsc::{channel, TryRecvError};
use thread;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use sync::atomic::{AtomicUsize, Ordering};
use sync::{mutex, MutexGuard, PoisonError};
use sys_common::condvar as sys;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use sync::mpsc::channel;
use sync::{Condvar, Mutex, Arc};
use thread;
use thread::{self, Thread};
use sync::atomic::{AtomicBool, Ordering};
use sync::Arc;
-use marker::{Sync, Send};
use mem;
-use clone::Clone;
use time::Instant;
struct Inner {
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use env;
use super::*;
use thread;
#[cfg(test)]
mod sync_tests {
- use prelude::v1::*;
-
use env;
use thread;
use super::*;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use sync::mpsc::channel;
use super::{Queue, Data, Empty, Inconsistent};
use sync::Arc;
#[cfg(test)]
#[allow(unused_imports)]
mod tests {
- use prelude::v1::*;
-
use thread;
use sync::mpsc::*;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use sync::Arc;
use super::Queue;
use thread;
pub use self::Failure::*;
use self::Blocker::*;
-use vec::Vec;
use core::mem;
use core::ptr;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use cell::UnsafeCell;
use fmt;
use marker;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use sync::mpsc::channel;
use sync::{Arc, Mutex, Condvar};
use sync::atomic::{AtomicUsize, Ordering};
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use panic;
use sync::mpsc::channel;
use thread;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use cell::UnsafeCell;
use fmt;
use marker;
mod tests {
#![allow(deprecated)] // rand
- use prelude::v1::*;
-
use rand::{self, Rng};
use sync::mpsc::channel;
use thread;
#[test]
fn test_rwlock_try_write() {
- use mem::drop;
-
let lock = RwLock::new(0isize);
let read_guard = lock.read().unwrap();
#![allow(dead_code)] // different code on OSX/linux/etc
-use vec::Vec;
-
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
target_os = "solaris",
target_os = "emscripten"))]
mod imp {
- use prelude::v1::*;
-
use libc::c_char;
use mem;
use ffi::CStr;
target_os = "ios",
target_os = "windows"))]
mod imp {
- use vec::Vec;
-
pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
}
//! Documentation can be found on the `rt::at_exit` function.
use alloc::boxed::FnBox;
-use boxed::Box;
use ptr;
use sys_common::mutex::Mutex;
-use vec::Vec;
type Queue = Vec<Box<FnBox()>>;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use sys_common;
macro_rules! t { ($a:expr, $b:expr) => ({
let mut m = Vec::new();
// <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 prelude::v1::*;
use io;
use io::ErrorKind;
use io::Read;
#[cfg(test)]
pub mod test {
- use prelude::v1::*;
use path::{Path, PathBuf};
use env;
use rand::{self, Rng};
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use io::prelude::*;
use super::*;
use io;
#![allow(missing_docs)]
-use boxed::Box;
use sync::Once;
use sys;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use marker::Sync;
use sys::mutex as imp;
/// An OS-based mutual exclusion lock.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use cmp;
use ffi::CString;
use fmt;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use super::*;
use collections::HashMap;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use fmt;
use marker;
use ops::Deref;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
use cell::RefCell;
use sync::Arc;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use alloc::boxed::FnBox;
use libc;
use sys::stack_overflow;
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
use cell::RefCell;
-use string::String;
use thread::Thread;
use thread::LocalKeyState;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use super::{Key, StaticKey};
fn assert_sync<T: Sync>() {}
use ops;
use slice;
use str;
-use string::String;
use sys_common::AsInner;
-use vec::Vec;
const UTF8_REPLACEMENT_CHARACTER: &'static [u8] = b"\xEF\xBF\xBD";
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use borrow::Cow;
use super::*;
use ffi::{OsStr, OsString};
use mem;
-use prelude::v1::*;
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
use libc;
-use prelude::v1::*;
use ascii;
use ffi::OsStr;
use fmt;
#[cfg(test)]
mod test {
- use prelude::v1::*;
use thread;
use io;
use io::prelude::*;
#![stable(feature = "rust1", since = "1.0.0")]
-use prelude::v1::*;
-
use io;
use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
use process;
#![unstable(reason = "not public", issue = "0", feature = "fd")]
-use prelude::v1::*;
-
use io::{self, Read};
use libc::{self, c_int, size_t, c_void};
use mem;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use os::unix::prelude::*;
use ffi::{CString, CStr, OsString, OsStr};
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
#[cfg(target_os = "linux")]
fn get_path(fd: c_int) -> Option<PathBuf> {
- use string::ToString;
let mut p = PathBuf::from("/proc/self/fd");
p.push(&fd.to_string());
readlink(&p).ok()
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use ffi::CStr;
use io;
use libc::{self, c_int, size_t, sockaddr, socklen_t};
#![allow(unused_imports)] // lots of cfg code here
-use prelude::v1::*;
use os::unix::prelude::*;
use error::Error as StdError;
use borrow::Cow;
use fmt::{self, Debug};
-use vec::Vec;
use str;
-use string::String;
use mem;
use sys_common::{AsInner, IntoInner};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use cmp;
use io;
use libc::{self, c_int};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use os::unix::prelude::*;
use collections::hash_map::{HashMap, Entry};
#[cfg(test)]
mod tests {
use super::*;
- use prelude::v1::*;
use ffi::OsStr;
use mem;
pub use self::imp::OsRng;
-#[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd")))]
+use mem;
+
+fn next_u32(mut fill_buf: &mut FnMut(&mut [u8])) -> u32 {
+ let mut buf: [u8; 4] = [0; 4];
+ fill_buf(&mut buf);
+ unsafe { mem::transmute::<[u8; 4], u32>(buf) }
+}
+
+fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 {
+ let mut buf: [u8; 8] = [0; 8];
+ fill_buf(&mut buf);
+ unsafe { mem::transmute::<[u8; 8], u64>(buf) }
+}
+
+#[cfg(all(unix,
+ not(target_os = "ios"),
+ not(target_os = "openbsd"),
+ not(target_os = "freebsd")))]
mod imp {
use self::OsRngInner::*;
+ use super::{next_u32, next_u64};
use fs::File;
use io;
use libc;
- use mem;
use rand::Rng;
use rand::reader::ReaderRng;
use sys::os::errno;
}
}
- fn getrandom_next_u32() -> u32 {
- let mut buf: [u8; 4] = [0; 4];
- getrandom_fill_bytes(&mut buf);
- unsafe { mem::transmute::<[u8; 4], u32>(buf) }
- }
-
- fn getrandom_next_u64() -> u64 {
- let mut buf: [u8; 8] = [0; 8];
- getrandom_fill_bytes(&mut buf);
- unsafe { mem::transmute::<[u8; 8], u64>(buf) }
- }
-
#[cfg(all(target_os = "linux",
any(target_arch = "x86_64",
target_arch = "x86",
impl Rng for OsRng {
fn next_u32(&mut self) -> u32 {
match self.inner {
- OsGetrandomRng => getrandom_next_u32(),
+ OsGetrandomRng => next_u32(&mut getrandom_fill_bytes),
OsReaderRng(ref mut rng) => rng.next_u32(),
}
}
fn next_u64(&mut self) -> u64 {
match self.inner {
- OsGetrandomRng => getrandom_next_u64(),
+ OsGetrandomRng => next_u64(&mut getrandom_fill_bytes),
OsReaderRng(ref mut rng) => rng.next_u64(),
}
}
#[cfg(target_os = "openbsd")]
mod imp {
+ use super::{next_u32, next_u64};
+
use io;
use libc;
- use mem;
use sys::os::errno;
use rand::Rng;
impl Rng for OsRng {
fn next_u32(&mut self) -> u32 {
- let mut v = [0; 4];
- self.fill_bytes(&mut v);
- unsafe { mem::transmute(v) }
+ next_u32(&mut |v| self.fill_bytes(v))
}
fn next_u64(&mut self) -> u64 {
- let mut v = [0; 8];
- self.fill_bytes(&mut v);
- unsafe { mem::transmute(v) }
+ next_u64(&mut |v| self.fill_bytes(v))
}
fn fill_bytes(&mut self, v: &mut [u8]) {
// getentropy(2) permits a maximum buffer size of 256 bytes
#[cfg(target_os = "ios")]
mod imp {
+ use super::{next_u32, next_u64};
+
use io;
- use mem;
use ptr;
use rand::Rng;
use libc::{c_int, size_t};
impl Rng for OsRng {
fn next_u32(&mut self) -> u32 {
- let mut v = [0; 4];
- self.fill_bytes(&mut v);
- unsafe { mem::transmute(v) }
+ next_u32(&mut |v| self.fill_bytes(v))
}
fn next_u64(&mut self) -> u64 {
- let mut v = [0; 8];
- self.fill_bytes(&mut v);
- unsafe { mem::transmute(v) }
+ next_u64(&mut |v| self.fill_bytes(v))
}
fn fill_bytes(&mut self, v: &mut [u8]) {
let ret = unsafe {
}
}
}
+
+#[cfg(target_os = "freebsd")]
+mod imp {
+ use super::{next_u32, next_u64};
+
+ use io;
+ use libc;
+ use rand::Rng;
+ use ptr;
+
+ pub struct OsRng {
+ // dummy field to ensure that this struct cannot be constructed outside
+ // of this module
+ _dummy: (),
+ }
+
+ impl OsRng {
+ /// Create a new `OsRng`.
+ pub fn new() -> io::Result<OsRng> {
+ Ok(OsRng { _dummy: () })
+ }
+ }
+
+ impl Rng for OsRng {
+ fn next_u32(&mut self) -> u32 {
+ next_u32(&mut |v| self.fill_bytes(v))
+ }
+ fn next_u64(&mut self) -> u64 {
+ next_u64(&mut |v| self.fill_bytes(v))
+ }
+ fn fill_bytes(&mut self, v: &mut [u8]) {
+ let mib = [libc::CTL_KERN, libc::KERN_ARND];
+ // kern.arandom permits a maximum buffer size of 256 bytes
+ for s in v.chunks_mut(256) {
+ let mut s_len = s.len();
+ let ret = unsafe {
+ libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
+ s.as_mut_ptr() as *mut _, &mut s_len,
+ ptr::null(), 0)
+ };
+ if ret == -1 || s_len != s.len() {
+ panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
+ ret, s.len(), s_len);
+ }
+ }
+ }
+ }
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use io;
use libc;
use sys::fd::FileDesc;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use alloc::boxed::FnBox;
use cmp;
use ffi::CStr;
target_os = "solaris"))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
- use prelude::v1::*;
-
use libc;
use libc::mmap;
use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
//! manner we pay a semi-large one-time cost up front for detecting whether a
//! function is available but afterwards it's just a load and a jump.
-use prelude::v1::*;
-
use ffi::CString;
use sync::atomic::{AtomicUsize, Ordering};
use sys::c;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use os::windows::prelude::*;
use ffi::{CString, OsStr};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use os::windows::prelude::*;
use ffi::OsString;
#![unstable(issue = "0", feature = "windows_handle")]
-use prelude::v1::*;
-
use cmp;
use io::{ErrorKind, Read};
use io;
#![allow(missing_docs, bad_style)]
-use prelude::v1::*;
-
use ffi::{OsStr, OsString};
use io::{self, ErrorKind};
use os::windows::ffi::{OsStrExt, OsStringExt};
//! CriticalSection is used and we keep track of who's holding the mutex to
//! detect recursive locks.
-use prelude::v1::*;
-
use cell::UnsafeCell;
use mem;
use sync::atomic::{AtomicUsize, Ordering};
#![unstable(issue = "0", feature = "windows_net")]
-use prelude::v1::*;
-
use cmp;
use io::{self, Read};
use libc::{c_int, c_void, c_ulong};
#![allow(bad_style)]
-use prelude::v1::*;
use os::windows::prelude::*;
use error::Error as StdError;
use borrow::Cow;
use fmt::{self, Debug};
use sys_common::wtf8::{Wtf8, Wtf8Buf};
-use string::String;
-use result::Result;
-use option::Option;
use mem;
use sys_common::{AsInner, IntoInner};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
use os::windows::prelude::*;
use ffi::OsStr;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use ascii::*;
use collections::HashMap;
use collections;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
use ffi::{OsStr, OsString};
use super::make_command_line;
#![unstable(issue = "0", feature = "windows_stdio")]
-use prelude::v1::*;
use io::prelude::*;
use cmp;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use alloc::boxed::FnBox;
use io;
use ffi::CStr;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use prelude::v1::*;
-
use ptr;
use sys::c;
use sys_common::mutex::Mutex;
// Due to rust-lang/rust#18804, make sure this is not generic!
#[cfg(target_os = "linux")]
unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
- use prelude::v1::*;
use mem;
use libc;
use sys_common::thread_local as os;
#[doc(hidden)]
pub mod os {
- use prelude::v1::*;
-
use cell::{Cell, UnsafeCell};
use marker;
use ptr;
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use sync::mpsc::{channel, Sender};
use cell::{Cell, UnsafeCell};
use super::LocalKeyState;
#[cfg(test)]
mod dynamic_tests {
- use prelude::v1::*;
-
use cell::RefCell;
use collections::HashMap;
#![stable(feature = "rust1", since = "1.0.0")]
-use prelude::v1::*;
-
use any::Any;
use cell::UnsafeCell;
use ffi::{CStr, CString};
#[cfg(test)]
mod tests {
- use prelude::v1::*;
-
use any::Any;
use sync::mpsc::{channel, Sender};
use result;
#[test]
fn test_spawn_sched() {
- use clone::Clone;
-
let (tx, rx) = channel();
fn f(i: i32, tx: Sender<()>) {
pub fn expand_type(t: P<ast::Ty>, fld: &mut MacroExpander) -> P<ast::Ty> {
let t = match t.node.clone() {
ast::TyKind::Mac(mac) => {
- if fld.cx.ecfg.features.unwrap().type_macros {
- expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
- } else {
- feature_gate::emit_feature_err(
- &fld.cx.parse_sess.span_diagnostic,
- "type_macros",
- t.span,
- feature_gate::GateIssue::Language,
- "type macros are experimental");
-
- DummyResult::raw_ty(t.span)
- }
+ expand_mac_invoc(mac, None, Vec::new(), t.span, fld)
}
_ => t
};
// Allows associated type defaults
(active, associated_type_defaults, "1.2.0", Some(29661)),
- // Allows macros to appear in the type position.
- (active, type_macros, "1.3.0", Some(27245)),
-
// allow `repr(simd)`, and importing the various simd intrinsics
(active, repr_simd, "1.4.0", Some(27731)),
// mean anything
(accepted, test_accepted_feature, "1.0.0", None),
(accepted, tuple_indexing, "1.0.0", None),
+ // Allows macros to appear in the type position.
+ (accepted, type_macros, "1.13.0", Some(27245)),
(accepted, while_let, "1.0.0", None),
// Allows `#[deprecated]` attribute
(accepted, deprecated, "1.9.0", Some(29935))
if !self.eat(&token::OpenDelim(token::Brace)) {
let sp = self.span;
let tok = self.this_token_to_string();
- return Err(self.span_fatal_help(sp,
- &format!("expected `{{`, found `{}`", tok),
- "place this code inside a block"));
+ let mut e = self.span_fatal(sp, &format!("expected `{{`, found `{}`", tok));
+
+ // Check to see if the user has written something like
+ //
+ // if (cond)
+ // bar;
+ //
+ // Which is valid in other languages, but not Rust.
+ match self.parse_stmt_without_recovery(false) {
+ Ok(Some(stmt)) => {
+ let mut stmt_span = stmt.span;
+ // expand the span to include the semicolon, if it exists
+ if self.eat(&token::Semi) {
+ stmt_span.hi = self.last_span.hi;
+ }
+ e.span_help(stmt_span, "try placing this code inside a block");
+ }
+ Err(mut e) => {
+ self.recover_stmt_(SemiColonMode::Break);
+ e.cancel();
+ }
+ _ => ()
+ }
+ return Err(e);
}
self.parse_block_tail(lo, BlockCheckMode::Default)
));
}
+extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateLexicalBlockFile(
+ LLVMRustDIBuilderRef Builder,
+ LLVMRustMetadataRef Scope,
+ LLVMRustMetadataRef File) {
+ return wrap(Builder->createLexicalBlockFile(
+ unwrapDI<DIDescriptor>(Scope),
+ unwrapDI<DIFile>(File)));
+}
+
extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateStaticVariable(
LLVMRustDIBuilderRef Builder,
LLVMRustMetadataRef Context,
}
fn main() {
- some_func(5i32); //~ ERROR E0277
+ some_func(5i32);
+ //~^ ERROR the trait bound `i32: Foo` is not satisfied
+ //~| NOTE trait `i32: Foo` not satisfied
+ //~| NOTE required by `some_func`
}
let mut fancy = FancyNum{ num: 5 };
let fancy_ref = &(&mut fancy);
fancy_ref.num = 6; //~ ERROR E0389
+ //~^ NOTE assignment into an immutable reference
println!("{}", fancy_ref.num);
}
fn ice<A>(a: A) {
let r = loop {};
r = r + a;
- //~^ ERROR E0277
+ //~^ ERROR the trait bound `(): Add<A>` is not satisfied
+ //~| NOTE trait `(): Add<A>` not satisfied
}
let _ = v as *const [u8]; //~ ERROR cannot cast
let _ = fat_v as *const Foo;
//~^ ERROR the trait bound `[u8]: std::marker::Sized` is not satisfied
+ //~| NOTE trait `[u8]: std::marker::Sized` not satisfied
//~| NOTE `[u8]` does not have a constant size known at compile-time
//~| NOTE required for the cast to the object type `Foo`
let _ = foo as *const str; //~ ERROR casting
let a : *const str = "hello";
let _ = a as *const Foo;
//~^ ERROR the trait bound `str: std::marker::Sized` is not satisfied
+ //~| NOTE trait `str: std::marker::Sized` not satisfied
//~| NOTE `str` does not have a constant size known at compile-time
//~| NOTE required for the cast to the object type `Foo`
const CONST_0: Debug+Sync = *(&0 as &(Debug+Sync));
//~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied
+//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size
const CONST_FOO: str = *"foo";
//~^ ERROR `str: std::marker::Sized` is not satisfied
+//~| NOTE `str: std::marker::Sized` not satisfied
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size
static STATIC_1: Debug+Sync = *(&1 as &(Debug+Sync));
//~^ ERROR `std::fmt::Debug + Sync + 'static: std::marker::Sized` is not satisfied
+//~| NOTE `std::fmt::Debug + Sync + 'static: std::marker::Sized` not satisfied
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size
static STATIC_BAR: str = *"bar";
//~^ ERROR `str: std::marker::Sized` is not satisfied
+//~| NOTE `str: std::marker::Sized` not satisfied
//~| NOTE does not have a constant size known at compile-time
//~| NOTE constant expressions must have a statically known size
fn main() {
send(before());
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+ //~| NOTE trait `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` not satisfied
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `[closure
//~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
send(after());
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+ //~| NOTE trait `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` not satisfied
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `[closure
//~| NOTE required because it appears within the type `impl std::ops::Fn<(i32,)>`
fn cycle1() -> impl Clone {
send(cycle2().clone());
//~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
+ //~| NOTE trait `std::rc::Rc<std::string::String>: std::marker::Send` not satisfied
//~| NOTE `std::rc::Rc<std::string::String>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `impl std::clone::Clone`
//~| NOTE required by `send`
fn cycle2() -> impl Clone {
send(cycle1().clone());
//~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
+ //~| NOTE trait `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` not satisfied
//~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
//~| NOTE required because it appears within the type `impl std::clone::Clone`
//~| NOTE required by `send`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(type_macros)]
-
macro_rules! t {
() => ( String ; ); //~ ERROR macro expansion ignores token `;`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(type_macros, concat_idents)]
+#![feature(concat_idents)]
#[derive(Debug)] //~ NOTE in this expansion
struct Baz<T>(
--- /dev/null
+// Copyright 2016 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(conservative_impl_trait)]
+
+trait Foo {
+ fn foo(fn(u8) -> ()); //~ NOTE type in trait
+ fn bar(Option<u8>); //~ NOTE type in trait
+ fn baz((u8, u16)); //~ NOTE type in trait
+ fn qux() -> u8; //~ NOTE type in trait
+}
+
+struct Bar;
+
+impl Foo for Bar {
+ fn foo(_: fn(u16) -> ()) {}
+ //~^ ERROR method `foo` has an incompatible type for trait
+ //~| NOTE expected u8
+ fn bar(_: Option<u16>) {}
+ //~^ ERROR method `bar` has an incompatible type for trait
+ //~| NOTE expected u8
+ fn baz(_: (u16, u16)) {}
+ //~^ ERROR method `baz` has an incompatible type for trait
+ //~| NOTE expected u8
+ fn qux() -> u16 { 5u16 }
+ //~^ ERROR method `qux` has an incompatible type for trait
+ //~| NOTE expected u8
+}
+
+fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(type_macros)]
-
// (typeof used because it's surprisingly hard to find an unparsed token after a stmt)
macro_rules! m {
() => ( i ; typeof ); //~ ERROR expected expression, found reserved keyword `typeof`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(type_macros)]
-
macro_rules! foo {
($a:expr) => $a; //~ ERROR macro rhs must be delimited
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ {
+ if (foo) => {} //~ ERROR expected `{`, found `=>`
+ }
+ {
+ if (foo)
+ bar; //~ ERROR expected `{`, found `bar`
+ //^ HELP try placing this code inside a block
+ }
+}
fn main() {
Index::index(&[] as &[i32], 2u32);
//~^ ERROR E0277
+ //~| NOTE not satisfied
//~| NOTE trait message
//~| NOTE required by
Index::index(&[] as &[i32], Foo(2u32));
//~^ ERROR E0277
+ //~| NOTE not satisfied
//~| NOTE on impl for Foo
//~| NOTE required by
Index::index(&[] as &[i32], Bar(2u32));
//~^ ERROR E0277
+ //~| NOTE not satisfied
//~| NOTE on impl for Bar
//~| NOTE required by
}
#[rustc_error]
fn main() {
Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32); //~ ERROR E0277
+ //~| NOTE not satisfied
//~| NOTE a usize is required
//~| NOTE required by
}
//~^ ERROR
//~^^ NOTE a collection of type `std::option::Option<std::vec::Vec<u8>>` cannot be built from an iterator over elements of type `&u8`
//~^^^ NOTE required by `collect`
+ //~| NOTE trait `std::option::Option<std::vec::Vec<u8>>: MyFromIterator<&u8>` not satisfied
let x: String = foobar(); //~ ERROR
//~^ NOTE test error `std::string::String` with `u8` `_` `u32`
//~^^ NOTE required by `foobar`
+ //~| NOTE trait `std::string::String: Foo<u8, _, u32>` not satisfied
}
fn main() {
let x = &[1, 2, 3] as &[i32];
x[1i32]; //~ ERROR E0277
+ //~| NOTE trait `[i32]: std::ops::Index<i32>` not satisfied
//~| NOTE slice indices are of type `usize`
x[..1i32]; //~ ERROR E0277
+ //~| NOTE trait `[i32]: std::ops::Index<std::ops::RangeTo<i32>>` not satisfied
//~| NOTE slice indices are of type `usize`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(pub_restricted, type_macros)]
+#![feature(pub_restricted)]
mod foo {
type T = ();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(pub_restricted, type_macros)]
+#![feature(pub_restricted)]
macro_rules! define_struct {
($t:ty) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(pub_restricted, type_macros)]
+#![feature(pub_restricted)]
macro_rules! define_struct {
($t:ty) => {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(concat_idents, type_macros)]
+#![feature(concat_idents)]
pub fn main() {
struct Foo;
// suggest a where-clause, if needed
mem::size_of::<U>();
//~^ ERROR `U: std::marker::Sized` is not satisfied
+ //~| NOTE trait `U: std::marker::Sized` not satisfied
//~| HELP consider adding a `where U: std::marker::Sized` bound
//~| NOTE required by `std::mem::size_of`
mem::size_of::<Misc<U>>();
//~^ ERROR `U: std::marker::Sized` is not satisfied
+ //~| NOTE trait `U: std::marker::Sized` not satisfied
//~| HELP consider adding a `where U: std::marker::Sized` bound
//~| NOTE required because it appears within the type `Misc<U>`
//~| NOTE required by `std::mem::size_of`
<u64 as From<T>>::from;
//~^ ERROR `u64: std::convert::From<T>` is not satisfied
+ //~| NOTE trait `u64: std::convert::From<T>` not satisfied
//~| HELP consider adding a `where u64: std::convert::From<T>` bound
//~| NOTE required by `std::convert::From::from`
<u64 as From<<T as Iterator>::Item>>::from;
//~^ ERROR `u64: std::convert::From<<T as std::iter::Iterator>::Item>` is not satisfied
+ //~| NOTE trait `u64: std::convert::From<<T as std::iter::Iterator>::Item>` not satisfied
//~| HELP consider adding a `where u64:
//~| NOTE required by `std::convert::From::from`
<Misc<_> as From<T>>::from;
//~^ ERROR `Misc<_>: std::convert::From<T>` is not satisfied
+ //~| NOTE trait `Misc<_>: std::convert::From<T>` not satisfied
//~| NOTE required by `std::convert::From::from`
// ... and also not if the error is not related to the type
mem::size_of::<[T]>();
//~^ ERROR `[T]: std::marker::Sized` is not satisfied
+ //~| NOTE `[T]: std::marker::Sized` not satisfied
//~| NOTE `[T]` does not have a constant size
//~| NOTE required by `std::mem::size_of`
mem::size_of::<[&U]>();
//~^ ERROR `[&U]: std::marker::Sized` is not satisfied
+ //~| NOTE `[&U]: std::marker::Sized` not satisfied
//~| NOTE `[&U]` does not have a constant size
//~| NOTE required by `std::mem::size_of`
}
+++ /dev/null
-// 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.
-
-macro_rules! Id {
- ($T:tt) => ($T);
-}
-
-struct Foo<T> {
- x: Id!(T)
- //~^ ERROR: type macros are experimental (see issue #27245)
-}
-
-fn main() {
- let foo = Foo { x: i32 };
-}
}
#[rustc_variance]
-struct Foo<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[+], regions=[-])
+struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
field: (T, &'a ())
}
#[rustc_variance]
-struct Bar<'a, T : Trait<'a>> { //~ ERROR ItemVariances(types=[o], regions=[o])
+struct Bar<'a, T : Trait<'a>> { //~ ERROR [o, o]
field: <T as Trait<'a>>::Type
}
// For better or worse, associated types are invariant, and hence we
// get an invariant result for `'a`.
#[rustc_variance]
-struct Foo<'a> { //~ ERROR regions=[o]
+struct Foo<'a> { //~ ERROR [o]
x: Box<Fn(i32) -> &'a i32 + 'static>
}
#![feature(rustc_attrs)]
#[rustc_variance]
-trait Foo: 'static { //~ ERROR types=[o]
+trait Foo: 'static { //~ ERROR [o]
}
#[rustc_variance]
-trait Bar<T> { //~ ERROR types=[o, o]
+trait Bar<T> { //~ ERROR [o, o]
fn do_it(&self)
where T: 'static;
}
// Regions that just appear in normal spots are contravariant:
#[rustc_variance]
-struct Test2<'a, 'b, 'c> { //~ ERROR regions=[-, -, -]
+struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
x: &'a isize,
y: &'b [isize],
c: &'c str
// Those same annotations in function arguments become covariant:
#[rustc_variance]
-struct Test3<'a, 'b, 'c> { //~ ERROR regions=[+, +, +]
+struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
x: extern "Rust" fn(&'a isize),
y: extern "Rust" fn(&'b [isize]),
c: extern "Rust" fn(&'c str),
// Mutability induces invariance:
#[rustc_variance]
-struct Test4<'a, 'b:'a> { //~ ERROR regions=[-, o]
+struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
x: &'a mut &'b isize,
}
// contravariant context:
#[rustc_variance]
-struct Test5<'a, 'b:'a> { //~ ERROR regions=[+, o]
+struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
x: extern "Rust" fn(&'a mut &'b isize),
}
// argument list occurs in an invariant context.
#[rustc_variance]
-struct Test6<'a, 'b:'a> { //~ ERROR regions=[-, o]
+struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
x: &'a mut extern "Rust" fn(&'b isize),
}
// No uses at all is bivariant:
#[rustc_variance]
-struct Test7<'a> { //~ ERROR regions=[*]
+struct Test7<'a> { //~ ERROR [*]
//~^ ERROR parameter `'a` is never used
x: isize
}
// Try enums too.
#[rustc_variance]
-enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o]
+enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
Test8A(extern "Rust" fn(&'a isize)),
Test8B(&'b [isize]),
Test8C(&'b mut &'c str),
#![feature(rustc_attrs)]
#[rustc_variance]
-enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[+, -, o, *]
+enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
//~^ ERROR parameter `'d` is never used
Test8A(extern "Rust" fn(&'a isize)),
Test8B(&'b [isize]),
}
#[rustc_variance]
-struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[*, o, -, +]
+struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
//~^ ERROR parameter `'w` is never used
f: Base<'z, 'y, 'x, 'w>
}
#[rustc_variance] // Combine - and + to yield o
-struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[o, o, *]
+struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
//~^ ERROR parameter `'c` is never used
f: Base<'a, 'a, 'b, 'c>
}
#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
-struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[o, -, *]
+struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
//~^ ERROR parameter `'c` is never used
f: Base<'a, 'b, 'a, 'c>
}
#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
-struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[+, -, o]
+struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
f: Base<'a, 'b, 'c, 'a>
}
// influence variance.
#[rustc_variance]
-trait Getter<T> { //~ ERROR types=[o, o]
+trait Getter<T> { //~ ERROR [o, o]
fn get(&self) -> T;
}
#[rustc_variance]
-trait Setter<T> { //~ ERROR types=[o, o]
+trait Setter<T> { //~ ERROR [o, o]
fn get(&self, T);
}
#[rustc_variance]
-struct TestStruct<U,T:Setter<U>> { //~ ERROR types=[+, +]
+struct TestStruct<U,T:Setter<U>> { //~ ERROR [+, +]
t: T, u: U
}
#[rustc_variance]
-enum TestEnum<U,T:Setter<U>> {//~ ERROR types=[*, +]
+enum TestEnum<U,T:Setter<U>> {//~ ERROR [*, +]
//~^ ERROR parameter `U` is never used
Foo(T)
}
#[rustc_variance]
-trait TestTrait<U,T:Setter<U>> { //~ ERROR types=[o, o, o]
+trait TestTrait<U,T:Setter<U>> { //~ ERROR [o, o, o]
fn getter(&self, u: U) -> T;
}
#[rustc_variance]
-trait TestTrait2<U> : Getter<U> { //~ ERROR types=[o, o]
+trait TestTrait2<U> : Getter<U> { //~ ERROR [o, o]
}
#[rustc_variance]
-trait TestTrait3<U> { //~ ERROR types=[o, o]
+trait TestTrait3<U> { //~ ERROR [o, o]
fn getter<T:Getter<U>>(&self);
}
#[rustc_variance]
-struct TestContraStruct<U,T:Setter<U>> { //~ ERROR types=[*, +]
+struct TestContraStruct<U,T:Setter<U>> { //~ ERROR [*, +]
//~^ ERROR parameter `U` is never used
t: T
}
#[rustc_variance]
-struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR types=[*, +]
+struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [*, +]
//~^ ERROR parameter `U` is never used
t: T
}
trait T { fn foo(&self); }
#[rustc_variance]
-struct TOption<'a> { //~ ERROR regions=[-]
+struct TOption<'a> { //~ ERROR [-]
v: Option<Box<T + 'a>>,
}
#![feature(rustc_attrs)]
#[rustc_variance]
-struct TestImm<A, B> { //~ ERROR types=[+, +]
+struct TestImm<A, B> { //~ ERROR [+, +]
x: A,
y: B,
}
#[rustc_variance]
-struct TestMut<A, B:'static> { //~ ERROR types=[+, o]
+struct TestMut<A, B:'static> { //~ ERROR [+, o]
x: A,
y: &'static mut B,
}
#[rustc_variance]
-struct TestIndirect<A:'static, B:'static> { //~ ERROR types=[+, o]
+struct TestIndirect<A:'static, B:'static> { //~ ERROR [+, o]
m: TestMut<A, B>
}
#[rustc_variance]
-struct TestIndirect2<A:'static, B:'static> { //~ ERROR types=[o, o]
+struct TestIndirect2<A:'static, B:'static> { //~ ERROR [o, o]
n: TestMut<A, B>,
m: TestMut<B, A>
}
#[rustc_variance]
-trait Getter<A> { //~ ERROR types=[o, o]
+trait Getter<A> { //~ ERROR [o, o]
fn get(&self) -> A;
}
#[rustc_variance]
-trait Setter<A> { //~ ERROR types=[o, o]
+trait Setter<A> { //~ ERROR [o, o]
fn set(&mut self, a: A);
}
#[rustc_variance]
-trait GetterSetter<A> { //~ ERROR types=[o, o]
+trait GetterSetter<A> { //~ ERROR [o, o]
fn get(&self) -> A;
fn set(&mut self, a: A);
}
#[rustc_variance]
-trait GetterInTypeBound<A> { //~ ERROR types=[o, o]
+trait GetterInTypeBound<A> { //~ ERROR [o, o]
// Here, the use of `A` in the method bound *does* affect
// variance. Think of it as if the method requested a dictionary
// for `T:Getter<A>`. Since this dictionary is an input, it is
}
#[rustc_variance]
-trait SetterInTypeBound<A> { //~ ERROR types=[o, o]
+trait SetterInTypeBound<A> { //~ ERROR [o, o]
fn do_it<T:Setter<A>>(&self);
}
#[rustc_variance]
-struct TestObject<A, R> { //~ ERROR types=[o, o]
+struct TestObject<A, R> { //~ ERROR [o, o]
n: Box<Setter<A>+Send>,
m: Box<Getter<R>+Send>,
}
// not considered bivariant.
#[rustc_variance]
-struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR types=[o, o], regions=[-]
+struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o]
t: &'a mut (A,B)
}
#[rustc_variance]
-struct InvariantCell<A> { //~ ERROR types=[o]
+struct InvariantCell<A> { //~ ERROR [o]
t: Cell<A>
}
#[rustc_variance]
-struct InvariantIndirect<A> { //~ ERROR types=[o]
+struct InvariantIndirect<A> { //~ ERROR [o]
t: InvariantCell<A>
}
#[rustc_variance]
-struct Covariant<A> { //~ ERROR types=[+]
+struct Covariant<A> { //~ ERROR [+]
t: A, u: fn() -> A
}
#[rustc_variance]
-struct Contravariant<A> { //~ ERROR types=[-]
+struct Contravariant<A> { //~ ERROR [-]
t: fn(A)
}
#[rustc_variance]
-enum Enum<A,B,C> { //~ ERROR types=[+, -, o]
+enum Enum<A,B,C> { //~ ERROR [+, -, o]
Foo(Covariant<A>),
Bar(Contravariant<B>),
Zed(Covariant<C>,Contravariant<C>)
--- /dev/null
+// Copyright 2013-2016 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:-g
+
+#![crate_type = "rlib"]
+
+#[macro_export]
+macro_rules! new_scope {
+ () => {
+ let x = 1;
+ }
+}
// min-lldb-version: 310
-// compile-flags:-g
+// compile-flags:-g -Zdebug-macros
// === GDB TESTS ===================================================================================
--- /dev/null
+// Copyright 2013-2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-windows
+// ignore-android
+// min-lldb-version: 310
+
+// aux-build:macro-stepping.rs
+
+#![allow(unused)]
+
+#[macro_use]
+extern crate macro_stepping; // exports new_scope!()
+
+// compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+
+// gdb-command:run
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc1[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc2[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc3[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc4[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc5[...]
+// gdb-command:next
+// gdb-command:frame
+// gdb-check:[...]#loc6[...]
+
+// === LLDB TESTS ==================================================================================
+
+// lldb-command:set set stop-line-count-before 0
+// lldb-command:set set stop-line-count-after 1
+// Can't set both to zero or lldb will stop printing source at all. So it will output the current
+// line and the next. We deal with this by having at least 2 lines between the #loc's
+
+// lldb-command:run
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc1[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc2[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc3[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc4[...]
+// lldb-command:next
+// lldb-command:frame select
+// lldb-check:[...]#loc5[...]
+
+macro_rules! foo {
+ () => {
+ let a = 1;
+ let b = 2;
+ let c = 3;
+ }
+}
+
+macro_rules! foo2 {
+ () => {
+ foo!();
+ let x = 1;
+ foo!();
+ }
+}
+
+fn main() {
+ zzz(); // #break
+
+ foo!(); // #loc1
+
+ foo2!(); // #loc2
+
+ let x = vec![42]; // #loc3
+
+ new_scope!(); // #loc4
+
+ println!("Hello {}", // #loc5
+ "world");
+
+ zzz(); // #loc6
+}
+
+fn zzz() {()}
extern crate syntax;
use rustc::mir::transform::{self, MirPass, MirSource};
-use rustc::mir::repr::{Mir, Literal};
+use rustc::mir::repr::{Mir, Literal, Location};
use rustc::mir::visit::MutVisitor;
use rustc::ty::TyCtxt;
use rustc::middle::const_val::ConstVal;
struct Visitor;
impl<'tcx> MutVisitor<'tcx> for Visitor {
- fn visit_literal(&mut self, literal: &mut Literal<'tcx>) {
+ fn visit_literal(&mut self, literal: &mut Literal<'tcx>, _: Location) {
if let Literal::Value { ref mut value } = *literal {
if let ConstVal::Integral(ConstInt::I32(ref mut i @ 11)) = *value {
*i = 42;
}
fn parent() {
- let file = File::open("Makefile").unwrap();
+ let file = File::open(file!()).unwrap();
let tcp1 = TcpListener::bind("127.0.0.1:0").unwrap();
let tcp2 = tcp1.try_clone().unwrap();
let addr = tcp1.local_addr().unwrap();
--- /dev/null
+// Copyright 2016 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.
+
+const TEST_DATA: [u8; 32 * 1024 * 1024] = [42; 32 * 1024 * 1024];
+
+// Check that the promoted copy of TEST_DATA doesn't
+// leave an alloca from an unused temp behind, which,
+// without optimizations, can still blow the stack.
+fn main() {
+ println!("{}", TEST_DATA.len());
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(repr_simd, platform_intrinsics, concat_idents,
- type_macros, test)]
+#![feature(repr_simd, platform_intrinsics, concat_idents, test)]
#![allow(non_camel_case_types)]
extern crate test;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(type_macros)]
-
use std::ops::*;
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(type_macros)]
-
macro_rules! Tuple {
{ $A:ty,$B:ty } => { ($A, $B) }
}