diff --git a/mk/docs.mk b/mk/docs.mk index f202c75360bf8..6c0be654e1f5d 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -66,7 +66,7 @@ ERR_IDX_GEN_MD = $(RPATH_VAR2_T_$(CFG_BUILD)_H_$(CFG_BUILD)) $(ERR_IDX_GEN_EXE) D := $(S)src/doc -DOC_TARGETS := book nomicon style error-index +DOC_TARGETS := book nomicon error-index COMPILER_DOC_TARGETS := DOC_L10N_TARGETS := @@ -209,13 +209,6 @@ doc/nomicon/index.html: $(RUSTBOOK_EXE) $(wildcard $(S)/src/doc/nomicon/*.md) | $(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 diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index b40dbfde4a4a5..9eacb5e3924fa 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -308,10 +308,6 @@ impl Build { 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); } diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs index 8d3cb36166b70..12929664886c4 100644 --- a/src/bootstrap/step.rs +++ b/src/bootstrap/step.rs @@ -92,7 +92,6 @@ macro_rules! targets { (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 }), @@ -366,8 +365,7 @@ impl<'a> Step<'a> { 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 } => { @@ -382,8 +380,7 @@ impl<'a> Step<'a> { 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), ]; diff --git a/src/doc/style/README.md b/src/doc/style/README.md deleted file mode 100644 index 8d837d1a1a916..0000000000000 --- a/src/doc/style/README.md +++ /dev/null @@ -1,64 +0,0 @@ -% 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? diff --git a/src/doc/style/SUMMARY.md b/src/doc/style/SUMMARY.md deleted file mode 100644 index 508ede6c4a0ac..0000000000000 --- a/src/doc/style/SUMMARY.md +++ /dev/null @@ -1,50 +0,0 @@ -# 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) diff --git a/src/doc/style/errors/README.md b/src/doc/style/errors/README.md deleted file mode 100644 index 444da26ff8fed..0000000000000 --- a/src/doc/style/errors/README.md +++ /dev/null @@ -1,3 +0,0 @@ -% Errors - -> **[FIXME]** Add some general text here. diff --git a/src/doc/style/errors/ergonomics.md b/src/doc/style/errors/ergonomics.md deleted file mode 100644 index 269f2a289464a..0000000000000 --- a/src/doc/style/errors/ergonomics.md +++ /dev/null @@ -1,66 +0,0 @@ -% 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. diff --git a/src/doc/style/errors/handling.md b/src/doc/style/errors/handling.md deleted file mode 100644 index 9b8a00d73665b..0000000000000 --- a/src/doc/style/errors/handling.md +++ /dev/null @@ -1,7 +0,0 @@ -% 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] diff --git a/src/doc/style/errors/propagation.md b/src/doc/style/errors/propagation.md deleted file mode 100644 index 0a347cd577b90..0000000000000 --- a/src/doc/style/errors/propagation.md +++ /dev/null @@ -1,8 +0,0 @@ -% Propagation - -> **[FIXME]** We need guidelines on how to layer error information up a stack of -> abstractions. - -### Error interoperation [FIXME] - -> **[FIXME]** Document the `FromError` infrastructure. diff --git a/src/doc/style/errors/signaling.md b/src/doc/style/errors/signaling.md deleted file mode 100644 index 4038ec10b9ab5..0000000000000 --- a/src/doc/style/errors/signaling.md +++ /dev/null @@ -1,125 +0,0 @@ -% 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` 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. diff --git a/src/doc/style/features/README.md b/src/doc/style/features/README.md deleted file mode 100644 index 09657503d20d1..0000000000000 --- a/src/doc/style/features/README.md +++ /dev/null @@ -1,9 +0,0 @@ -% 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). diff --git a/src/doc/style/features/crates.md b/src/doc/style/features/crates.md deleted file mode 100644 index 4748b05f17f74..0000000000000 --- a/src/doc/style/features/crates.md +++ /dev/null @@ -1,6 +0,0 @@ -% Crates - -> **[FIXME]** What general guidelines should we provide for crate design? - -> Possible topics: facades; per-crate preludes (to be imported as globs); -> "lib.rs" diff --git a/src/doc/style/features/functions-and-methods/README.md b/src/doc/style/features/functions-and-methods/README.md deleted file mode 100644 index a3559ca3e7b6b..0000000000000 --- a/src/doc/style/features/functions-and-methods/README.md +++ /dev/null @@ -1,44 +0,0 @@ -% 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. diff --git a/src/doc/style/features/functions-and-methods/convenience.md b/src/doc/style/features/functions-and-methods/convenience.md deleted file mode 100644 index 69fd3772a761f..0000000000000 --- a/src/doc/style/features/functions-and-methods/convenience.md +++ /dev/null @@ -1,43 +0,0 @@ -% 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. diff --git a/src/doc/style/features/functions-and-methods/input.md b/src/doc/style/features/functions-and-methods/input.md deleted file mode 100644 index 5b63a4514443c..0000000000000 --- a/src/doc/style/features/functions-and-methods/input.md +++ /dev/null @@ -1,203 +0,0 @@ -% 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) -> Box { ... } -``` - -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>(c: T) { ... } -``` - -over any of - -```rust,ignore -fn foo(c: &[i32]) { ... } -fn foo(c: &Vec) { ... } -fn foo(c: &SomeOtherCollection) { ... } -``` - -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 -``` - -(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`? diff --git a/src/doc/style/features/functions-and-methods/output.md b/src/doc/style/features/functions-and-methods/output.md deleted file mode 100644 index e26eee53367cf..0000000000000 --- a/src/doc/style/features/functions-and-methods/output.md +++ /dev/null @@ -1,56 +0,0 @@ -% 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) -> Result> -``` - -over - -```rust,ignore -fn from_utf8_owned(vv: Vec) -> Option -``` - -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. diff --git a/src/doc/style/features/let.md b/src/doc/style/features/let.md deleted file mode 100644 index ba9787b45f13c..0000000000000 --- a/src/doc/style/features/let.md +++ /dev/null @@ -1,103 +0,0 @@ -% Let binding - -### Always separately bind RAII guards. [FIXME: needs RFC] - -Prefer - -```rust,ignore -fn use_mutex(m: sync::mutex::Mutex) { - 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) { - 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::>(); -``` - -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. diff --git a/src/doc/style/features/loops.md b/src/doc/style/features/loops.md deleted file mode 100644 index b144825f98183..0000000000000 --- a/src/doc/style/features/loops.md +++ /dev/null @@ -1,13 +0,0 @@ -% 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` diff --git a/src/doc/style/features/match.md b/src/doc/style/features/match.md deleted file mode 100644 index 0d5a1184a0e87..0000000000000 --- a/src/doc/style/features/match.md +++ /dev/null @@ -1,26 +0,0 @@ -% Pattern matching - -### Dereference `match` targets when possible. [FIXME: needs RFC] - -Prefer - -~~~~ignore -match *foo { - X(...) => ... - Y(...) => ... -} -~~~~ - -over - -~~~~ignore -match foo { - box X(...) => ... - box Y(...) => ... -} -~~~~ - - - - - diff --git a/src/doc/style/features/modules.md b/src/doc/style/features/modules.md deleted file mode 100644 index 995c5fda8a0aa..0000000000000 --- a/src/doc/style/features/modules.md +++ /dev/null @@ -1,133 +0,0 @@ -% 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. diff --git a/src/doc/style/features/traits/README.md b/src/doc/style/features/traits/README.md deleted file mode 100644 index 1893db24466fa..0000000000000 --- a/src/doc/style/features/traits/README.md +++ /dev/null @@ -1,22 +0,0 @@ -% 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. diff --git a/src/doc/style/features/traits/common.md b/src/doc/style/features/traits/common.md deleted file mode 100644 index e8699c75229d3..0000000000000 --- a/src/doc/style/features/traits/common.md +++ /dev/null @@ -1,71 +0,0 @@ -% 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. diff --git a/src/doc/style/features/traits/extensions.md b/src/doc/style/features/traits/extensions.md deleted file mode 100644 index fc3a03c01f5a1..0000000000000 --- a/src/doc/style/features/traits/extensions.md +++ /dev/null @@ -1,7 +0,0 @@ -% Using traits to add extension methods - -> **[FIXME]** Elaborate. - -### Consider using default methods rather than extension traits **[FIXME]** - -> **[FIXME]** Elaborate. diff --git a/src/doc/style/features/traits/generics.md b/src/doc/style/features/traits/generics.md deleted file mode 100644 index f9dac1272c334..0000000000000 --- a/src/doc/style/features/traits/generics.md +++ /dev/null @@ -1,67 +0,0 @@ -% 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>(iterator: T) -> SomeCollection -``` - -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(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` 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. diff --git a/src/doc/style/features/traits/objects.md b/src/doc/style/features/traits/objects.md deleted file mode 100644 index 34712ed1ae7f1..0000000000000 --- a/src/doc/style/features/traits/objects.md +++ /dev/null @@ -1,49 +0,0 @@ -% 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]) -> Frame { - ... - } -} - -fn make_gui() -> Box { - let b: Box = box Button::new(...); - let l: Box = box Label::new(...); - - box Frame::new([b, l]) as Box -} -``` - -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. diff --git a/src/doc/style/features/traits/overloading.md b/src/doc/style/features/traits/overloading.md deleted file mode 100644 index d7482c9619072..0000000000000 --- a/src/doc/style/features/traits/overloading.md +++ /dev/null @@ -1,7 +0,0 @@ -% 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. diff --git a/src/doc/style/features/traits/reuse.md b/src/doc/style/features/traits/reuse.md deleted file mode 100644 index feedd3937fc9d..0000000000000 --- a/src/doc/style/features/traits/reuse.md +++ /dev/null @@ -1,30 +0,0 @@ -% 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`. diff --git a/src/doc/style/features/types/README.md b/src/doc/style/features/types/README.md deleted file mode 100644 index d3b95d8a6e719..0000000000000 --- a/src/doc/style/features/types/README.md +++ /dev/null @@ -1,68 +0,0 @@ -% 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/) diff --git a/src/doc/style/features/types/conversions.md b/src/doc/style/features/types/conversions.md deleted file mode 100644 index f0f230f57e557..0000000000000 --- a/src/doc/style/features/types/conversions.md +++ /dev/null @@ -1,22 +0,0 @@ -% 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. diff --git a/src/doc/style/features/types/newtype.md b/src/doc/style/features/types/newtype.md deleted file mode 100644 index 9646e3e82aa53..0000000000000 --- a/src/doc/style/features/types/newtype.md +++ /dev/null @@ -1,69 +0,0 @@ -% 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>>`. 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(Enumerate>>); -impl Iterator<(usize, T)> for MyTransformResult { ... } - -fn my_transform>(iter: Iter) -> MyTransformResult { - ... -} -``` - -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. diff --git a/src/doc/style/ownership/README.md b/src/doc/style/ownership/README.md deleted file mode 100644 index 11bdb03a3a818..0000000000000 --- a/src/doc/style/ownership/README.md +++ /dev/null @@ -1,3 +0,0 @@ -% Ownership and resource management - -> **[FIXME]** Add general remarks about ownership/resources here. diff --git a/src/doc/style/ownership/builders.md b/src/doc/style/ownership/builders.md deleted file mode 100644 index 3422591233275..0000000000000 --- a/src/doc/style/ownership/builders.md +++ /dev/null @@ -1,176 +0,0 @@ -% 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, - cwd: Option, - // 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 { - ... - } -} -``` - -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) -> 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. diff --git a/src/doc/style/ownership/cell-smart.md b/src/doc/style/ownership/cell-smart.md deleted file mode 100644 index cd027cc4aaffc..0000000000000 --- a/src/doc/style/ownership/cell-smart.md +++ /dev/null @@ -1,4 +0,0 @@ -% Cells and smart pointers - -> **[FIXME]** Add guidelines about when to use Cell, RefCell, Rc and -> Arc (and how to use them together). diff --git a/src/doc/style/ownership/constructors.md b/src/doc/style/ownership/constructors.md deleted file mode 100644 index 51fc74ac1158a..0000000000000 --- a/src/doc/style/ownership/constructors.md +++ /dev/null @@ -1,62 +0,0 @@ -% Constructors - -### Define constructors as static, inherent methods. [FIXME: needs RFC] - -In Rust, "constructors" are just a convention: - -```rust,ignore -impl Vec { - pub fn new() -> Vec { ... } -} -``` - -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. diff --git a/src/doc/style/ownership/destructors.md b/src/doc/style/ownership/destructors.md deleted file mode 100644 index 1cfcd78d20da8..0000000000000 --- a/src/doc/style/ownership/destructors.md +++ /dev/null @@ -1,22 +0,0 @@ -% 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. diff --git a/src/doc/style/ownership/raii.md b/src/doc/style/ownership/raii.md deleted file mode 100644 index 244e8096a1a2f..0000000000000 --- a/src/doc/style/ownership/raii.md +++ /dev/null @@ -1,12 +0,0 @@ -% 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` diff --git a/src/doc/style/platform.md b/src/doc/style/platform.md deleted file mode 100644 index d29d060b69461..0000000000000 --- a/src/doc/style/platform.md +++ /dev/null @@ -1,7 +0,0 @@ -% 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. diff --git a/src/doc/style/safety/README.md b/src/doc/style/safety/README.md deleted file mode 100644 index 1ac6e704d23eb..0000000000000 --- a/src/doc/style/safety/README.md +++ /dev/null @@ -1,19 +0,0 @@ -% 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. diff --git a/src/doc/style/safety/lib-guarantees.md b/src/doc/style/safety/lib-guarantees.md deleted file mode 100644 index 8ee64f1806a69..0000000000000 --- a/src/doc/style/safety/lib-guarantees.md +++ /dev/null @@ -1,81 +0,0 @@ -% 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` 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. diff --git a/src/doc/style/safety/unsafe.md b/src/doc/style/safety/unsafe.md deleted file mode 100644 index a8a50af044c29..0000000000000 --- a/src/doc/style/safety/unsafe.md +++ /dev/null @@ -1,22 +0,0 @@ -% 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. diff --git a/src/doc/style/style/README.md b/src/doc/style/style/README.md deleted file mode 100644 index 87449710543c0..0000000000000 --- a/src/doc/style/style/README.md +++ /dev/null @@ -1,5 +0,0 @@ -% Style - -This section gives a set of strict rules for styling Rust code. - -> **[FIXME]** General remarks about the style guidelines diff --git a/src/doc/style/style/braces.md b/src/doc/style/style/braces.md deleted file mode 100644 index 80323dba1d4c2..0000000000000 --- a/src/doc/style/style/braces.md +++ /dev/null @@ -1,77 +0,0 @@ -% 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, -} -``` diff --git a/src/doc/style/style/comments.md b/src/doc/style/style/comments.md deleted file mode 100644 index af02d87cc8da8..0000000000000 --- a/src/doc/style/style/comments.md +++ /dev/null @@ -1,122 +0,0 @@ -% 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 { - // ... -} -``` diff --git a/src/doc/style/style/features.md b/src/doc/style/style/features.md deleted file mode 100644 index 13cc37fc236ca..0000000000000 --- a/src/doc/style/style/features.md +++ /dev/null @@ -1,13 +0,0 @@ -## `return` [RFC #968] - -Terminate `return` statements with semicolons: - -``` rust,ignore -fn foo(bar: i32) -> Option { - if some_condition() { - return None; - } - - ... -} -``` diff --git a/src/doc/style/style/imports.md b/src/doc/style/style/imports.md deleted file mode 100644 index c958875ddb926..0000000000000 --- a/src/doc/style/style/imports.md +++ /dev/null @@ -1,50 +0,0 @@ -% 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. diff --git a/src/doc/style/style/naming/README.md b/src/doc/style/style/naming/README.md deleted file mode 100644 index 6d88a838f5f53..0000000000000 --- a/src/doc/style/style/naming/README.md +++ /dev/null @@ -1,115 +0,0 @@ -% 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` | - -

-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` | `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. diff --git a/src/doc/style/style/naming/containers.md b/src/doc/style/style/naming/containers.md deleted file mode 100644 index c352a5b1bf191..0000000000000 --- a/src/doc/style/style/naming/containers.md +++ /dev/null @@ -1,69 +0,0 @@ -% 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 - -// Lookup element, failing if it is not found: -impl Index for Container { ... } -impl IndexMut 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`: - -```rust,ignore -// Extract contents or fail if not available -fn assert(self) -> V -fn expect(self, &str) -> V -``` - -For `Result`: - -```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 -``` diff --git a/src/doc/style/style/naming/conversions.md b/src/doc/style/style/naming/conversions.md deleted file mode 100644 index 0287919c78aae..0000000000000 --- a/src/doc/style/style/naming/conversions.md +++ /dev/null @@ -1,32 +0,0 @@ -% 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 | - -

-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`, 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? diff --git a/src/doc/style/style/naming/iterators.md b/src/doc/style/style/naming/iterators.md deleted file mode 100644 index 945cbe4800cb0..0000000000000 --- a/src/doc/style/style/naming/iterators.md +++ /dev/null @@ -1,32 +0,0 @@ -% 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 -``` - -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`. diff --git a/src/doc/style/style/naming/ownership.md b/src/doc/style/style/naming/ownership.md deleted file mode 100644 index 32cd8a1595afb..0000000000000 --- a/src/doc/style/style/naming/ownership.md +++ /dev/null @@ -1,34 +0,0 @@ -% 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. diff --git a/src/doc/style/style/optional.md b/src/doc/style/style/optional.md deleted file mode 100644 index d3c2178cc993f..0000000000000 --- a/src/doc/style/style/optional.md +++ /dev/null @@ -1,3 +0,0 @@ -* - -* diff --git a/src/doc/style/style/organization.md b/src/doc/style/style/organization.md deleted file mode 100644 index 85065406d761c..0000000000000 --- a/src/doc/style/style/organization.md +++ /dev/null @@ -1,14 +0,0 @@ -% 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. diff --git a/src/doc/style/style/whitespace.md b/src/doc/style/style/whitespace.md deleted file mode 100644 index c33c17c8e42a2..0000000000000 --- a/src/doc/style/style/whitespace.md +++ /dev/null @@ -1,133 +0,0 @@ -% 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( - 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; -``` diff --git a/src/doc/style/testing/README.md b/src/doc/style/testing/README.md deleted file mode 100644 index a21f69414d326..0000000000000 --- a/src/doc/style/testing/README.md +++ /dev/null @@ -1,5 +0,0 @@ -% 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? diff --git a/src/doc/style/testing/unit.md b/src/doc/style/testing/unit.md deleted file mode 100644 index dbbe9fc3ac6da..0000000000000 --- a/src/doc/style/testing/unit.md +++ /dev/null @@ -1,30 +0,0 @@ -% 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!` diff --git a/src/doc/style/todo.md b/src/doc/style/todo.md deleted file mode 100644 index 28ef2a1832d8b..0000000000000 --- a/src/doc/style/todo.md +++ /dev/null @@ -1,5 +0,0 @@ -* [Containers and iteration]() -* [The visitor pattern]() -* [Concurrency]() -* [Documentation]() -* [Macros]() diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index dae12f6e8bdf7..c8a78f84f1857 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -67,7 +67,6 @@ use core::mem; 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` @@ -428,12 +427,8 @@ impl Box { pub fn downcast(self) -> Result, Box> { if self.is::() { 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) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index d9fd2d92710dc..c6453da3f4697 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -91,7 +91,7 @@ #![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 diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 4f486ad7cb8b2..a3018a46eea22 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -72,8 +72,6 @@ #![stable(feature = "rust1", since = "1.0.0")] use fmt; -use mem::transmute; -use raw::TraitObject; use intrinsics; use marker::Reflect; @@ -199,11 +197,7 @@ impl Any { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { 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 @@ -240,11 +234,7 @@ impl Any { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { 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 diff --git a/src/librustc/infer/bivariate.rs b/src/librustc/infer/bivariate.rs index 125f815feda6f..4acb8b807d594 100644 --- a/src/librustc/infer/bivariate.rs +++ b/src/librustc/infer/bivariate.rs @@ -106,7 +106,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> } } - 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) } diff --git a/src/librustc/infer/combine.rs b/src/librustc/infer/combine.rs index b4818f963b3ba..5ce30484ede00 100644 --- a/src/librustc/infer/combine.rs +++ b/src/librustc/infer/combine.rs @@ -329,8 +329,8 @@ impl<'cx, 'gcx, 'tcx> ty::fold::TypeFolder<'gcx, 'tcx> for Generalizer<'cx, 'gcx } } - 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(..) | diff --git a/src/librustc/infer/equate.rs b/src/librustc/infer/equate.rs index e06f7303acb29..bf247acec5a2d 100644 --- a/src/librustc/infer/equate.rs +++ b/src/librustc/infer/equate.rs @@ -79,7 +79,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, '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> { debug!("{}.regions({:?}, {:?})", self.tag(), a, diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs index 1e053d6bfdab2..9169d299e040b 100644 --- a/src/librustc/infer/error_reporting.rs +++ b/src/librustc/infer/error_reporting.rs @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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 { @@ -120,7 +120,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { Some(span)) } - let (description, span) = match region { + let (description, span) = match *region { ty::ReScope(scope) => { let new_string; let unknown_scope = || { @@ -405,12 +405,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } 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 { 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 } @@ -602,7 +602,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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 @@ -616,7 +616,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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, @@ -667,8 +667,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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) => { @@ -939,9 +939,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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, diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs index ecd9759c721b2..beda734ee0d56 100644 --- a/src/librustc/infer/freshen.rs +++ b/src/librustc/infer/freshen.rs @@ -83,8 +83,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { 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 @@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> { ty::ReEmpty | ty::ReErased => { // replace all free regions with 'erased - ty::ReErased + self.tcx().mk_region(ty::ReErased) } } } diff --git a/src/librustc/infer/glb.rs b/src/librustc/infer/glb.rs index 5dd85a31a9a20..a5709e1880801 100644 --- a/src/librustc/infer/glb.rs +++ b/src/librustc/infer/glb.rs @@ -57,7 +57,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> 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, diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index 743d6135fbb5b..90be5e935baf1 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -164,7 +164,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { .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] @@ -268,9 +268,9 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, - r0: ty::Region) - -> ty::Region { + a_map: &FnvHashMap, + 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()); @@ -301,7 +301,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { 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)); } } @@ -364,10 +364,12 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &FnvHashMap, + a_map: &FnvHashMap, 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; @@ -419,7 +421,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { 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()); @@ -430,13 +432,14 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } } - fn rev_lookup(span: Span, - a_map: &FnvHashMap, - r: ty::Region) -> ty::Region + fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, + span: Span, + a_map: &FnvHashMap, + 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!( @@ -445,19 +448,21 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { 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) + map: &FnvHashMap) -> Vec { 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: {:?}", @@ -467,8 +472,8 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, .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 } @@ -479,13 +484,13 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, 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 }); @@ -497,9 +502,9 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn tainted_regions(&self, snapshot: &CombinedSnapshot, - r: ty::Region, + r: &'tcx ty::Region, directions: TaintDirections) - -> FnvHashSet { + -> FnvHashSet<&'tcx ty::Region> { self.region_vars.tainted(&snapshot.region_vars_snapshot, r, directions) } @@ -596,7 +601,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn skolemize_late_bound_regions(&self, binder: &ty::Binder, snapshot: &CombinedSnapshot) - -> (T, SkolemizationMap) + -> (T, SkolemizationMap<'tcx>) where T : TypeFoldable<'tcx> { let (result, map) = self.tcx.replace_late_bound_regions(binder, |br| { @@ -619,7 +624,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn leak_check(&self, overly_polymorphic: bool, span: Span, - skol_map: &SkolemizationMap, + skol_map: &SkolemizationMap<'tcx>, snapshot: &CombinedSnapshot) -> RelateResult<'tcx, ()> { @@ -673,7 +678,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, '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( @@ -742,7 +747,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// 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(&self, - skol_map: SkolemizationMap, + skol_map: SkolemizationMap<'tcx>, snapshot: &CombinedSnapshot, value: &T) -> T where T : TypeFoldable<'tcx> @@ -755,7 +760,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, '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 = + let inv_skol_map: FnvHashMap<&'tcx ty::Region, ty::BoundRegion> = skol_map .iter() .flat_map(|(&skol_br, &skol)| { @@ -794,7 +799,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // (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, @@ -802,7 +807,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "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())) } } }); @@ -826,7 +832,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// /// 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); diff --git a/src/librustc/infer/lub.rs b/src/librustc/infer/lub.rs index ad1b32ffaeb32..7d352be67d32b 100644 --- a/src/librustc/infer/lub.rs +++ b/src/librustc/infer/lub.rs @@ -57,7 +57,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx> 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, diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 1b65b5dae0748..9854cd95397b7 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -177,7 +177,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: '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; +pub type SkolemizationMap<'tcx> = FnvHashMap; /// Why did we require that the two types be related? /// @@ -1123,8 +1123,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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); } @@ -1147,7 +1147,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn region_outlives_predicate(&self, span: Span, - predicate: &ty::PolyRegionOutlivesPredicate) + predicate: &ty::PolyRegionOutlivesPredicate<'tcx>) -> UnitResult<'tcx> { self.commit_if_ok(|snapshot| { @@ -1190,8 +1190,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .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 @@ -1199,7 +1200,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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)) } @@ -1245,7 +1246,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) } - 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) } @@ -1530,7 +1531,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, FnvHashMap) + -> (T, FnvHashMap) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( @@ -1576,8 +1577,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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, @@ -1666,7 +1667,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.region_maps.temporary_scope(rvalue_id) } - pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option { + pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> Option> { self.tables.borrow().upvar_capture_map.get(&upvar_id).cloned() } diff --git a/src/librustc/infer/region_inference/graphviz.rs b/src/librustc/infer/region_inference/graphviz.rs index 905ad7c0faa23..1c64ebc0537ae 100644 --- a/src/librustc/infer/region_inference/graphviz.rs +++ b/src/librustc/infer/region_inference/graphviz.rs @@ -123,7 +123,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( struct ConstraintGraph<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, graph_name: String, - map: &'a FnvHashMap>, + map: &'a FnvHashMap, SubregionOrigin<'tcx>>, node_ids: FnvHashMap, } @@ -135,8 +135,8 @@ enum Node { // type Edge = Constraint; #[derive(Clone, PartialEq, Eq, Debug, Copy)] -enum Edge { - Constraint(Constraint), +enum Edge<'tcx> { + Constraint(Constraint<'tcx>), EnclScope(CodeExtent, CodeExtent), } @@ -177,7 +177,7 @@ impl<'a, 'gcx, 'tcx> ConstraintGraph<'a, 'gcx, 'tcx> { 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() } @@ -214,11 +214,11 @@ fn constraint_to_nodes(c: &Constraint) -> (Node, Node) { 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)), } } @@ -234,7 +234,7 @@ fn edge_to_nodes(e: &Edge) -> (Node, Node) { 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 { let mut set = FnvHashSet(); for node in self.node_ids.keys() { @@ -243,26 +243,26 @@ impl<'a, 'gcx, 'tcx> dot::GraphWalk<'a> for ConstraintGraph<'a, 'gcx, 'tcx> { debug!("constraint graph has {} nodes", set.len()); set.into_iter().collect() } - fn edges(&self) -> dot::Edges { + fn edges(&self) -> dot::Edges> { 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>; +pub type ConstraintMap<'tcx> = FnvHashMap, SubregionOrigin<'tcx>>; fn dump_region_constraints_to<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, map: &ConstraintMap<'tcx>, diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs index d3b4afa2cee79..b3693ae1e21ad 100644 --- a/src/librustc/infer/region_inference/mod.rs +++ b/src/librustc/infer/region_inference/mod.rs @@ -39,22 +39,22 @@ mod graphviz; // 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 @@ -66,8 +66,8 @@ pub enum Constraint { 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)] @@ -80,36 +80,36 @@ pub enum GenericKind<'tcx> { // 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), + 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), + AllRegions(Vec<&'tcx Region>), // B = exists {B} --> 'min must meet some bound b in {B} - AnyBound(Vec), + AnyBound(Vec>), // B = forall {B} --> 'min must meet all bounds b in {B} - AllBounds(Vec), + AllBounds(Vec>), } #[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, @@ -122,7 +122,7 @@ pub enum UndoLogEntry { AddVar(RegionVid), /// We added the given `constraint` - AddConstraint(Constraint), + AddConstraint(Constraint<'tcx>), /// We added the given `verify` AddVerify(usize), @@ -131,7 +131,7 @@ pub enum UndoLogEntry { 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 @@ -153,13 +153,13 @@ pub enum RegionResolutionError<'tcx> { /// `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)`: /// @@ -168,9 +168,9 @@ pub enum RegionResolutionError<'tcx> { /// `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 @@ -182,7 +182,7 @@ pub enum RegionResolutionError<'tcx> { #[derive(Clone, Debug)] pub enum ProcessedErrorOrigin<'tcx> { - ConcreteFailure(SubregionOrigin<'tcx>, Region, Region), + ConcreteFailure(SubregionOrigin<'tcx>, &'tcx Region, &'tcx Region), VariableFailure(RegionVariableOrigin), } @@ -213,7 +213,7 @@ impl SameRegions { } } -pub type CombineMap = FnvHashMap; +pub type CombineMap<'tcx> = FnvHashMap, RegionVid>; pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, @@ -222,7 +222,7 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // 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>>, + constraints: RefCell, 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. @@ -250,8 +250,8 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // a bit of a hack but seems to work. givens: RefCell>, - lubs: RefCell, - glbs: RefCell, + lubs: RefCell>, + glbs: RefCell>, skolemization_count: Cell, bound_count: Cell, @@ -264,12 +264,12 @@ pub struct RegionVarBindings<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // 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>, + undo_log: RefCell>>, unification_table: RefCell>, // This contains the results of inference. It begins as an empty // option and only acquires a value after inference is complete. - values: RefCell>>, + values: RefCell>>>, } pub struct RegionSnapshot { @@ -303,14 +303,14 @@ impl TaintDirections { } } -struct TaintSet { +struct TaintSet<'tcx> { directions: TaintDirections, - regions: FnvHashSet + 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); @@ -318,8 +318,9 @@ impl TaintSet { } 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 = {:?}", @@ -330,19 +331,21 @@ impl TaintSet { 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| { @@ -359,7 +362,7 @@ impl TaintSet { } } - fn into_set(self) -> FnvHashSet { + fn into_set(self) -> FnvHashSet<&'tcx ty::Region> { self.regions } @@ -368,8 +371,8 @@ impl TaintSet { } 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); @@ -450,7 +453,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { .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"); @@ -529,13 +532,14 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// 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 @@ -543,7 +547,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// completes to remove all trace of the skolemized regions /// created in that time. pub fn pop_skolemized(&self, - skols: &FnvHashSet, + skols: &FnvHashSet<&'tcx ty::Region>, snapshot: &RegionSnapshot) { debug!("pop_skolemized_regions(skols={:?})", skols); @@ -566,7 +570,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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, @@ -597,9 +601,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { self.skolemization_count.set(snapshot.skolemization_count); return; - fn kill_constraint(skols: &FnvHashSet, - undo_entry: &UndoLogEntry) - -> bool { + fn kill_constraint<'tcx>(skols: &FnvHashSet<&'tcx ty::Region>, + undo_entry: &UndoLogEntry<'tcx>) + -> bool { match undo_entry { &AddConstraint(ConstrainVarSubVar(_, _)) => false, @@ -626,7 +630,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } - 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. @@ -652,14 +656,14 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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()); @@ -704,20 +708,26 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - 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()); @@ -727,26 +737,26 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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); @@ -758,8 +768,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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, @@ -768,29 +778,43 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { }); } - 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 } @@ -806,7 +830,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - 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(), @@ -814,18 +838,19 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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 { + fn combine_map(&self, t: CombineMapType) -> &RefCell> { match t { Glb => &self.glbs, Lub => &self.lubs, @@ -834,26 +859,26 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { pub fn combine_vars(&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 { @@ -878,9 +903,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// related to other regions. pub fn tainted(&self, mark: &RegionSnapshot, - r0: Region, + r0: &'tcx Region, directions: TaintDirections) - -> FnvHashSet { + -> FnvHashSet<&'tcx ty::Region> { debug!("tainted(mark={:?}, r0={:?}, directions={:?})", mark, r0, directions); @@ -888,7 +913,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // 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(); @@ -910,26 +936,30 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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: {:?}, {:?}", @@ -937,9 +967,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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: @@ -949,33 +978,34 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // 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) } } } @@ -985,24 +1015,24 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { // ______________________________________________________________________ #[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>, subject: ast::NodeId) - -> Vec { + -> Vec> { let mut var_data = self.construct_var_data(); // Dorky hack to cause `dump_constraints` to only get called @@ -1020,9 +1050,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { var_data } - fn construct_var_data(&self) -> Vec { + fn construct_var_data(&self) -> Vec> { (0..self.num_vars() as usize) - .map(|_| Value(ty::ReEmpty)) + .map(|_| Value(self.tcx.mk_region(ty::ReEmpty))) .collect() } @@ -1059,7 +1089,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - 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); @@ -1089,9 +1119,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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, @@ -1099,7 +1129,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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"); @@ -1136,7 +1166,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// and check that they are satisfied. fn collect_errors(&self, free_regions: &FreeRegionMap, - var_data: &mut Vec, + var_data: &mut Vec>, errors: &mut Vec>) { let constraints = self.constraints.borrow(); for (constraint, origin) in constraints.iter() { @@ -1192,7 +1222,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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; } @@ -1213,8 +1243,8 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { /// 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>) { debug!("collect_var_errors"); @@ -1271,7 +1301,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } } - fn construct_graph(&self) -> RegionGraph { + fn construct_graph(&self) -> RegionGraph<'tcx> { let num_vars = self.num_vars(); let constraints = self.constraints.borrow(); @@ -1315,7 +1345,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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>) { @@ -1339,9 +1369,9 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, '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, } } @@ -1378,7 +1408,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } fn collect_concrete_regions(&self, - graph: &RegionGraph, + graph: &RegionGraph<'tcx>, orig_node_idx: RegionVid, dir: Direction, dup_vec: &mut [u32]) @@ -1423,7 +1453,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { 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); @@ -1460,7 +1490,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } fn iterate_until_fixed_point(&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; @@ -1481,17 +1511,23 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> { } -fn normalize(values: &Vec, 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>, + r: &'tcx ty::Region) + -> &'tcx ty::Region { + match *r { + ty::ReVar(rid) => lookup(tcx, values, rid), _ => r, } } -fn lookup(values: &Vec, rid: ty::RegionVid) -> ty::Region { +fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + values: &Vec>, + 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. } } @@ -1535,8 +1571,8 @@ impl<'a, 'gcx, 'tcx> GenericKind<'tcx> { } } -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 { @@ -1552,7 +1588,7 @@ impl<'a, 'gcx, 'tcx> VerifyBound { 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()), @@ -1562,13 +1598,13 @@ impl<'a, 'gcx, 'tcx> VerifyBound { 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() { @@ -1578,7 +1614,7 @@ impl<'a, 'gcx, 'tcx> VerifyBound { } } - 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() { @@ -1590,18 +1626,18 @@ impl<'a, 'gcx, 'tcx> VerifyBound { fn is_met(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, free_regions: &FreeRegionMap, - var_values: &Vec, - min: ty::Region) + var_values: &Vec>, + 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) => diff --git a/src/librustc/infer/resolve.rs b/src/librustc/infer/resolve.rs index 5f550b427e21a..357a03a2ffd7c 100644 --- a/src/librustc/infer/resolve.rs +++ b/src/librustc/infer/resolve.rs @@ -72,10 +72,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpportunisticTypeAndRegionResolv } } - 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, } } } @@ -138,10 +138,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for FullTypeResolver<'a, 'gcx, 'tcx> } } - 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, } } } diff --git a/src/librustc/infer/sub.rs b/src/librustc/infer/sub.rs index 2f7f5254727db..159de2faced57 100644 --- a/src/librustc/infer/sub.rs +++ b/src/librustc/infer/sub.rs @@ -107,7 +107,8 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, '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> { debug!("{}.regions({:?}, {:?}) self.cause={:?}", self.tag(), a, b, self.fields.cause); // FIXME -- we have more fine-grained information available diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 48ea953cc1e8b..1e4b2e9116fd2 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -27,6 +27,7 @@ #![feature(box_patterns)] #![feature(box_syntax)] #![feature(collections)] +#![feature(conservative_impl_trait)] #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(enumset)] diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 92e1b0681cc7e..b33bc520fe216 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -149,7 +149,7 @@ pub trait CrateStore<'tcx> { 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; fn repr_attrs(&self, def: DefId) -> Vec; fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx>; @@ -198,7 +198,6 @@ pub trait CrateStore<'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; @@ -329,7 +328,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { 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 { bug!("item_variances") } fn repr_attrs(&self, def: DefId) -> Vec { bug!("repr_attrs") } fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Ty<'tcx> { bug!("item_type") } @@ -391,7 +390,6 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore { 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") } diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2a8594c59a837..37366f38974a4 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { 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) } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 87463055a276a..798702e6fd657 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -76,7 +76,7 @@ pub trait Delegate<'tcx> { 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); @@ -301,11 +301,11 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { 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); @@ -352,7 +352,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { 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={:?})", @@ -431,7 +431,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { 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 { @@ -449,7 +450,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // 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); } @@ -557,7 +558,6 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { 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); @@ -578,14 +578,16 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { }; 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); } @@ -761,7 +763,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { }; let bk = ty::BorrowKind::from_mutbl(m); self.delegate.borrow(expr.id, expr.span, cmt, - *r, bk, AutoRef); + r, bk, AutoRef); } } } @@ -822,7 +824,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.delegate.borrow(expr.id, expr.span, cmt_base, - *r, + r, ty::BorrowKind::from_mutbl(m), AutoRef); } @@ -835,7 +837,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // 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, @@ -890,7 +892,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // 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 { @@ -979,7 +981,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // 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); } diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs index e4ce89767139a..8193d062631c1 100644 --- a/src/librustc/middle/free_region.rs +++ b/src/librustc/middle/free_region.rs @@ -37,7 +37,7 @@ impl FreeRegionMap { 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(..) | @@ -65,9 +65,9 @@ impl FreeRegionMap { } 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); } @@ -122,26 +122,26 @@ impl FreeRegionMap { /// 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), _ => diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 676e456dcea94..a74bdb02044de 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -90,11 +90,11 @@ use std::rc::Rc; #[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) @@ -110,18 +110,18 @@ pub struct Upvar { // different kinds of pointers: #[derive(Clone, Copy, PartialEq, Eq, Hash)] -pub enum PointerKind { +pub enum PointerKind<'tcx> { /// `Box` 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 @@ -198,8 +198,8 @@ pub type cmt<'tcx> = Rc>; // 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), } @@ -216,7 +216,7 @@ fn deref_kind(t: Ty, context: DerefKindContext) -> McResult { 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) => { @@ -767,13 +767,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; // 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); @@ -817,11 +817,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { /// 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, @@ -845,7 +845,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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); @@ -855,7 +855,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { 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, @@ -1480,7 +1480,7 @@ pub fn ptr_sigil(ptr: PointerKind) -> &'static str { } } -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"), diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 8369a6c39d54d..ebe4050022153 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -89,9 +89,12 @@ struct LifetimeContext<'a, 'tcx: 'a> { #[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>), @@ -157,7 +160,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for LifetimeContext<'a, 'tcx> { 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); }); @@ -461,7 +469,7 @@ fn extract_labels(ctxt: &mut LifetimeContext, b: &hir::Block) { 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 @@ -566,8 +574,24 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .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); @@ -597,19 +621,11 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { 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; } @@ -671,7 +687,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break; } - EarlyScope(lifetimes, s) | + EarlyScope(lifetimes, _, s) | LateScope(lifetimes, s) => { search_result = search_lifetimes(lifetimes, lifetime_ref); if search_result.is_some() { @@ -767,7 +783,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { return; } - EarlyScope(lifetimes, s) | + EarlyScope(lifetimes, _, s) | LateScope(lifetimes, s) => { if let Some((_, lifetime_def)) = search_lifetimes(lifetimes, lifetime) { signal_shadowing_problem( diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index f511d820fac58..059fcfdca8a00 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -911,7 +911,7 @@ pub enum Rvalue<'tcx> { 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>), diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index cf91229f1c713..76e5f8598c1c5 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -145,8 +145,7 @@ impl<'tcx> Rvalue<'tcx> { } &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() diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index ead8de86dbae4..f608185157a4e 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -724,7 +724,7 @@ make_mir_visitor!(Visitor,); make_mir_visitor!(MutVisitor,mut); #[derive(Copy, Clone, Debug)] -pub enum LvalueContext { +pub enum LvalueContext<'tcx> { // Appears as LHS of an assignment Store, @@ -738,7 +738,7 @@ pub enum LvalueContext { 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 }, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6f263fcebeb0..10112e5084557 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -232,8 +232,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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); @@ -738,8 +738,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { 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 diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 837e33b3e7fc2..6598aacc1d3d2 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -93,7 +93,7 @@ pub struct FulfillmentContext<'tcx> { #[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>, } @@ -142,7 +142,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'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; } @@ -162,7 +162,7 @@ impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> { 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(), @@ -246,7 +246,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { 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); @@ -440,8 +440,7 @@ fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 't { 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 }) @@ -581,7 +580,8 @@ fn process_predicate<'a, 'gcx, 'tcx>( // 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![])) @@ -691,7 +691,7 @@ fn coinductive_obligation<'a,'gcx,'tcx>(selcx: &SelectionContext<'a,'gcx,'tcx>, } 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>>) { diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index 25d2df8fdedb3..219d520046762 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '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(..) | diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 9ea738bd326eb..b015de79be5c6 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -36,7 +36,7 @@ use super::util; 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; @@ -644,8 +644,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // 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); @@ -1064,9 +1063,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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() } } @@ -1250,7 +1247,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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 { @@ -1603,7 +1600,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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); @@ -1936,7 +1933,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // for `PhantomData`, 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) => { @@ -1985,7 +1982,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_def_id, recursion_depth, normalized_ty, - vec![]); + &[]); obligations.push(skol_obligation); this.infcx().plug_leaks(skol_map, snapshot, &obligations) }) @@ -2180,12 +2177,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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)); @@ -2267,7 +2263,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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>> { @@ -2476,7 +2472,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, '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={:?})", @@ -2585,7 +2581,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } 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 { @@ -2601,14 +2597,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // 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); @@ -2621,15 +2617,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // 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) @@ -2642,7 +2637,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.recursion_depth + 1, inner_source, - vec![inner_target])); + &[inner_target])); } _ => bug!() @@ -2665,7 +2660,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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), @@ -2682,7 +2678,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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(); @@ -2753,9 +2749,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // 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 = @@ -2875,7 +2871,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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> { diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 1954ce1993c5e..038de25312d35 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, '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) => { @@ -401,12 +401,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, recursion_depth: usize, param_ty: Ty<'tcx>, - ty_params: Vec>) + 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) } @@ -496,7 +496,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; 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)) } diff --git a/src/librustc/ty/_match.rs b/src/librustc/ty/_match.rs index 39dba57c47b7c..b1846e0394148 100644 --- a/src/librustc/ty/_match.rs +++ b/src/librustc/ty/_match.rs @@ -52,7 +52,8 @@ impl<'a, 'gcx, 'tcx> TypeRelation<'a, 'gcx, 'tcx> for Match<'a, 'gcx, 'tcx> { 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, diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3501dd4846087..e048e618e84d6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -213,7 +213,7 @@ pub struct Tables<'tcx> { 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. @@ -1152,12 +1152,17 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool { impl_interners!('tcx, type_list: mk_type_list(Vec>, 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> { diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index 32c87fb615a53..3d60d326b2b0f 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -41,11 +41,11 @@ pub enum TypeError<'tcx> { FixedArraySize(ExpectedFound), TyParamSize(ExpectedFound), 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>), IntegerAsChar, IntMismatch(ExpectedFound), @@ -296,7 +296,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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. } diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index c6c37296e9e12..1afd49ab47fbf 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -137,7 +137,7 @@ impl FlagComputation { } &ty::TyRef(r, ref m) => { - self.add_region(*r); + self.add_region(r); self.add_ty(m.ty); } @@ -176,8 +176,8 @@ impl FlagComputation { 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); @@ -208,8 +208,11 @@ impl FlagComputation { } 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); } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 2e114a801d6ed..2c18d1d52547f 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -169,7 +169,7 @@ pub trait TypeFolder<'gcx: 'tcx, 'tcx> : Sized { 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) } @@ -188,7 +188,7 @@ pub trait TypeVisitor<'tcx> : Sized { 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) } } @@ -222,13 +222,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// whether any late-bound regions were skipped pub fn collect_regions(self, value: &T, - region_set: &mut FnvHashSet) + 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 } @@ -240,7 +242,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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)) @@ -260,14 +262,14 @@ pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { 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(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, @@ -288,8 +290,8 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, '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); @@ -313,16 +315,16 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { 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 + fld_r: &'a mut (FnMut(ty::BoundRegion) -> &'tcx ty::Region + 'a), + map: FnvHashMap } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, FnvHashMap) - where F : FnMut(ty::BoundRegion) -> ty::Region, + -> (T, FnvHashMap) + where F : FnMut(ty::BoundRegion) -> &'tcx ty::Region, T : TypeFoldable<'tcx>, { let mut replacer = RegionReplacer::new(self, &mut f); @@ -340,7 +342,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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 } @@ -353,11 +358,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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 @@ -411,7 +416,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn erase_late_bound_regions(self, value: &Binder) -> 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 @@ -428,7 +433,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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) } } @@ -436,7 +441,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { fn new(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, @@ -465,22 +470,22 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, '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 } } } @@ -528,7 +533,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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. @@ -537,9 +542,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // 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) } } } @@ -574,7 +579,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, 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)) })) } @@ -616,7 +621,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { 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) } } @@ -630,17 +635,18 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { 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 } _ => {} } @@ -688,8 +694,8 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { 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); } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 1dcc623d36558..62bd30e255592 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -264,7 +264,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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)); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index d5686906e6a7b..0e8bea86178f3 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -38,7 +38,7 @@ dep_map_ty! { TraitItemDefIds: TraitItemDefIds(DefId) -> Rc Option> } 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 } +dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc> } dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Rc> } dep_map_ty! { ImplItems: ImplItems(DefId) -> Vec } dep_map_ty! { TraitItems: TraitItems(DefId) -> Rc>> } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 6c82157c8ca7c..759dc30037210 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -343,7 +343,7 @@ pub struct Method<'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, @@ -355,7 +355,7 @@ impl<'tcx> Method<'tcx> { 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, @@ -417,21 +417,6 @@ pub struct AssociatedType<'tcx> { pub container: ImplOrTraitItemContainer, } -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable)] -pub struct ItemVariances { - pub types: Vec, - pub regions: Vec, -} - -impl ItemVariances { - pub fn empty() -> ItemVariances { - ItemVariances { - types: vec![], - regions: vec![], - } - } -} - #[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type @@ -658,28 +643,28 @@ pub enum BorrowKind { /// 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; +pub type UpvarCaptureMap<'tcx> = FnvHashMap>; #[derive(Copy, Clone)] pub struct ClosureUpvar<'tcx> { @@ -700,7 +685,7 @@ pub enum IntVarValue { /// 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, @@ -709,7 +694,7 @@ pub enum ObjectLifetimeDefault { BaseDefault, /// Use the given region as the default. - Specific(Region), + Specific(&'tcx Region), } #[derive(Clone)] @@ -719,18 +704,18 @@ pub struct TypeParameterDef<'tcx> { pub index: u32, pub default_def_id: DefId, // for use in error reporing about defaults pub default: Option>, - 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, + 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, @@ -750,11 +735,25 @@ pub struct Generics<'tcx> { pub parent: Option, pub parent_regions: u32, pub parent_types: u32, - pub regions: Vec, + pub regions: Vec>, pub types: Vec>, 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> { @@ -812,7 +811,7 @@ pub enum Predicate<'tcx> { Equate(PolyEquatePredicate<'tcx>), /// where 'a : 'b - RegionOutlives(PolyRegionOutlivesPredicate), + RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), /// where T : 'a TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), @@ -951,7 +950,6 @@ impl<'tcx> TraitPredicate<'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, _) | @@ -964,8 +962,8 @@ impl<'tcx> TraitPredicate<'tcx> { 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> + 'a { + self.trait_ref.input_types() } pub fn self_ty(&self) -> Ty<'tcx> { @@ -992,8 +990,9 @@ pub type PolyEquatePredicate<'tcx> = ty::Binder>; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct OutlivesPredicate(pub A, pub B); // `A : B` pub type PolyOutlivesPredicate = ty::Binder>; -pub type PolyRegionOutlivesPredicate = PolyOutlivesPredicate; -pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, ty::Region>; +pub type PolyRegionOutlivesPredicate<'tcx> = PolyOutlivesPredicate<&'tcx ty::Region, + &'tcx ty::Region>; +pub type PolyTypeOutlivesPredicate<'tcx> = PolyOutlivesPredicate, &'tcx ty::Region>; /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: @@ -1082,7 +1081,7 @@ impl<'tcx> ToPredicate<'tcx> for PolyEquatePredicate<'tcx> { } } -impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate { +impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> { fn to_predicate(&self) -> Predicate<'tcx> { Predicate::RegionOutlives(self.clone()) } @@ -1107,7 +1106,7 @@ impl<'tcx> Predicate<'tcx> { pub fn walk_tys(&self) -> IntoIter> { 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() @@ -1123,10 +1122,7 @@ impl<'tcx> Predicate<'tcx> { } 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] @@ -1206,15 +1202,15 @@ impl<'tcx> TraitRef<'tcx> { } 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> + '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() } } @@ -1239,7 +1235,7 @@ pub struct ParameterEnvironment<'tcx> { /// 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 @@ -1866,7 +1862,7 @@ impl<'a, 'tcx> AdtDefData<'tcx, 'tcx> { }; 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) { @@ -2593,7 +2589,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { || self.lookup_repr_hints(did).contains(&attr::ReprSimd) } - pub fn item_variances(self, item_id: DefId) -> Rc { + pub fn item_variances(self, item_id: DefId) -> Rc> { lookup_locally_or_in_crate_store( "item_variance_map", item_id, &self.item_variance_map, || Rc::new(self.sess.cstore.item_variances(item_id))) @@ -2827,7 +2823,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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 } } @@ -2843,8 +2839,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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) @@ -2894,7 +2892,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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, }; @@ -2903,6 +2901,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { 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)) } @@ -2912,7 +2914,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { autoderefs)) } - pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option { + pub fn upvar_capture(self, upvar_id: ty::UpvarId) -> Option> { Some(self.tables.borrow().upvar_capture_map.get(&upvar_id).unwrap().clone()) } @@ -2938,10 +2940,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// 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, } diff --git a/src/librustc/ty/outlives.rs b/src/librustc/ty/outlives.rs index ee431681ad100..4d5b38212f600 100644 --- a/src/librustc/ty/outlives.rs +++ b/src/librustc/ty/outlives.rs @@ -17,7 +17,7 @@ use ty::{self, Ty, TypeFoldable}; #[derive(Debug)] pub enum Component<'tcx> { - Region(ty::Region), + Region(&'tcx ty::Region), Param(ty::ParamTy), UnresolvedInferenceVariable(ty::InferTy), @@ -210,7 +210,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec) { +fn push_region_constraints<'tcx>(out: &mut Vec>, regions: Vec<&'tcx ty::Region>) { for r in regions { if !r.is_bound() { out.push(Component::Region(r)); diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8975a799be143..5c157ff32e7bb 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -14,7 +14,7 @@ //! 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; @@ -71,8 +71,8 @@ pub trait TypeRelation<'a, 'gcx: 'a+'tcx, 'tcx: 'a> : Sized { 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(&mut self, a: &ty::Binder, b: &ty::Binder) -> RelateResult<'tcx, ty::Binder> @@ -139,7 +139,7 @@ fn relate_item_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, } pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, - variances: Option<&ty::ItemVariances>, + variances: Option<&Vec>, a_subst: &'tcx Substs<'tcx>, b_subst: &'tcx Substs<'tcx>) -> RelateResult<'tcx, &'tcx Substs<'tcx>> @@ -147,19 +147,18 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, { 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::>()?; - - 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::>()?; + 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> { @@ -473,9 +472,9 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, (&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)) => @@ -571,11 +570,11 @@ impl<'tcx> Relate<'tcx> for &'tcx Substs<'tcx> { } } -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) diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index f7c4b9938c279..705cca056f24c 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -9,7 +9,6 @@ // 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}; @@ -73,13 +72,6 @@ impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Vec { } } -impl<'tcx> Lift<'tcx> for ty::Region { - type Lifted = Self; - fn lift_to_tcx(&self, _: TyCtxt) -> Option { - 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 { @@ -316,13 +308,21 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { 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), @@ -655,7 +655,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ImplHeader<'tcx> { } } -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 } @@ -673,41 +673,6 @@ 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 - } - - 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>(&self, _visitor: &mut V) -> bool { - false - } - - fn visit_with>(&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>(&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 { @@ -783,7 +748,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> { } } -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 => @@ -805,7 +770,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ObjectLifetimeDefault { } } -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, diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 8aa81cc4743c9..0e3f18c4474ea 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -19,8 +19,8 @@ use util::common::ErrorReported; 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; @@ -293,7 +293,7 @@ impl<'tcx> Decodable for ClosureSubsts<'tcx> { #[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>, } @@ -335,7 +335,7 @@ impl<'tcx> PolyTraitRef<'tcx> { self.0.substs } - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -360,12 +360,12 @@ pub struct ExistentialTraitRef<'tcx> { } impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + '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() } } @@ -376,7 +376,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { self.0.def_id } - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -675,6 +675,15 @@ pub enum Region { ReErased, } +impl<'tcx> Decodable for &'tcx Region { + fn decode(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, @@ -1206,26 +1215,26 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { /// 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 { + 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(_) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e1a19a7b7992e..0ccfea2330999 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -13,41 +13,156 @@ 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, + 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> 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(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> { + 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, "", *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>(&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>, - pub regions: Vec, + params: Vec> } impl<'a, 'gcx, 'tcx> Substs<'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - t: Vec>, - r: Vec) - -> &'tcx Substs<'tcx> - { - tcx.mk_substs(Substs { types: t, regions: r }) + pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I) + -> &'tcx Substs<'tcx> + where I: IntoIterator> { + tcx.mk_substs(Substs { + params: params.into_iter().collect() + }) + } + + pub fn maybe_new(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I) + -> Result<&'tcx Substs<'tcx>, E> + where I: IntoIterator, E>> { + Ok(tcx.mk_substs(Substs { + params: params.into_iter().collect::>()? + })) } pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>, - mut t: Vec>, - r: Vec, - 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, @@ -60,19 +175,16 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { 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(&mut self, @@ -80,36 +192,76 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { 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> + 'a { + self.params.iter().filter_map(|k| k.as_type()) + } + + #[inline] + pub fn regions(&'a self) -> impl DoubleEndedIterator + '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` @@ -122,11 +274,27 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { 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>(&self, visitor: &mut V) -> bool { + self.params.visit_with(visitor) } } @@ -215,16 +383,18 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { 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 => { @@ -278,9 +448,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { 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!( @@ -291,7 +462,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { source_ty, p.idx, self.root_ty, - self.substs); + self.substs.params); } }; @@ -354,8 +525,8 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { 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)) } } @@ -367,12 +538,11 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { 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) } } } @@ -381,13 +551,13 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> { 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) } } } @@ -404,13 +574,11 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { 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) } }) } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 51710c13a7dea..dd5c6a9758abf 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -306,7 +306,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn required_region_bounds(self, erased_self_ty: Ty<'tcx>, predicates: Vec>) - -> Vec { + -> Vec<&'tcx ty::Region> { debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", erased_self_ty, predicates); @@ -496,8 +496,8 @@ impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx> { 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::(0); } @@ -693,10 +693,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { 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 diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 8a9ee45351dfc..409f5a85997bd 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -67,6 +67,12 @@ pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { 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>, parent_ty: Ty<'tcx>) { match parent_ty.sty { ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | @@ -79,28 +85,28 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { 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::>()); + }).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) => { @@ -111,17 +117,5 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { stack.push(sig.0.output); - push_reversed(stack, &sig.0.inputs); -} - -fn push_reversed<'tcx>(stack: &mut Vec>, 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()); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 54b19362b1d86..1f166cb192fa3 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -115,9 +115,9 @@ pub fn predicate_obligations<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, /// 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 @@ -196,7 +196,7 @@ pub fn implied_bounds<'a, 'gcx, 'tcx>( /// 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>) -> Vec> { @@ -260,8 +260,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, '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)))); @@ -364,7 +363,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { cause, ty::Predicate::TypeOutlives( ty::Binder( - ty::OutlivesPredicate(mt.ty, *r))))); + ty::OutlivesPredicate(mt.ty, r))))); } } @@ -535,7 +534,7 @@ pub fn object_region_bounds<'a, 'gcx, 'tcx>( tcx: TyCtxt<'a, 'gcx, 'tcx>, principal: ty::PolyExistentialTraitRef<'tcx>, others: ty::BuiltinBounds) - -> Vec + -> 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 diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 02ad8fb7033ed..24b68c66e4667 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -22,6 +22,8 @@ use ty::fold::{TypeFolder, TypeVisitor}; use std::cell::Cell; use std::fmt; +use std::usize; + use syntax::abi::Abi; use syntax::parse::token; use syntax::ast::CRATE_NODE_ID; @@ -80,15 +82,17 @@ pub fn parameterized(f: &mut fmt::Formatter, 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)); @@ -107,8 +111,8 @@ pub fn parameterized(f: &mut fmt::Formatter, 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; } @@ -124,7 +128,7 @@ pub fn parameterized(f: &mut fmt::Formatter, 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); } } @@ -139,13 +143,15 @@ pub fn parameterized(f: &mut fmt::Formatter, } }; - 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)?; @@ -167,11 +173,12 @@ pub fn parameterized(f: &mut fmt::Formatter, 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)?; } @@ -197,10 +204,10 @@ pub fn parameterized(f: &mut fmt::Formatter, 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)?; } @@ -240,7 +247,7 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, 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 @@ -254,7 +261,8 @@ fn in_binder<'a, 'gcx, 'tcx, T, U>(f: &mut fmt::Formatter, name, ty::Issue32330::WontChange) } - }) + }; + tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) }).0; start_or_continue(f, "", "> ")?; @@ -344,7 +352,7 @@ impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> { } } -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, @@ -368,13 +376,6 @@ impl<'tcx> fmt::Display for ty::TypeAndMut<'tcx> { } } -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) @@ -598,7 +599,7 @@ impl<'tcx> fmt::Debug for ty::ParameterEnvironment<'tcx> { } } -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"), @@ -654,13 +655,6 @@ impl fmt::Debug for ty::Variance { } } -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) @@ -793,13 +787,14 @@ impl<'tcx> fmt::Display for ty::Binder> { } } -impl<'tcx> fmt::Display for ty::Binder, ty::Region>> { +impl<'tcx> fmt::Display for ty::Binder, &'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> { +impl<'tcx> fmt::Display for ty::Binder> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { ty::tls::with(|tcx| in_binder(f, tcx, self, tcx.lift(self))) } @@ -973,7 +968,7 @@ impl fmt::Debug for ty::UpvarId { } } -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) @@ -997,7 +992,7 @@ impl fmt::Display for ty::InferTy { } } -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", diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index c1f162e5772bf..e86fa9a05f372 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -126,7 +126,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { 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) { diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 667bf16874ec4..9f95175d59d43 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -28,7 +28,7 @@ pub fn guarantee_lifetime<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, 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 @@ -56,7 +56,7 @@ struct GuaranteeLifetimeContext<'a, 'tcx: 'a> { span: Span, cause: euv::LoanCause, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, cmt_original: mc::cmt<'tcx> } @@ -92,7 +92,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, '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) { @@ -102,7 +102,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - 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. @@ -112,16 +112,15 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { 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)) => { @@ -135,7 +134,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { } } - 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), diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index c982fc091d24c..a255564f01e25 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -130,7 +130,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for GatherLoanCtxt<'a, 'tcx> { 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) { @@ -307,7 +307,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { 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={:?})", @@ -318,7 +318,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { // 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; } @@ -358,7 +358,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { } 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, diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 3d9df4c8bd008..d08f792b30c14 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -31,7 +31,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, 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, @@ -49,7 +49,7 @@ pub fn compute_restrictions<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, struct RestrictionsContext<'a, 'tcx: 'a> { bccx: &'a BorrowckCtxt<'a, 'tcx>, span: Span, - loan_region: ty::Region, + loan_region: &'tcx ty::Region, cause: euv::LoanCause, } @@ -157,7 +157,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { 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) => { diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs index 111646912ade3..3ff2fb8e2e527 100644 --- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs +++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs @@ -16,7 +16,7 @@ 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; @@ -26,6 +26,7 @@ use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; use std::fmt; +use std::iter; use std::u32; pub struct ElaborateDrops; @@ -859,7 +860,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> { 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 { diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 225895adefa4b..6137afbb59f4d 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -41,6 +41,7 @@ use rustc::ty::{self, TyCtxt}; 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}; @@ -345,7 +346,7 @@ impl<'tcx> Loan<'tcx> { } } -#[derive(Eq, Hash)] +#[derive(Eq)] pub struct LoanPath<'tcx> { kind: LoanPathKind<'tcx>, ty: ty::Ty<'tcx>, @@ -353,10 +354,13 @@ pub struct LoanPath<'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(&self, state: &mut H) { + self.kind.hash(state); } } @@ -365,7 +369,7 @@ pub enum LoanPathKind<'tcx> { LpVar(ast::NodeId), // `x` in README.md LpUpvar(ty::UpvarId), // `x` captured by-value into closure LpDowncast(Rc>, DefId), // `x` downcast to particular enum variant - LpExtend(Rc>, mc::MutabilityCategory, LoanPathElem) + LpExtend(Rc>, mc::MutabilityCategory, LoanPathElem<'tcx>) } impl<'tcx> LoanPath<'tcx> { @@ -410,8 +414,8 @@ impl ToInteriorKind for mc::InteriorKind { // `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, InteriorKind), } @@ -564,10 +568,11 @@ pub fn opt_loan_path<'tcx>(cmt: &mc::cmt<'tcx>) -> Option>> { // 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 @@ -577,7 +582,7 @@ pub struct BckError<'tcx> { span: Span, cause: AliasableViolationKind, cmt: mc::cmt<'tcx>, - code: bckerr_code + code: bckerr_code<'tcx> } #[derive(Copy, Clone, Debug, PartialEq)] @@ -605,7 +610,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { 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) @@ -614,9 +619,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { 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); } @@ -965,8 +970,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .emit(); } - fn region_end_span(&self, region: ty::Region) -> Option { - match region { + fn region_end_span(&self, region: &'tcx ty::Region) -> Option { + match *region { ty::ReScope(scope) => { match scope.span(&self.tcx.region_maps, &self.tcx.map) { Some(s) => { @@ -1194,8 +1199,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } -fn statement_scope_span(tcx: TyCtxt, region: ty::Region) -> Option { - match region { +fn statement_scope_span(tcx: TyCtxt, region: &ty::Region) -> Option { + match *region { ty::ReScope(scope) => { match tcx.map.find(scope.node_id(&tcx.region_maps)) { Some(hir_map::NodeStmt(stmt)) => Some(stmt.span), diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index 3c82358542876..82c142c919e34 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -1172,7 +1172,7 @@ impl<'a, 'gcx, 'tcx> Delegate<'tcx> for MutationChecker<'a, 'gcx> { _: NodeId, span: Span, _: cmt, - _: Region, + _: &'tcx Region, kind: BorrowKind, _: LoanCause) { match kind { diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 32d0bbbfdb6b7..460a6e68a5c5a 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -20,13 +20,14 @@ use rustc::middle::region::{self, CodeExtent}; 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; @@ -283,25 +284,26 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { 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, @@ -309,7 +311,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { 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> { @@ -317,16 +319,16 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, '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> { @@ -675,7 +677,7 @@ fn subst_ty_renumber_bound() { 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) @@ -710,7 +712,7 @@ fn subst_ty_renumber_some_bounds() { 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)) @@ -772,7 +774,7 @@ fn subst_region_renumber_region() { 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) diff --git a/src/librustc_metadata/astencode.rs b/src/librustc_metadata/astencode.rs index ad52d346857ff..0236f9c413ddc 100644 --- a/src/librustc_metadata/astencode.rs +++ b/src/librustc_metadata/astencode.rs @@ -517,7 +517,7 @@ pub fn encode_cast_kind(ebml_w: &mut Encoder, kind: cast::CastKind) { // 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>); @@ -531,7 +531,7 @@ trait rbml_writer_helpers<'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))); @@ -617,7 +617,7 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> { &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)) }) } @@ -824,7 +824,7 @@ trait rbml_decoder_decoder_helpers<'tcx> { 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>; fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) @@ -835,8 +835,8 @@ trait rbml_decoder_decoder_helpers<'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>) @@ -908,7 +908,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 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 @@ -948,7 +948,8 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { .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| { @@ -1032,7 +1033,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { 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(); @@ -1041,7 +1042,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> { Decodable::decode(this) }).unwrap(); - adjustment::AutoPtr(dcx.tcx.mk_region(r), m) + adjustment::AutoPtr(r, m) } 1 => { let m: hir::Mutability = diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs index 94426dcbf1d8d..0fd7b683067b7 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -73,7 +73,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { decoder::closure_ty(&cdata, def_id.index, tcx) } - fn item_variances(&self, def: DefId) -> ty::ItemVariances { + fn item_variances(&self, def: DefId) -> Vec { self.dep_graph.read(DepNode::MetaData(def)); let cdata = self.get_crate_data(def.krate); decoder::get_item_variances(&cdata, def.index) @@ -291,13 +291,6 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore { 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) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index b0335258b4041..bbda089b1c2a8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -859,7 +859,8 @@ pub fn maybe_get_item_mir<'a, 'tcx>(cdata: Cmd, } } -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, @@ -879,7 +880,7 @@ fn get_explicit_self(item: rbml::Doc) -> ty::ExplicitSelfCategory { // 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) @@ -905,16 +906,6 @@ pub fn get_trait_name(cdata: Cmd, id: DefIndex) -> ast::Name { 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> { let item_doc = cdata.lookup_item(id); @@ -959,7 +950,7 @@ pub fn get_impl_or_trait_item<'a, 'tcx>(cdata: Cmd, id: DefIndex, tcx: TyCtxt<'a "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, @@ -1000,7 +991,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: DefIndex) }).collect() } -pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> ty::ItemVariances { +pub fn get_item_variances(cdata: Cmd, id: DefIndex) -> Vec { 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); diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index c76cf23639237..f51299226fe7d 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -20,7 +20,7 @@ use rustc::hir; 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; @@ -129,19 +129,19 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } 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> { @@ -207,8 +207,8 @@ impl<'a,'tcx> TyDecoder<'a,'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()); @@ -245,7 +245,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { 'e' => ty::ReEmpty, 'E' => ty::ReErased, _ => bug!("parse_region: bad input") - } + }) } fn parse_scope(&mut self) -> region::CodeExtent { @@ -403,9 +403,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { '~' => 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(); @@ -657,7 +655,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } } - 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(); @@ -681,7 +679,7 @@ impl<'a,'tcx> TyDecoder<'a,'tcx> { } - 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, diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 90fd8a0eb2f65..7255eae61d453 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -133,7 +133,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx 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) => { @@ -251,12 +251,16 @@ fn enc_opt(w: &mut Cursor>, t: Option, enc_f: F) where pub fn enc_substs<'a, 'tcx>(w: &mut Cursor>, 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, "]"); } @@ -286,8 +290,8 @@ pub fn enc_generics<'a, 'tcx>(w: &mut Cursor>, cx: &ctxt<'a, 'tcx>, } } -pub fn enc_region(w: &mut Cursor>, cx: &ctxt, r: ty::Region) { - match r { +pub fn enc_region(w: &mut Cursor>, cx: &ctxt, r: &ty::Region) { + match *r { ty::ReLateBound(id, br) => { write!(w, "b[{}|", id.depth); enc_bound_region(w, cx, br); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index ec390704d0789..1b64b4d0b5317 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -278,7 +278,7 @@ struct Binding<'tcx> { var_id: NodeId, var_ty: Ty<'tcx>, mutability: Mutability, - binding_mode: BindingMode, + binding_mode: BindingMode<'tcx>, } #[derive(Clone, Debug)] diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 8c9ed53c8ab4d..bf43bfb326a58 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -293,7 +293,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { 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); diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 2f83c0ef1bebb..0b33e5a145083 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -89,13 +89,15 @@ should go to. 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, @@ -789,7 +791,7 @@ fn build_free<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, -> 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, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index a61fdb79df822..6e8a5771eea94 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -108,7 +108,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { 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() } @@ -137,7 +137,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { ty: adjusted_ty, span: self.span, kind: ExprKind::Borrow { - region: *r, + region: r, borrow_kind: to_borrow_kind(m), arg: expr.to_ref(), }, @@ -154,7 +154,7 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { 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(), }, @@ -310,7 +310,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, _ => span_bug!(expr.span, "type of & not region"), }; ExprKind::Borrow { - region: *region, + region: region, borrow_kind: to_borrow_kind(mutbl), arg: expr.to_ref(), } @@ -842,8 +842,7 @@ fn convert_var<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, 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() @@ -907,8 +906,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } 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() @@ -922,7 +920,7 @@ fn overloaded_operator<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, 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() diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 972e7f5be7075..a38b429333b70 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -144,10 +144,10 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { trait_def_id: DefId, method_name: &str, self_ty: Ty<'tcx>, - params: Vec>) + 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) => { diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index c54c8bfb5981e..0bd22cd2d9308 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -161,7 +161,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> { 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 { diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 2a5b7d0fb2902..353f243335302 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -193,7 +193,7 @@ pub enum ExprKind<'tcx> { id: DefId, }, Borrow { - region: Region, + region: &'tcx Region, borrow_kind: BorrowKind, arg: ExprRef<'tcx>, }, @@ -284,7 +284,7 @@ pub enum PatternKind<'tcx> { Binding { mutability: Mutability, name: ast::Name, - mode: BindingMode, + mode: BindingMode<'tcx>, var: ast::NodeId, ty: Ty<'tcx>, subpattern: Option>, @@ -332,9 +332,9 @@ pub enum PatternKind<'tcx> { } #[derive(Copy, Clone, Debug)] -pub enum BindingMode { +pub enum BindingMode<'tcx> { ByValue, - ByRef(Region, BorrowKind), + ByRef(&'tcx Region, BorrowKind), } #[derive(Clone, Debug)] diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index bcdc0d2ea3f9d..32c78ca4a5ad1 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -543,7 +543,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { 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, diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index b116ab7b3161a..4aae6d690c4df 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -683,7 +683,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> { 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. diff --git a/src/librustc_passes/rvalues.rs b/src/librustc_passes/rvalues.rs index 782ee34edd4f9..c3ef5a72a2944 100644 --- a/src/librustc_passes/rvalues.rs +++ b/src/librustc_passes/rvalues.rs @@ -88,7 +88,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for RvalueContextDelegate<'a, 'gcx, 'tc _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) { } diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs index 25a1479c28948..9b02cbe6721f3 100644 --- a/src/librustc_trans/back/symbol_names.rs +++ b/src/librustc_trans/back/symbol_names.rs @@ -104,8 +104,9 @@ use util::sha2::{Digest, Sha256}; 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; @@ -126,14 +127,14 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, // 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(); @@ -154,11 +155,13 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, '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)); @@ -252,7 +255,7 @@ impl<'a, 'tcx> Instance<'tcx> { // 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()) @@ -282,14 +285,14 @@ impl ItemPathBuffer for SymbolPathBuffer { } 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[..])) } @@ -297,7 +300,7 @@ pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, /// 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(), @@ -306,7 +309,7 @@ pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx> 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[..])) } diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 165884c8f55a2..5e431193a2c4c 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -514,7 +514,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx -> 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) { diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 9aa486dc62811..a30f8f291a677 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -400,9 +400,9 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, 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); diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 76910304eebb0..8dd76535cf811 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -753,7 +753,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, .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, @@ -1235,7 +1235,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 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, diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs index c5053e4feee62..5055ed86a0386 100644 --- a/src/librustc_trans/common.rs +++ b/src/librustc_trans/common.rs @@ -265,7 +265,7 @@ pub fn BuilderRef_res(b: BuilderRef) -> BuilderRef_res { } 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 diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 0a295b251b31e..71184dd3f814d 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -563,7 +563,9 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { /// 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) }) } diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index fccb326b23221..67d4a0e044c9c 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -342,11 +342,10 @@ impl<'tcx> TypeMap<'tcx> { // 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 = diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs index 73ed7a5510f3a..5e248261e1185 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -344,37 +344,35 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, 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 { diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 2a996ca75a37e..f757578e6954d 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -175,13 +175,13 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, 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(", "); } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index 6a072c84dd9b3..f29d85f3b52f0 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -302,7 +302,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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, diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 7faff98aea442..8bef7584db9e2 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -146,12 +146,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, 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]); @@ -162,11 +162,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } (_, "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]); @@ -176,12 +176,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } } (_, "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] @@ -199,15 +199,15 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, 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); @@ -219,7 +219,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, 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)) } @@ -238,7 +238,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, false, false, - substs.types[0], + substs.type_at(0), llargs[1], llargs[0], llargs[2], @@ -248,7 +248,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, true, false, - substs.types[0], + substs.type_at(0), llargs[1], llargs[0], llargs[2], @@ -257,7 +257,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "write_bytes") => { memset_intrinsic(bcx, false, - substs.types[0], + substs.type_at(0), llargs[0], llargs[1], llargs[2], @@ -268,7 +268,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, false, true, - substs.types[0], + substs.type_at(0), llargs[0], llargs[1], llargs[2], @@ -278,7 +278,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, copy_intrinsic(bcx, true, true, - substs.types[0], + substs.type_at(0), llargs[0], llargs[1], llargs[2], @@ -287,14 +287,14 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, (_, "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()); @@ -306,7 +306,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, 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])); @@ -406,7 +406,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, }, (_, "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); @@ -458,7 +458,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, 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], @@ -477,7 +477,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "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 { @@ -490,7 +490,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } "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 { @@ -529,7 +529,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, _ => 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 { diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs index 97c77ee3d8c72..483bc99c310fc 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -265,7 +265,7 @@ pub fn get_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 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 @@ -307,7 +307,7 @@ pub fn get_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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); diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 020ac8d643b86..0ffb83067f91c 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -32,7 +32,7 @@ impl<'tcx> fmt::Display for Instance<'tcx> { 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> { diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 87d0ea0fe81f3..7341e8db41de5 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -342,7 +342,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, '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. @@ -487,7 +487,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 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)); } diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 90dcc3a61fd7e..2c91c408487b8 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -171,8 +171,8 @@ impl<'a, 'tcx> TransItem<'tcx> { 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); @@ -244,7 +244,7 @@ impl<'a, 'tcx> TransItem<'tcx> { 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[..]) } @@ -264,8 +264,9 @@ impl<'a, 'tcx> TransItem<'tcx> { 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, } @@ -273,7 +274,9 @@ impl<'a, 'tcx> TransItem<'tcx> { 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, } @@ -374,7 +377,7 @@ impl<'a, 'tcx> TransItem<'tcx> { /// 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"), @@ -396,7 +399,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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('('); @@ -446,7 +449,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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); }, @@ -494,7 +497,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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(_) | @@ -529,16 +532,16 @@ fn push_item_name(tcx: TyCtxt, } 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(", "); } @@ -562,7 +565,7 @@ fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, 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 { @@ -572,7 +575,7 @@ 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); diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs index 6862002ed83b2..b47d2cd0f204b 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_trans/type_of.rs @@ -17,6 +17,7 @@ use common::*; use machine; use rustc::traits::Reveal; use rustc::ty::{self, Ty, TypeFoldable}; +use rustc::ty::subst::Substs; use type_::Type; @@ -256,7 +257,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // 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(..) => { @@ -330,7 +331,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> // 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[..]) } } @@ -367,10 +368,10 @@ pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) 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 = tps.iter().map(|t| t.to_string()).collect(); + let strings: Vec = substs.types().map(|t| t.to_string()).collect(); let tstr = if strings.is_empty() { base } else { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index f6984f42cab34..f24a7cf2121eb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -178,8 +178,9 @@ type TraitAndProjections<'tcx> = (ty::PolyTraitRef<'tcx>, Vec = 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 @@ -238,7 +239,7 @@ pub fn ast_region_to_region(tcx: TyCtxt, lifetime: &hir::Lifetime) lifetime.id, r); - r + tcx.mk_region(r) } fn report_elision_failure( @@ -313,14 +314,14 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { pub fn opt_ast_region_to_region(&self, rscope: &RegionScope, default_span: Span, - opt_lifetime: &Option) -> ty::Region + opt_lifetime: &Option) -> &'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}; @@ -335,7 +336,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { err.emit(); ty::ReStatic } - } + }) }; debug!("opt_ast_region_to_region(opt_lifetime={:?}) yields {:?}", @@ -366,7 +367,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { .emit(); return Substs::for_item(tcx, def_id, |_, _| { - ty::ReStatic + tcx.mk_region(ty::ReStatic) }, |_, _| { tcx.types.err }); @@ -431,7 +432,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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); @@ -472,7 +473,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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; @@ -481,7 +483,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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 { @@ -588,7 +590,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } if lifetimes_for_params.iter().map(|e| e.lifetime_count).sum::() == 1 { - Ok(possible_implied_output_region.unwrap()) + Ok(*possible_implied_output_region.unwrap()) } else { Err(Some(lifetimes_for_params)) } @@ -937,8 +939,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // 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) @@ -1100,7 +1102,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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, @@ -1108,7 +1110,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { from context; please supply an explicit bound"); ty::ReStatic } - } + }) } }; @@ -1643,7 +1645,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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 @@ -1801,7 +1803,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { sig: &hir::MethodSig, untransformed_self_ty: Ty<'tcx>, anon_scope: Option) - -> (&'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), @@ -1826,7 +1828,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { decl: &hir::FnDecl, arg_anon_scope: Option, ret_anon_scope: Option) - -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory) + -> (&'tcx ty::BareFnTy<'tcx>, ty::ExplicitSelfCategory<'tcx>) { debug!("ty_of_method_or_bare_fn"); @@ -1863,7 +1865,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // 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) }; @@ -1890,7 +1892,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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(..) => { @@ -1902,8 +1904,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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 @@ -1957,7 +1958,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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, } @@ -2070,7 +2071,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { explicit_region_bounds: &[&hir::Lifetime], principal_trait_ref: ty::PolyExistentialTraitRef<'tcx>, builtin_bounds: ty::BuiltinBounds) - -> Option // if None, use the default + -> Option<&'tcx ty::Region> // if None, use the default { let tcx = self.tcx(); @@ -2093,7 +2094,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { 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 @@ -2109,8 +2110,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { // 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 @@ -2242,7 +2243,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected // and return from functions in multiple places. #[derive(PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { - pub region_bounds: Vec, + pub region_bounds: Vec<&'tcx ty::Region>, pub builtin_bounds: ty::BuiltinBounds, pub trait_bounds: Vec>, pub projection_bounds: Vec>, @@ -2264,7 +2265,7 @@ impl<'a, 'gcx, 'tcx> Bounds<'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()); } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 52073359c0fd9..78175c85b19bf 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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 @@ -220,7 +220,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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) } diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 9a3cbabe55331..19261a2447f91 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -101,7 +101,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { 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); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index 377ca5eaebe30..46e8c27f6d33b 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -203,7 +203,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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); diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 4a0d529812891..26a4705528976 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -336,7 +336,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { 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() }; @@ -436,8 +436,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { 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)?; @@ -459,7 +458,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { 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 diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 78476e814006f..1604f34d57552 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -299,11 +299,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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); @@ -318,11 +317,10 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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); @@ -332,65 +330,9 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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); @@ -479,6 +421,86 @@ pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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) { + 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>, diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 82545d564a20c..cede9d871ff4d 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -412,7 +412,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, '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(()); } @@ -438,7 +438,7 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>( ty::TyStruct(def, substs) if def.is_phantom_data() => { // PhantomData - 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) } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 7f9e715b7fafc..ad48827a1d039 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -37,7 +37,7 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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 { diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 9e0b38fd9fe51..be77ca435a18c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -145,7 +145,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { { 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)) })) @@ -327,19 +327,22 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // 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] } }) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c306463ec1de0..a64982cd1bf81 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -519,9 +519,9 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { 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 @@ -529,7 +529,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // 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, @@ -1220,8 +1220,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { // 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; @@ -1236,16 +1236,18 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { 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) } @@ -1262,7 +1264,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { 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) @@ -1324,7 +1326,7 @@ impl<'tcx> Candidate<'tcx> { // 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()) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 573dae46456ba..f9699a55f5068 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 16300d869abf5..e972a5ca7fb38 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -770,7 +770,7 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) { } 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 { @@ -1422,13 +1422,13 @@ impl<'a, 'gcx, 'tcx> RegionScope for FnCtxt<'a, 'gcx, 'tcx> { // (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, Option>> { Ok((0..count).map(|_| { - self.next_region_var(infer::MiscVariable(span)) + *self.next_region_var(infer::MiscVariable(span)) }).collect()) } } @@ -1862,7 +1862,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// 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(); @@ -1893,13 +1893,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // 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); } } @@ -3454,7 +3454,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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); } @@ -4242,18 +4242,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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) { @@ -4269,18 +4274,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } }, |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(|| { @@ -4290,7 +4286,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { i -= has_self as usize; type_segment } else { - i -= type_types; + i -= fn_start; fn_segment }; let types = match segment.map(|(s, _)| &s.parameters) { @@ -4299,6 +4295,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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. @@ -4502,28 +4503,28 @@ pub fn may_break(tcx: TyCtxt, id: ast::NodeId, b: &hir::Block) -> bool { } 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(); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 859d5ff0543d0..cef2bb07e35ca 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -169,7 +169,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { 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, @@ -324,9 +324,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); @@ -407,8 +408,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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) => { @@ -476,9 +477,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // 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); @@ -525,7 +527,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { // 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); @@ -713,7 +715,7 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { 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); @@ -780,9 +782,10 @@ impl<'a, 'gcx, 'tcx, 'v> Visitor<'v> for RegionCtxt<'a, 'gcx, 'tcx> { 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); } @@ -819,7 +822,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /*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); } @@ -889,7 +892,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // // 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); @@ -933,8 +936,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); @@ -989,7 +991,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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) { @@ -1003,8 +1005,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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) } @@ -1014,7 +1016,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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, @@ -1023,7 +1025,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { rvalue_scope); } ty::ReStatic => {} - region => { + _ => { span_bug!(span, "unexpected rvalue region in rvalue \ destructor safety checking: `{:?}`", @@ -1049,7 +1051,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); } _ => {} } @@ -1061,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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; @@ -1132,7 +1134,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, '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, @@ -1168,7 +1170,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); @@ -1182,8 +1184,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } 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); } } } @@ -1197,8 +1199,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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`, @@ -1212,9 +1214,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); } } @@ -1225,14 +1227,14 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// 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={:?})", @@ -1322,10 +1324,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { /// 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)> @@ -1364,7 +1366,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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 @@ -1436,7 +1438,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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={:?}, \ @@ -1445,11 +1447,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); } @@ -1461,7 +1463,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); @@ -1479,7 +1481,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn components_must_outlive(&self, origin: infer::SubregionOrigin<'tcx>, components: Vec>, - region: ty::Region) + region: &'tcx ty::Region) { for component in components { let origin = origin.clone(); @@ -1510,7 +1512,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); @@ -1522,7 +1524,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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={:?})", @@ -1552,7 +1554,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { // 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; } @@ -1575,11 +1577,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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); } @@ -1597,10 +1599,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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; @@ -1617,7 +1616,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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) @@ -1632,7 +1631,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } } - 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={:?})", @@ -1650,7 +1649,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn projection_declared_bounds(&self, span: Span, projection_ty: ty::ProjectionTy<'tcx>) - -> Vec + -> Vec<&'tcx ty::Region> { // First assemble bounds from where clauses and traits. @@ -1665,9 +1664,9 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn projection_bound(&self, span: Span, - declared_bounds: Vec, + 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); @@ -1679,7 +1678,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { 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() { @@ -1701,7 +1700,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { } fn declared_generic_bounds_from_env(&self, generic: GenericKind<'tcx>) - -> Vec + -> Vec<&'tcx ty::Region> { let param_env = &self.parameter_environment; @@ -1735,7 +1734,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { fn declared_projection_bounds_from_trait(&self, span: Span, projection_ty: ty::ProjectionTy<'tcx>) - -> Vec + -> Vec<&'tcx ty::Region> { debug!("projection_bounds(projection_ty={:?})", projection_ty); diff --git a/src/librustc_typeck/check/upvar.rs b/src/librustc_typeck/check/upvar.rs index 030491b521d95..a85e295784e97 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/src/librustc_typeck/check/upvar.rs @@ -252,7 +252,7 @@ impl<'a, 'gcx, 'tcx> AdjustBorrowKind<'a, 'gcx, 'tcx> { 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(), @@ -536,7 +536,7 @@ impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> { 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) { diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index bcad7dd3bd0fa..38ec7ba686f6f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -416,7 +416,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { 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 }) @@ -457,7 +457,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { 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)) @@ -468,22 +468,22 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> { 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); } } @@ -597,7 +597,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // 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 => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index cfc1292c34b78..3bd0e890bb811 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -87,7 +87,7 @@ struct WritebackCx<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> { // 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 + free_to_bound_regions: DefIdMap<&'gcx ty::Region> } impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { @@ -102,16 +102,22 @@ 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); } _ => { @@ -311,9 +317,9 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { // 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 { @@ -331,7 +337,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { 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(_) | @@ -626,12 +632,12 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> { } } - 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) } } } diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d00cbf0221e0e..7d6cee7b3bac1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { 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); @@ -413,7 +413,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { (&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)) } @@ -498,7 +498,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { // Register an obligation for `A: Trait`. 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. diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7e1fb32881d6f..0074d3930e29f 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1486,6 +1486,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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); @@ -1493,6 +1494,7 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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) }); @@ -1500,17 +1502,18 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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::>(); // 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(); @@ -1529,8 +1532,8 @@ fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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 @@ -1741,12 +1744,12 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, -> 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) => { @@ -1762,10 +1765,29 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, }; 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., ``). + 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, @@ -1776,24 +1798,6 @@ fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, 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 { @@ -1919,7 +1923,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, 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); @@ -1937,7 +1941,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, fn from_bounds<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, bounds: &[hir::TyParamBound]) - -> Vec + -> Vec<&'tcx ty::Region> { bounds.iter() .filter_map(|bound| { @@ -1954,7 +1958,7 @@ fn compute_object_lifetime_default<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, fn from_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, param_id: ast::NodeId, predicates: &[hir::WherePredicate]) - -> Vec + -> Vec<&'tcx ty::Region> { predicates.iter() .flat_map(|predicate| { @@ -2126,7 +2130,7 @@ pub fn mk_item_substs<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, } 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)) } diff --git a/src/librustc_typeck/constrained_type_params.rs b/src/librustc_typeck/constrained_type_params.rs index 7d3bd095a3a88..637df52e3cb03 100644 --- a/src/librustc_typeck/constrained_type_params.rs +++ b/src/librustc_typeck/constrained_type_params.rs @@ -58,8 +58,8 @@ impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { 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)); } diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 8a8232535c775..2a989105c9cb4 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -172,7 +172,7 @@ fn write_substs_to_tcx<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, 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); } diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index 9aca779dd89c4..f5b13c4207d90 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -257,12 +257,12 @@ impl RegionScope for BindingRscope { /// 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 { @@ -283,7 +283,7 @@ impl<'r> RegionScope for ObjectLifetimeDefaultRscope<'r> { Some(self.base_object_lifetime_default(span)), ty::ObjectLifetimeDefault::Specific(r) => - Some(r), + Some(*r), } } diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 536fa629fd611..2cf84b5745af4 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -26,7 +26,6 @@ use rustc::hir::intravisit::Visitor; use super::terms::*; use super::terms::VarianceTerm::*; -use super::terms::ParamKind::*; use super::xform::*; pub struct ConstraintContext<'a, 'tcx: 'a> { @@ -209,7 +208,6 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { 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); @@ -224,11 +222,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { // 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]) } } @@ -330,7 +324,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { 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); } @@ -401,8 +395,11 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { 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) => { @@ -449,7 +446,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { 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={:?}", @@ -459,7 +456,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { 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); @@ -483,13 +480,13 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { /// 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); diff --git a/src/librustc_typeck/variance/solve.rs b/src/librustc_typeck/variance/solve.rs index d3b63119bcb32..82b63d0cc0937 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/src/librustc_typeck/variance/solve.rs @@ -21,7 +21,6 @@ use std::rc::Rc; use super::constraints::*; use super::terms::*; use super::terms::VarianceTerm::*; -use super::terms::ParamKind::*; use super::xform::*; struct SolveContext<'a, 'tcx: 'a> { @@ -109,24 +108,16 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { 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; } diff --git a/src/librustc_typeck/variance/terms.rs b/src/librustc_typeck/variance/terms.rs index d30cbc8f117cf..c0b53787177d5 100644 --- a/src/librustc_typeck/variance/terms.rs +++ b/src/librustc_typeck/variance/terms.rs @@ -31,7 +31,6 @@ use rustc::hir::intravisit::Visitor; use util::nodemap::NodeMap; use self::VarianceTerm::*; -use self::ParamKind::*; pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>; @@ -61,7 +60,7 @@ pub struct TermsContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, pub arena: &'a TypedArena>, - pub empty_variances: Rc, + pub empty_variances: Rc>, // For marker types, UnsafeCell, and other lang items where // variance is hardcoded, records the item-id and the hardcoded @@ -76,15 +75,8 @@ pub struct TermsContext<'a, 'tcx: 'a> { pub inferred_infos: Vec> , } -#[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>, @@ -110,7 +102,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>( // 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. @@ -162,17 +154,19 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { 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, @@ -194,14 +188,12 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { 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, @@ -211,13 +203,12 @@ impl<'a, 'tcx> TermsContext<'a, 'tcx> { 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); } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e2e655ce38bcc..c8620254b6f42 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -642,8 +642,8 @@ impl Clean for hir::TyParamBound { fn external_path_params(cx: &DocContext, trait_did: Option, has_self: bool, bindings: Vec, 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::>(); match (trait_did, cx.tcx_opt()) { // Attempt to sugar an external path like Fn<(A, B,), C> to Fn(A, B) -> C @@ -737,12 +737,11 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { 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 { @@ -775,9 +774,9 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { impl<'tcx> Clean>> for Substs<'tcx> { fn clean(&self, cx: &DocContext) -> Option> { 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))); @@ -822,7 +821,7 @@ impl Clean for hir::LifetimeDef { } } -impl Clean for ty::RegionParameterDef { +impl<'tcx> Clean for ty::RegionParameterDef<'tcx> { fn clean(&self, _: &DocContext) -> Lifetime { Lifetime(self.name.to_string()) } @@ -914,7 +913,7 @@ impl<'tcx> Clean for ty::EquatePredicate<'tcx> { } } -impl Clean for ty::OutlivesPredicate { +impl<'tcx> Clean 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 { @@ -924,7 +923,7 @@ impl Clean for ty::OutlivesPredicate { } } -impl<'tcx> Clean for ty::OutlivesPredicate, ty::Region> { +impl<'tcx> Clean for ty::OutlivesPredicate, &'tcx ty::Region> { fn clean(&self, cx: &DocContext) -> WherePredicate { let ty::OutlivesPredicate(ref ty, ref lt) = *self; diff --git a/src/libstd/error.rs b/src/libstd/error.rs index 44595361fb57c..ab537f39bf96a 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -54,7 +54,6 @@ use fmt::{self, Debug, Display}; use marker::Reflect; use mem::transmute; use num; -use raw::TraitObject; use str; use string; @@ -326,11 +325,7 @@ impl Error + 'static { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { 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 @@ -344,11 +339,7 @@ impl Error + 'static { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { 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 @@ -409,13 +400,8 @@ impl Error { pub fn downcast(self: Box) -> Result, Box> { if self.is::() { 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) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 031d9a2d3f46e..26599208ec009 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -491,18 +491,7 @@ fn expand_trait_item(ti: ast::TraitItem, fld: &mut MacroExpander) pub fn expand_type(t: P, fld: &mut MacroExpander) -> P { 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 }; diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d746f8e21141f..dc68e06463464 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -213,9 +213,6 @@ declare_features! ( // 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)), @@ -321,6 +318,8 @@ declare_features! ( // 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)) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9443df6321bd0..1646246069ead 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4087,9 +4087,30 @@ impl<'a> Parser<'a> { 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) diff --git a/src/test/compile-fail/issue-30007.rs b/src/test/compile-fail/issue-30007.rs index 95a52cb232a49..fa0b75da999c2 100644 --- a/src/test/compile-fail/issue-30007.rs +++ b/src/test/compile-fail/issue-30007.rs @@ -8,8 +8,6 @@ // 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 `;` } diff --git a/src/test/compile-fail/issue-32950.rs b/src/test/compile-fail/issue-32950.rs index e8ca1c1fa98ff..20e5b1d72d3d7 100644 --- a/src/test/compile-fail/issue-32950.rs +++ b/src/test/compile-fail/issue-32950.rs @@ -8,7 +8,7 @@ // 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( diff --git a/src/test/compile-fail/issue-35869.rs b/src/test/compile-fail/issue-35869.rs new file mode 100644 index 0000000000000..8b7fc80bdb6b7 --- /dev/null +++ b/src/test/compile-fail/issue-35869.rs @@ -0,0 +1,37 @@ +// 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 or the MIT license +// , 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); //~ 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) {} + //~^ 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() {} diff --git a/src/test/compile-fail/macro-context.rs b/src/test/compile-fail/macro-context.rs index 5d07f0747ff43..4aa0a3023bb10 100644 --- a/src/test/compile-fail/macro-context.rs +++ b/src/test/compile-fail/macro-context.rs @@ -8,8 +8,6 @@ // 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` diff --git a/src/test/compile-fail/macro-error.rs b/src/test/compile-fail/macro-error.rs index a69188da58d16..4a6dbf014a1ca 100644 --- a/src/test/compile-fail/macro-error.rs +++ b/src/test/compile-fail/macro-error.rs @@ -8,8 +8,6 @@ // 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 } diff --git a/src/test/compile-fail/type-macros-fail.rs b/src/test/compile-fail/missing-block-hint.rs similarity index 59% rename from src/test/compile-fail/type-macros-fail.rs rename to src/test/compile-fail/missing-block-hint.rs index 4712e2b65e16a..1f29ff4e05c09 100644 --- a/src/test/compile-fail/type-macros-fail.rs +++ b/src/test/compile-fail/missing-block-hint.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -macro_rules! Id { - ($T:tt) => ($T); -} - -struct Foo { - x: Id!(T) - //~^ ERROR: type macros are experimental (see issue #27245) -} - fn main() { - let foo = Foo { x: i32 }; + { + if (foo) => {} //~ ERROR expected `{`, found `=>` + } + { + if (foo) + bar; //~ ERROR expected `{`, found `bar` + //^ HELP try placing this code inside a block + } } diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs index 9cc53386d465c..f3dcf405a68a6 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test.rs @@ -8,7 +8,7 @@ // 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 = (); diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs index 01466c6a85a5a..3bf8ca30a6c3f 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test2.rs @@ -8,7 +8,7 @@ // 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) => { diff --git a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs index ef187a1daed37..febe224fb84dc 100644 --- a/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs +++ b/src/test/compile-fail/privacy/restricted/tuple-struct-fields/test3.rs @@ -8,7 +8,7 @@ // 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) => { diff --git a/src/test/compile-fail/syntax-extension-minor.rs b/src/test/compile-fail/syntax-extension-minor.rs index 3e36b126523a7..f06e3544e575d 100644 --- a/src/test/compile-fail/syntax-extension-minor.rs +++ b/src/test/compile-fail/syntax-extension-minor.rs @@ -8,7 +8,7 @@ // 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; diff --git a/src/test/compile-fail/variance-associated-types.rs b/src/test/compile-fail/variance-associated-types.rs index 5539a26d2a170..7dbfc6ac1257d 100644 --- a/src/test/compile-fail/variance-associated-types.rs +++ b/src/test/compile-fail/variance-associated-types.rs @@ -20,12 +20,12 @@ trait Trait<'a> { } #[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: >::Type } diff --git a/src/test/compile-fail/variance-object-types.rs b/src/test/compile-fail/variance-object-types.rs index 2f422bfd38cc7..1f54771e3676a 100644 --- a/src/test/compile-fail/variance-object-types.rs +++ b/src/test/compile-fail/variance-object-types.rs @@ -18,7 +18,7 @@ use std::cell::Cell; // 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 &'a i32 + 'static> } diff --git a/src/test/compile-fail/variance-region-bounds.rs b/src/test/compile-fail/variance-region-bounds.rs index 99416057b2540..41d204a541b5a 100644 --- a/src/test/compile-fail/variance-region-bounds.rs +++ b/src/test/compile-fail/variance-region-bounds.rs @@ -13,11 +13,11 @@ #![feature(rustc_attrs)] #[rustc_variance] -trait Foo: 'static { //~ ERROR types=[o] +trait Foo: 'static { //~ ERROR [o] } #[rustc_variance] -trait Bar { //~ ERROR types=[o, o] +trait Bar { //~ ERROR [o, o] fn do_it(&self) where T: 'static; } diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index 78591063de8ab..bf46edcfab8b1 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -16,7 +16,7 @@ // 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 @@ -25,7 +25,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[-, -, -] // 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), @@ -34,7 +34,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[+, +, +] // 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, } @@ -42,7 +42,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[-, o] // 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), } @@ -52,14 +52,14 @@ struct Test5<'a, 'b:'a> { //~ ERROR regions=[+, o] // 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 } @@ -67,7 +67,7 @@ struct Test7<'a> { //~ ERROR regions=[*] // 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), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index d8af30da163bf..e28828f62e52d 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -15,7 +15,7 @@ #![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]), @@ -23,25 +23,25 @@ enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[+, -, o, *] } #[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> } diff --git a/src/test/compile-fail/variance-trait-bounds.rs b/src/test/compile-fail/variance-trait-bounds.rs index 150a1aa56fe72..4c737a7594d26 100644 --- a/src/test/compile-fail/variance-trait-bounds.rs +++ b/src/test/compile-fail/variance-trait-bounds.rs @@ -15,48 +15,48 @@ // influence variance. #[rustc_variance] -trait Getter { //~ ERROR types=[o, o] +trait Getter { //~ ERROR [o, o] fn get(&self) -> T; } #[rustc_variance] -trait Setter { //~ ERROR types=[o, o] +trait Setter { //~ ERROR [o, o] fn get(&self, T); } #[rustc_variance] -struct TestStruct> { //~ ERROR types=[+, +] +struct TestStruct> { //~ ERROR [+, +] t: T, u: U } #[rustc_variance] -enum TestEnum> {//~ ERROR types=[*, +] +enum TestEnum> {//~ ERROR [*, +] //~^ ERROR parameter `U` is never used Foo(T) } #[rustc_variance] -trait TestTrait> { //~ ERROR types=[o, o, o] +trait TestTrait> { //~ ERROR [o, o, o] fn getter(&self, u: U) -> T; } #[rustc_variance] -trait TestTrait2 : Getter { //~ ERROR types=[o, o] +trait TestTrait2 : Getter { //~ ERROR [o, o] } #[rustc_variance] -trait TestTrait3 { //~ ERROR types=[o, o] +trait TestTrait3 { //~ ERROR [o, o] fn getter>(&self); } #[rustc_variance] -struct TestContraStruct> { //~ ERROR types=[*, +] +struct TestContraStruct> { //~ ERROR [*, +] //~^ ERROR parameter `U` is never used t: T } #[rustc_variance] -struct TestBox+Setter> { //~ ERROR types=[*, +] +struct TestBox+Setter> { //~ ERROR [*, +] //~^ ERROR parameter `U` is never used t: T } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index 4244b0e1d8b8b..b120588ecab52 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -21,7 +21,7 @@ use std::mem; trait T { fn foo(&self); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[-] +struct TOption<'a> { //~ ERROR [-] v: Option>, } diff --git a/src/test/compile-fail/variance-types-bounds.rs b/src/test/compile-fail/variance-types-bounds.rs index c47710d6d376d..2df94cc907a9c 100644 --- a/src/test/compile-fail/variance-types-bounds.rs +++ b/src/test/compile-fail/variance-types-bounds.rs @@ -14,46 +14,46 @@ #![feature(rustc_attrs)] #[rustc_variance] -struct TestImm { //~ ERROR types=[+, +] +struct TestImm { //~ ERROR [+, +] x: A, y: B, } #[rustc_variance] -struct TestMut { //~ ERROR types=[+, o] +struct TestMut { //~ ERROR [+, o] x: A, y: &'static mut B, } #[rustc_variance] -struct TestIndirect { //~ ERROR types=[+, o] +struct TestIndirect { //~ ERROR [+, o] m: TestMut } #[rustc_variance] -struct TestIndirect2 { //~ ERROR types=[o, o] +struct TestIndirect2 { //~ ERROR [o, o] n: TestMut, m: TestMut } #[rustc_variance] -trait Getter { //~ ERROR types=[o, o] +trait Getter { //~ ERROR [o, o] fn get(&self) -> A; } #[rustc_variance] -trait Setter { //~ ERROR types=[o, o] +trait Setter { //~ ERROR [o, o] fn set(&mut self, a: A); } #[rustc_variance] -trait GetterSetter { //~ ERROR types=[o, o] +trait GetterSetter { //~ ERROR [o, o] fn get(&self) -> A; fn set(&mut self, a: A); } #[rustc_variance] -trait GetterInTypeBound { //~ ERROR types=[o, o] +trait GetterInTypeBound { //~ 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`. Since this dictionary is an input, it is @@ -63,12 +63,12 @@ trait GetterInTypeBound { //~ ERROR types=[o, o] } #[rustc_variance] -trait SetterInTypeBound { //~ ERROR types=[o, o] +trait SetterInTypeBound { //~ ERROR [o, o] fn do_it>(&self); } #[rustc_variance] -struct TestObject { //~ ERROR types=[o, o] +struct TestObject { //~ ERROR [o, o] n: Box+Send>, m: Box+Send>, } diff --git a/src/test/compile-fail/variance-types.rs b/src/test/compile-fail/variance-types.rs index d5164412358fc..7667972c9d251 100644 --- a/src/test/compile-fail/variance-types.rs +++ b/src/test/compile-fail/variance-types.rs @@ -17,32 +17,32 @@ use std::cell::Cell; // 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 { //~ ERROR types=[o] +struct InvariantCell { //~ ERROR [o] t: Cell } #[rustc_variance] -struct InvariantIndirect { //~ ERROR types=[o] +struct InvariantIndirect { //~ ERROR [o] t: InvariantCell } #[rustc_variance] -struct Covariant { //~ ERROR types=[+] +struct Covariant { //~ ERROR [+] t: A, u: fn() -> A } #[rustc_variance] -struct Contravariant { //~ ERROR types=[-] +struct Contravariant { //~ ERROR [-] t: fn(A) } #[rustc_variance] -enum Enum { //~ ERROR types=[+, -, o] +enum Enum { //~ ERROR [+, -, o] Foo(Covariant), Bar(Contravariant), Zed(Covariant,Contravariant) diff --git a/src/test/run-pass/simd-intrinsic-generic-cast.rs b/src/test/run-pass/simd-intrinsic-generic-cast.rs index a20dd3ef72a54..2efd9333999b2 100644 --- a/src/test/run-pass/simd-intrinsic-generic-cast.rs +++ b/src/test/run-pass/simd-intrinsic-generic-cast.rs @@ -8,8 +8,7 @@ // 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; diff --git a/src/test/run-pass/type-macros-hlist.rs b/src/test/run-pass/type-macros-hlist.rs index 803b0eae99e88..84c0983de80c8 100644 --- a/src/test/run-pass/type-macros-hlist.rs +++ b/src/test/run-pass/type-macros-hlist.rs @@ -8,8 +8,6 @@ // 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)] diff --git a/src/test/run-pass/type-macros-simple.rs b/src/test/run-pass/type-macros-simple.rs index 22dfd507f7e2e..7d1045cf3f1a8 100644 --- a/src/test/run-pass/type-macros-simple.rs +++ b/src/test/run-pass/type-macros-simple.rs @@ -8,8 +8,6 @@ // 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) } }