From 72d629caa50fa482dd4165cb43b9fb02ac24c8d8 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 23 Aug 2016 18:23:31 +1200 Subject: [PATCH 01/10] Improve error message when failing to parse a block We want to catch this error: ``` if (foo) bar; ``` as it's valid syntax in other languages, and say how to fix it. Unfortunately it didn't care if the suggestion made sense and just highlighted the unexpected token. Now it attempts to parse a statement, and if it succeeds, it shows the help message. Fixes #35907 --- src/libsyntax/parse/parser.rs | 27 ++++++++++++++++++--- src/test/compile-fail/missing-block-hint.rs | 20 +++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/missing-block-hint.rs 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/missing-block-hint.rs b/src/test/compile-fail/missing-block-hint.rs new file mode 100644 index 0000000000000..1f29ff4e05c09 --- /dev/null +++ b/src/test/compile-fail/missing-block-hint.rs @@ -0,0 +1,20 @@ +// 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. + +fn main() { + { + if (foo) => {} //~ ERROR expected `{`, found `=>` + } + { + if (foo) + bar; //~ ERROR expected `{`, found `bar` + //^ HELP try placing this code inside a block + } +} From 00d4a43d84d5979332dbbbc4329211b007f7fe45 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 29 Jul 2016 18:56:09 -0400 Subject: [PATCH 02/10] Remove style guide. We originally imported this into the repository with the intent of fixing it up. Instead, nothing happened. Its appearance on rust-lang.org makes it seem semi-official, but it's not. The rustfmt strike team will end up producing something like this anyway, and leaving it around does nothing but mislead people. --- src/doc/style/README.md | 64 ------ src/doc/style/SUMMARY.md | 50 ----- src/doc/style/errors/README.md | 3 - src/doc/style/errors/ergonomics.md | 66 ------ src/doc/style/errors/handling.md | 7 - src/doc/style/errors/propagation.md | 8 - src/doc/style/errors/signaling.md | 125 ----------- src/doc/style/features/README.md | 9 - src/doc/style/features/crates.md | 6 - .../features/functions-and-methods/README.md | 44 ---- .../functions-and-methods/convenience.md | 43 ---- .../features/functions-and-methods/input.md | 203 ------------------ .../features/functions-and-methods/output.md | 56 ----- src/doc/style/features/let.md | 103 --------- src/doc/style/features/loops.md | 13 -- src/doc/style/features/match.md | 26 --- src/doc/style/features/modules.md | 133 ------------ src/doc/style/features/traits/README.md | 22 -- src/doc/style/features/traits/common.md | 71 ------ src/doc/style/features/traits/extensions.md | 7 - src/doc/style/features/traits/generics.md | 67 ------ src/doc/style/features/traits/objects.md | 49 ----- src/doc/style/features/traits/overloading.md | 7 - src/doc/style/features/traits/reuse.md | 30 --- src/doc/style/features/types/README.md | 68 ------ src/doc/style/features/types/conversions.md | 22 -- src/doc/style/features/types/newtype.md | 69 ------ src/doc/style/ownership/README.md | 3 - src/doc/style/ownership/builders.md | 176 --------------- src/doc/style/ownership/cell-smart.md | 4 - src/doc/style/ownership/constructors.md | 62 ------ src/doc/style/ownership/destructors.md | 22 -- src/doc/style/ownership/raii.md | 12 -- src/doc/style/platform.md | 7 - src/doc/style/safety/README.md | 19 -- src/doc/style/safety/lib-guarantees.md | 81 ------- src/doc/style/safety/unsafe.md | 22 -- src/doc/style/style/README.md | 5 - src/doc/style/style/braces.md | 77 ------- src/doc/style/style/comments.md | 122 ----------- src/doc/style/style/features.md | 13 -- src/doc/style/style/imports.md | 50 ----- src/doc/style/style/naming/README.md | 115 ---------- src/doc/style/style/naming/containers.md | 69 ------ src/doc/style/style/naming/conversions.md | 32 --- src/doc/style/style/naming/iterators.md | 32 --- src/doc/style/style/naming/ownership.md | 34 --- src/doc/style/style/optional.md | 3 - src/doc/style/style/organization.md | 14 -- src/doc/style/style/whitespace.md | 133 ------------ src/doc/style/testing/README.md | 5 - src/doc/style/testing/unit.md | 30 --- src/doc/style/todo.md | 5 - 53 files changed, 2518 deletions(-) delete mode 100644 src/doc/style/README.md delete mode 100644 src/doc/style/SUMMARY.md delete mode 100644 src/doc/style/errors/README.md delete mode 100644 src/doc/style/errors/ergonomics.md delete mode 100644 src/doc/style/errors/handling.md delete mode 100644 src/doc/style/errors/propagation.md delete mode 100644 src/doc/style/errors/signaling.md delete mode 100644 src/doc/style/features/README.md delete mode 100644 src/doc/style/features/crates.md delete mode 100644 src/doc/style/features/functions-and-methods/README.md delete mode 100644 src/doc/style/features/functions-and-methods/convenience.md delete mode 100644 src/doc/style/features/functions-and-methods/input.md delete mode 100644 src/doc/style/features/functions-and-methods/output.md delete mode 100644 src/doc/style/features/let.md delete mode 100644 src/doc/style/features/loops.md delete mode 100644 src/doc/style/features/match.md delete mode 100644 src/doc/style/features/modules.md delete mode 100644 src/doc/style/features/traits/README.md delete mode 100644 src/doc/style/features/traits/common.md delete mode 100644 src/doc/style/features/traits/extensions.md delete mode 100644 src/doc/style/features/traits/generics.md delete mode 100644 src/doc/style/features/traits/objects.md delete mode 100644 src/doc/style/features/traits/overloading.md delete mode 100644 src/doc/style/features/traits/reuse.md delete mode 100644 src/doc/style/features/types/README.md delete mode 100644 src/doc/style/features/types/conversions.md delete mode 100644 src/doc/style/features/types/newtype.md delete mode 100644 src/doc/style/ownership/README.md delete mode 100644 src/doc/style/ownership/builders.md delete mode 100644 src/doc/style/ownership/cell-smart.md delete mode 100644 src/doc/style/ownership/constructors.md delete mode 100644 src/doc/style/ownership/destructors.md delete mode 100644 src/doc/style/ownership/raii.md delete mode 100644 src/doc/style/platform.md delete mode 100644 src/doc/style/safety/README.md delete mode 100644 src/doc/style/safety/lib-guarantees.md delete mode 100644 src/doc/style/safety/unsafe.md delete mode 100644 src/doc/style/style/README.md delete mode 100644 src/doc/style/style/braces.md delete mode 100644 src/doc/style/style/comments.md delete mode 100644 src/doc/style/style/features.md delete mode 100644 src/doc/style/style/imports.md delete mode 100644 src/doc/style/style/naming/README.md delete mode 100644 src/doc/style/style/naming/containers.md delete mode 100644 src/doc/style/style/naming/conversions.md delete mode 100644 src/doc/style/style/naming/iterators.md delete mode 100644 src/doc/style/style/naming/ownership.md delete mode 100644 src/doc/style/style/optional.md delete mode 100644 src/doc/style/style/organization.md delete mode 100644 src/doc/style/style/whitespace.md delete mode 100644 src/doc/style/testing/README.md delete mode 100644 src/doc/style/testing/unit.md delete mode 100644 src/doc/style/todo.md 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]() From 57719e2d73acdda337d1f68640ab551226cbe404 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 25 Aug 2016 15:20:31 -0400 Subject: [PATCH 03/10] Also remove build steps for style --- mk/docs.mk | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) 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 From 14b4d72e01708a82e3d070f72ac87988f08df7da Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Aug 2016 21:10:19 +0300 Subject: [PATCH 04/10] rustc_borrowck: Don't hash types in loan paths --- src/librustc_borrowck/borrowck/mod.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 225895adefa4b..9ab6aaa95630a 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); } } From 2b10df7f24828b09759277cc3a9c18c493c38ce0 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner Date: Thu, 25 Aug 2016 20:56:47 -0400 Subject: [PATCH 05/10] Replace unnecessary uses of `TraitObject` with casts --- src/liballoc/boxed.rs | 9 ++------- src/liballoc/lib.rs | 2 +- src/libcore/any.rs | 14 ++------------ src/libstd/error.rs | 22 ++++------------------ 4 files changed, 9 insertions(+), 38 deletions(-) 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/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) From ee055a1ff37bb47f32ed460ca7d249d91f8cbe7d Mon Sep 17 00:00:00 2001 From: Daniele Baracchi Date: Wed, 24 Aug 2016 13:07:43 +0200 Subject: [PATCH 06/10] Stabilize type-macros Closes #27245 --- src/libsyntax/ext/expand.rs | 13 +---------- src/libsyntax/feature_gate.rs | 5 ++--- src/test/compile-fail/issue-30007.rs | 2 -- src/test/compile-fail/issue-32950.rs | 2 +- src/test/compile-fail/macro-context.rs | 2 -- src/test/compile-fail/macro-error.rs | 2 -- .../restricted/tuple-struct-fields/test.rs | 2 +- .../restricted/tuple-struct-fields/test2.rs | 2 +- .../restricted/tuple-struct-fields/test3.rs | 2 +- .../compile-fail/syntax-extension-minor.rs | 2 +- src/test/compile-fail/type-macros-fail.rs | 22 ------------------- .../run-pass/simd-intrinsic-generic-cast.rs | 3 +-- src/test/run-pass/type-macros-hlist.rs | 2 -- src/test/run-pass/type-macros-simple.rs | 2 -- 14 files changed, 9 insertions(+), 54 deletions(-) delete mode 100644 src/test/compile-fail/type-macros-fail.rs 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/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/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/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/type-macros-fail.rs b/src/test/compile-fail/type-macros-fail.rs deleted file mode 100644 index 4712e2b65e16a..0000000000000 --- a/src/test/compile-fail/type-macros-fail.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -macro_rules! Id { - ($T:tt) => ($T); -} - -struct Foo { - x: Id!(T) - //~^ ERROR: type macros are experimental (see issue #27245) -} - -fn main() { - let foo = Foo { x: i32 }; -} 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) } } From 5222fa58a1bc766e5d9dc352e36d5725fa28cd7d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 18 Aug 2016 08:32:50 +0300 Subject: [PATCH 07/10] rustc: use accessors for Substs::{types,regions}. --- src/librustc/middle/dead.rs | 2 +- src/librustc/traits/error_reporting.rs | 7 ++- src/librustc/traits/fulfill.rs | 3 +- src/librustc/traits/object_safety.rs | 2 +- src/librustc/traits/select.rs | 35 ++++++------- src/librustc/ty/context.rs | 2 +- src/librustc/ty/flags.rs | 7 ++- src/librustc/ty/item_path.rs | 2 +- src/librustc/ty/mod.rs | 16 +++--- src/librustc/ty/relate.rs | 6 +-- src/librustc/ty/structural_impls.rs | 17 ------- src/librustc/ty/sty.rs | 19 +++---- src/librustc/ty/subst.rs | 52 +++++++++++++++++--- src/librustc/ty/util.rs | 5 +- src/librustc/ty/walk.rs | 19 ++++--- src/librustc/ty/wf.rs | 3 +- src/librustc/util/ppaux.rs | 36 +++++++------- src/librustc_metadata/tyencode.rs | 4 +- src/librustc_mir/transform/qualify_consts.rs | 2 +- src/librustc_trans/back/symbol_names.rs | 31 ++++++------ src/librustc_trans/callee.rs | 6 +-- src/librustc_trans/common.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 5 +- src/librustc_trans/debuginfo/mod.rs | 18 +++---- src/librustc_trans/debuginfo/type_names.rs | 4 +- src/librustc_trans/intrinsic.rs | 46 ++++++++--------- src/librustc_trans/meth.rs | 2 +- src/librustc_trans/monomorphize.rs | 2 +- src/librustc_trans/partitioning.rs | 4 +- src/librustc_trans/trans_item.rs | 33 +++++++------ src/librustc_trans/type_of.rs | 9 ++-- src/librustc_typeck/astconv.rs | 4 +- src/librustc_typeck/check/closure.rs | 2 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 12 +++-- src/librustc_typeck/check/method/probe.rs | 22 +++++---- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/regionck.rs | 13 ++--- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 2 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/lib.rs | 2 +- src/librustdoc/clean/mod.rs | 13 +++-- 43 files changed, 250 insertions(+), 229 deletions(-) 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/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..76477d3df9360 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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; } @@ -440,7 +440,6 @@ 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)) .filter(|t| t.has_infer_types()) .flat_map(|t| t.walk()) 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..f2ea14f17961f 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -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() } } @@ -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().cloned().collect() } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -2180,12 +2177,12 @@ 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.cloned() + .chain(assoc_types) + .collect(); // reintroduce the two binding levels we skipped, then flatten into one let all_types = ty::Binder(ty::Binder(all_types)); @@ -2476,7 +2473,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 +2582,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 +2598,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 types = substs_a.types().enumerate().map(|(i, ty)| { if ty_params.contains(i) { tcx.types.err } else { ty } }).collect(); - let substs = Substs::new(tcx, types, substs_a.regions.clone()); + let substs = Substs::new(tcx, types, substs_a.regions().cloned().collect()); for &ty in fields.split_last().unwrap().1 { if ty.subst(tcx, substs).references_error() { return Err(Unimplemented); @@ -2621,14 +2618,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 types = substs_a.types().enumerate().map(|(i, ty)| { if ty_params.contains(i) { - substs_b.types[i] + substs_b.type_at(i) } else { ty } }).collect(); - let substs = Substs::new(tcx, types, substs_a.regions.clone()); + let substs = Substs::new(tcx, types, substs_a.regions().cloned().collect()); let new_struct = tcx.mk_struct(def, substs); let origin = TypeOrigin::Misc(obligation.cause.span); let InferOk { obligations, .. } = @@ -2753,7 +2750,7 @@ 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)| { let simplified_obligation_ty = diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3501dd4846087..2cae19d95ccbb 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1152,7 +1152,7 @@ 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.types().any(keep_local) || substs.regions().any(keep_local) }) -> Substs<'tcx>, bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| { keep_local(&fty.sig) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index c6c37296e9e12..c7300946eade8 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -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/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/mod.rs b/src/librustc/ty/mod.rs index 6c82157c8ca7c..571ad3ca8b9aa 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -951,7 +951,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 +963,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(&self) -> slice::Iter> { + self.trait_ref.input_types() } pub fn self_ty(&self) -> Ty<'tcx> { @@ -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().cloned().collect() } ty::Predicate::Rfc1592(ref data) => { return data.walk_tys() @@ -1123,8 +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() + trait_inputs.cloned() .chain(Some(data.0.ty)) .collect() } @@ -1206,15 +1204,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(&self) -> slice::Iter> { // 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() } } diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8975a799be143..481e8c97974ac 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -147,14 +147,12 @@ 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 types = a_subst.types().zip(b_subst.types()).enumerate().map(|(i, (a_ty, b_ty))| { 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 regions = a_subst.regions().zip(b_subst.regions()).enumerate().map(|(i, (a_r, b_r))| { let variance = variances.map_or(ty::Invariant, |v| v.regions[i]); relation.relate_with_variance(variance, a_r, b_r) }).collect::>()?; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index f7c4b9938c279..9ccf817a53624 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}; @@ -692,22 +691,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Region { } } -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 { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 8aa81cc4743c9..3f8d55b4634e0 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -19,8 +19,9 @@ use util::common::ErrorReported; use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; -use std::ops; use std::mem; +use std::ops; +use std::slice; use syntax::abi; use syntax::ast::{self, Name}; use syntax::parse::token::keywords; @@ -335,7 +336,7 @@ impl<'tcx> PolyTraitRef<'tcx> { self.0.substs } - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types(&self) -> slice::Iter> { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -360,12 +361,12 @@ pub struct ExistentialTraitRef<'tcx> { } impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types(&self) -> slice::Iter>{ // 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 +377,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { self.0.def_id } - pub fn input_types(&self) -> &[Ty<'tcx>] { + pub fn input_types(&self) -> slice::Iter> { // FIXME(#20664) every use of this fn is probably a bug, it should yield Binder<> self.0.input_types() } @@ -1213,19 +1214,19 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } 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().cloned().collect() } TyClosure(_, ref substs) => { - substs.func_substs.regions.to_vec() + substs.func_substs.regions().cloned().collect() } TyProjection(ref data) => { - data.trait_ref.substs.regions.to_vec() + data.trait_ref.substs.regions().cloned().collect() } TyFnDef(..) | TyFnPtr(_) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e1a19a7b7992e..96f4bda361b63 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -13,18 +13,20 @@ 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 std::slice; + /////////////////////////////////////////////////////////////////////////// /// 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, + types: Vec>, + regions: Vec, } impl<'a, 'gcx, 'tcx> Substs<'tcx> { @@ -104,12 +106,34 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { self.regions.is_empty() && self.types.is_empty() } + #[inline] + pub fn types(&self) -> slice::Iter> { + self.types.iter() + } + + #[inline] + pub fn regions(&self) -> slice::Iter { + self.regions.iter() + } + + #[inline] + pub fn type_at(&self, i: usize) -> Ty<'tcx> { + self.types[i] + } + + #[inline] + pub fn region_at(&self, i: usize) -> ty::Region { + self.regions[i] + } + + #[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) } + #[inline] pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region { - self.regions[def.index as usize] + self.region_at(def.index as usize) } /// Transform from substitutions for a child of `source_ancestor` @@ -130,6 +154,22 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } } +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> Encodable for &'tcx Substs<'tcx> { fn encode(&self, s: &mut S) -> Result<(), S::Error> { cstore::tls::with_encoding_context(s, |ecx, rbml_w| { diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 51710c13a7dea..641dfa67c5b9e 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -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..5a94ba3cf6cd2 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -79,7 +79,7 @@ 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); + push_reversed(stack, data.trait_ref.substs.types()); } ty::TyTrait(ref obj) => { push_reversed(stack, obj.principal.input_types()); @@ -90,17 +90,17 @@ fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { ty::TyEnum(_, ref substs) | ty::TyStruct(_, ref substs) | ty::TyAnon(_, ref substs) => { - push_reversed(stack, &substs.types); + push_reversed(stack, substs.types()); } ty::TyClosure(_, ref substs) => { - push_reversed(stack, &substs.func_substs.types); - push_reversed(stack, &substs.upvar_tys); + push_reversed(stack, substs.func_substs.types()); + push_reversed(stack, substs.upvar_tys); } - ty::TyTuple(ref ts) => { + ty::TyTuple(ts) => { push_reversed(stack, ts); } ty::TyFnDef(_, substs, ref ft) => { - push_reversed(stack, &substs.types); + push_reversed(stack, substs.types()); push_sig_subtypes(stack, &ft.sig); } ty::TyFnPtr(ref ft) => { @@ -114,14 +114,17 @@ fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) push_reversed(stack, &sig.0.inputs); } -fn push_reversed<'tcx>(stack: &mut Vec>, tys: &[Ty<'tcx>]) { +fn push_reversed<'a, 'tcx: 'a, I>(stack: &mut Vec>, tys: I) + where I: IntoIterator>, + I::IntoIter: DoubleEndedIterator +{ // 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() { + for &ty in tys.into_iter().rev() { stack.push(ty); } } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index 54b19362b1d86..e1a39e6957a49 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -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)))); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 02ad8fb7033ed..c75fbf9579f5c 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, regions| { // Don't print any regions if they're all erased. - if regions.iter().all(|r| *r == ty::ReErased) { + if Iterator::all(&mut Clone::clone(®ions), + |r: &ty::Region| *r == ty::ReErased) { return Ok(()); } 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, "<", substs.regions().take(num_regions).skip(0))?; - 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, "::<", substs.regions().take(usize::MAX).skip(num_regions))?; // 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)?; } @@ -368,13 +375,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) diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index 90fd8a0eb2f65..10f503f4e3699 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -251,11 +251,11 @@ 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 { + for &r in substs.regions() { enc_region(w, cx, r); } write!(w, "|"); - for &ty in &substs.types { + for &ty in substs.types() { enc_ty(w, cx, ty); } write!(w, "]"); 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_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/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/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/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index fccb326b23221..49aa19557309f 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 58425cf60d550..72a91f50be35e 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -344,36 +344,34 @@ 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)| { + 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(); diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs index 2a996ca75a37e..9337f7e58ffcc 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/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..103afd827de93 100644 --- a/src/librustc_trans/meth.rs +++ b/src/librustc_trans/meth.rs @@ -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..93302ab3b3be1 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..72f81c7d48da8 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -937,8 +937,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) 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/dropck.rs b/src/librustc_typeck/check/dropck.rs index 82545d564a20c..4e48838f85cfb 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -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/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 9e0b38fd9fe51..8b757309f4887 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -328,18 +328,20 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { // // FIXME -- permit users to manually specify lifetimes 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.regions().count() { + 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.types().count() { + 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 - substs.types().count()] } }) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c306463ec1de0..d8ff9b4057f34 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.regions().count() { + substs.region_at(i) } else { // In general, during probe we erase regions. See // `impl_self_ty()` for an explanation. 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.types().count() { + substs.type_at(i) } else { self.type_var_for_def(self.span, def, cur_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/mod.rs b/src/librustc_typeck/check/mod.rs index 16300d869abf5..f2ed3e37c1a28 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1899,7 +1899,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// 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); } } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 859d5ff0543d0..a596b3cdcbb81 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1445,11 +1445,11 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> { let origin = infer::ParameterInScope(origin, expr_span); - for ®ion in &substs.regions { + for ®ion 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); } @@ -1575,11 +1575,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 +1597,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; diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index bcad7dd3bd0fa..ecec4913fb7dc 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -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().cloned().collect() } None => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index cfc1292c34b78..3e5623404ed35 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -103,7 +103,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { } let free_substs = fcx.parameter_environment.free_substs; - for (i, r) in free_substs.regions.iter().enumerate() { + for (i, r) in free_substs.regions().enumerate() { match *r { ty::ReFree(ty::FreeRegion { bound_region: ty::BoundRegion::BrNamed(def_id, name, _), .. diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index d00cbf0221e0e..4362e040d2661 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); 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/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e2e655ce38bcc..51a697dad2fd6 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).cloned().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))); From dffd238f8b3195982427ba14bc01d47c6da6aedf Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Thu, 25 Aug 2016 23:58:52 +0300 Subject: [PATCH 08/10] rustc: pass ty::Region behind an interned 'tcx reference. --- src/librustc/infer/bivariate.rs | 3 +- src/librustc/infer/combine.rs | 4 +- src/librustc/infer/equate.rs | 3 +- src/librustc/infer/error_reporting.rs | 22 +- src/librustc/infer/freshen.rs | 6 +- src/librustc/infer/glb.rs | 3 +- src/librustc/infer/higher_ranked/mod.rs | 66 ++-- src/librustc/infer/lub.rs | 3 +- src/librustc/infer/mod.rs | 25 +- .../infer/region_inference/graphviz.rs | 24 +- src/librustc/infer/region_inference/mod.rs | 346 ++++++++++-------- src/librustc/infer/resolve.rs | 16 +- src/librustc/infer/sub.rs | 3 +- src/librustc/middle/cstore.rs | 2 - src/librustc/middle/expr_use_visitor.rs | 30 +- src/librustc/middle/free_region.rs | 24 +- src/librustc/middle/mem_categorization.rs | 32 +- src/librustc/mir/repr.rs | 2 +- src/librustc/mir/tcx.rs | 3 +- src/librustc/mir/visit.rs | 4 +- src/librustc/traits/fulfill.rs | 9 +- src/librustc/traits/select.rs | 11 +- src/librustc/ty/_match.rs | 3 +- src/librustc/ty/context.rs | 9 +- src/librustc/ty/error.rs | 12 +- src/librustc/ty/flags.rs | 6 +- src/librustc/ty/fold.rs | 78 ++-- src/librustc/ty/mod.rs | 59 +-- src/librustc/ty/outlives.rs | 4 +- src/librustc/ty/relate.rs | 16 +- src/librustc/ty/structural_impls.rs | 50 +-- src/librustc/ty/sty.rs | 15 +- src/librustc/ty/subst.rs | 16 +- src/librustc/ty/util.rs | 6 +- src/librustc/ty/wf.rs | 12 +- src/librustc/util/ppaux.rs | 18 +- src/librustc_borrowck/borrowck/check_loans.rs | 2 +- .../borrowck/gather_loans/lifetime.rs | 21 +- .../borrowck/gather_loans/mod.rs | 8 +- .../borrowck/gather_loans/restrictions.rs | 6 +- src/librustc_borrowck/borrowck/mod.rs | 29 +- src/librustc_const_eval/check_match.rs | 2 +- src/librustc_driver/test.rs | 27 +- src/librustc_metadata/astencode.rs | 21 +- src/librustc_metadata/csearch.rs | 7 - src/librustc_metadata/decoder.rs | 17 +- src/librustc_metadata/tydecode.rs | 14 +- src/librustc_metadata/tyencode.rs | 6 +- src/librustc_mir/build/matches/mod.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 16 +- src/librustc_mir/hair/cx/pattern.rs | 2 +- src/librustc_mir/hair/mod.rs | 8 +- src/librustc_passes/consts.rs | 2 +- src/librustc_passes/rvalues.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/context.rs | 4 +- src/librustc_trans/meth.rs | 2 +- src/librustc_typeck/astconv.rs | 52 +-- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/coercion.rs | 5 +- src/librustc_typeck/check/dropck.rs | 2 +- src/librustc_typeck/check/intrinsic.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/mod.rs | 10 +- src/librustc_typeck/check/regionck.rs | 96 ++--- src/librustc_typeck/check/upvar.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 2 +- src/librustc_typeck/check/writeback.rs | 17 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 8 +- .../constrained_type_params.rs | 4 +- src/librustc_typeck/rscope.rs | 6 +- src/librustc_typeck/variance/constraints.rs | 4 +- src/librustdoc/clean/mod.rs | 6 +- 75 files changed, 711 insertions(+), 664 deletions(-) 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/middle/cstore.rs b/src/librustc/middle/cstore.rs index 92e1b0681cc7e..381a86a42d482 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -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; @@ -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/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/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/fulfill.rs b/src/librustc/traits/fulfill.rs index 76477d3df9360..a0e25d54a1321 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>, } @@ -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); @@ -580,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![])) @@ -690,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/select.rs b/src/librustc/traits/select.rs index f2ea14f17961f..8adf6e19f39d7 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -1247,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 { @@ -2264,7 +2264,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>> { @@ -2662,7 +2662,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), @@ -2679,7 +2680,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(); @@ -2872,7 +2873,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/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 2cae19d95ccbb..e4e69c395a6fb 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. @@ -1157,7 +1157,12 @@ impl_interners!('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 c7300946eade8..20235cf6d79d6 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); 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/mod.rs b/src/librustc/ty/mod.rs index 571ad3ca8b9aa..3079deff1b641 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, @@ -658,28 +658,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 +700,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 +709,7 @@ pub enum ObjectLifetimeDefault { BaseDefault, /// Use the given region as the default. - Specific(Region), + Specific(&'tcx Region), } #[derive(Clone)] @@ -719,18 +719,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,7 +750,7 @@ 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, } @@ -812,7 +812,7 @@ pub enum Predicate<'tcx> { Equate(PolyEquatePredicate<'tcx>), /// where 'a : 'b - RegionOutlives(PolyRegionOutlivesPredicate), + RegionOutlives(PolyRegionOutlivesPredicate<'tcx>), /// where T : 'a TypeOutlives(PolyTypeOutlivesPredicate<'tcx>), @@ -991,8 +991,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: @@ -1081,7 +1082,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()) } @@ -1237,7 +1238,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 @@ -2825,7 +2826,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 } } @@ -2841,8 +2842,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) @@ -2892,7 +2895,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, }; @@ -2901,6 +2904,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)) } @@ -2910,7 +2917,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()) } @@ -2936,10 +2943,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 481e8c97974ac..8aa390cdd64e2 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -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> @@ -471,9 +471,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)) => @@ -569,11 +569,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 9ccf817a53624..705cca056f24c 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -72,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 { @@ -315,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), @@ -654,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 } @@ -672,25 +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 ty::ClosureSubsts<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { ty::ClosureSubsts { @@ -766,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 => @@ -788,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 3f8d55b4634e0..5e0f3bc5e26f7 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -294,7 +294,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>, } @@ -676,6 +676,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, @@ -1207,10 +1216,10 @@ 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]; diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index 96f4bda361b63..b20c17c8a6677 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -62,7 +62,7 @@ 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(); @@ -82,7 +82,7 @@ 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); @@ -122,7 +122,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn region_at(&self, i: usize) -> ty::Region { + pub fn region_at(&self, i: usize) -> &'tcx ty::Region { self.regions[i] } @@ -132,7 +132,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region { + pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> &'tcx ty::Region { self.region_at(def.index as usize) } @@ -255,13 +255,13 @@ 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) => { @@ -394,8 +394,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)) } } diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 641dfa67c5b9e..96f432587b10e 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); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index e1a39e6957a49..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> { @@ -363,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))))); } } @@ -534,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 c75fbf9579f5c..4b6234e8815ef 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -247,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 @@ -261,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, "", "> ")?; @@ -351,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, @@ -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"), @@ -793,13 +794,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 +975,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 +999,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/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 225895adefa4b..5826064c267a0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -365,7 +365,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 +410,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 +564,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 +578,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 +606,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 +615,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 +966,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 +1195,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..a99262d30eee3 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -283,25 +283,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 +310,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 +318,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> { 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..d5c3a4a6bb0dc 100644 --- a/src/librustc_metadata/csearch.rs +++ b/src/librustc_metadata/csearch.rs @@ -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..ccd8bb70f652d 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, diff --git a/src/librustc_metadata/tydecode.rs b/src/librustc_metadata/tydecode.rs index c76cf23639237..3b022448efa5d 100644 --- a/src/librustc_metadata/tydecode.rs +++ b/src/librustc_metadata/tydecode.rs @@ -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 10f503f4e3699..f502ec4554328 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) => { @@ -286,8 +286,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/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/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_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/collector.rs b/src/librustc_trans/collector.rs index 76910304eebb0..b0afc147e6f9d 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -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/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/meth.rs b/src/librustc_trans/meth.rs index 103afd827de93..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 diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 72f81c7d48da8..79c4a9af8295c 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,7 @@ 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] + tcx.mk_region(regions[def.index as usize]) }, |def, substs| { let i = def.index as usize; @@ -588,7 +589,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)) } @@ -1100,7 +1101,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 +1109,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { from context; please supply an explicit bound"); ty::ReStatic } - } + }) } }; @@ -1643,7 +1644,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 +1802,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 +1827,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 +1864,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 +1891,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 +1903,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 +1957,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 +2070,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 +2093,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 +2109,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 +2242,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 +2264,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/coercion.rs b/src/librustc_typeck/check/coercion.rs index 4a0d529812891..7126478f2c426 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)?; diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 4e48838f85cfb..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(()); } 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 8b757309f4887..9197bdaa030cd 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)) })) diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index d8ff9b4057f34..e38d6aa7a00d7 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1242,7 +1242,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } 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| { let i = def.index as usize; @@ -1264,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) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f2ed3e37c1a28..cc7eadefeb099 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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,7 +1893,7 @@ 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. @@ -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); } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index a596b3cdcbb81..5f5cda358ff2f 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={:?}, \ @@ -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; } @@ -1597,7 +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().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; @@ -1614,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) @@ -1629,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={:?})", @@ -1647,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. @@ -1662,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); @@ -1676,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() { @@ -1698,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; @@ -1732,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 ecec4913fb7dc..b3f26c6c8386c 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 }) diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 3e5623404ed35..6a738032adf0a 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,17 @@ 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().enumerate() { 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 +312,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 +332,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 +627,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 4362e040d2661..c522d9fce0e99 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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)) } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7e1fb32881d6f..2b2b1d3154f5a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1919,7 +1919,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 +1937,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 +1954,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 +2126,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/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..5fd03cbd054b0 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/src/librustc_typeck/variance/constraints.rs @@ -483,9 +483,9 @@ 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()); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 51a697dad2fd6..e0a6f40c86033 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -821,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()) } @@ -913,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 { @@ -923,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; From 7a8d4822d8eb922f0cd50e92f420b5f1938db64d Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Sat, 27 Aug 2016 01:13:48 +0300 Subject: [PATCH 09/10] rustc: use Vec in Substs, where Kind is a &TyS | &Region tagged pointer. --- src/librustc/lib.rs | 1 + src/librustc/middle/cstore.rs | 4 +- src/librustc/middle/resolve_lifetime.rs | 54 ++-- src/librustc/traits/fulfill.rs | 4 +- src/librustc/traits/select.rs | 34 ++- src/librustc/traits/util.rs | 8 +- src/librustc/ty/context.rs | 2 +- src/librustc/ty/flags.rs | 4 +- src/librustc/ty/maps.rs | 2 +- src/librustc/ty/mod.rs | 43 ++- src/librustc/ty/relate.rs | 25 +- src/librustc/ty/sty.rs | 13 +- src/librustc/ty/subst.rs | 246 +++++++++++++----- src/librustc/ty/util.rs | 2 +- src/librustc/ty/walk.rs | 41 ++- src/librustc/util/ppaux.rs | 21 +- .../borrowck/mir/elaborate_drops.rs | 5 +- src/librustc_driver/test.rs | 9 +- src/librustc_metadata/csearch.rs | 2 +- src/librustc_metadata/decoder.rs | 2 +- src/librustc_metadata/tydecode.rs | 18 +- src/librustc_metadata/tyencode.rs | 16 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/build/scope.rs | 6 +- src/librustc_mir/hair/cx/mod.rs | 4 +- src/librustc_trans/base.rs | 2 +- src/librustc_trans/collector.rs | 2 +- src/librustc_trans/debuginfo/metadata.rs | 2 +- src/librustc_trans/debuginfo/mod.rs | 4 +- src/librustc_trans/debuginfo/type_names.rs | 2 +- src/librustc_trans/glue.rs | 2 +- src/librustc_trans/trans_item.rs | 2 +- src/librustc_typeck/astconv.rs | 5 +- src/librustc_typeck/check/autoderef.rs | 2 +- src/librustc_typeck/check/coercion.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 7 +- src/librustc_typeck/check/method/probe.rs | 4 +- src/librustc_typeck/check/method/suggest.rs | 2 +- src/librustc_typeck/check/mod.rs | 63 ++--- src/librustc_typeck/check/regionck.rs | 8 +- src/librustc_typeck/check/wfcheck.rs | 34 +-- src/librustc_typeck/check/writeback.rs | 7 +- src/librustc_typeck/coherence/mod.rs | 2 +- src/librustc_typeck/collect.rs | 56 ++-- src/librustc_typeck/variance/constraints.rs | 25 +- src/librustc_typeck/variance/solve.rs | 19 +- src/librustc_typeck/variance/terms.rs | 31 +-- src/librustdoc/clean/mod.rs | 4 +- .../compile-fail/variance-associated-types.rs | 4 +- .../compile-fail/variance-object-types.rs | 2 +- .../compile-fail/variance-region-bounds.rs | 4 +- .../compile-fail/variance-regions-direct.rs | 14 +- .../compile-fail/variance-regions-indirect.rs | 10 +- .../compile-fail/variance-trait-bounds.rs | 18 +- .../variance-trait-object-bound.rs | 2 +- .../compile-fail/variance-types-bounds.rs | 20 +- src/test/compile-fail/variance-types.rs | 12 +- 57 files changed, 532 insertions(+), 409 deletions(-) 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 381a86a42d482..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>; @@ -328,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") } 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/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index a0e25d54a1321..6598aacc1d3d2 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -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(), @@ -440,7 +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() - .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 }) diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 8adf6e19f39d7..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; @@ -1933,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().cloned().collect() + substs.types().collect() } ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { @@ -1982,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,8 +2180,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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.cloned() - .chain(assoc_types) + let all_types: Vec<_> = input_types.chain(assoc_types) .collect(); // reintroduce the two binding levels we skipped, then flatten into one @@ -2598,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().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().cloned().collect()); + }); + let substs = Substs::new(tcx, params); for &ty in fields.split_last().unwrap().1 { if ty.subst(tcx, substs).references_error() { return Err(Unimplemented); @@ -2618,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().enumerate().map(|(i, ty)| { + let params = substs_a.params().iter().enumerate().map(|(i, &k)| { if ty_params.contains(i) { - substs_b.type_at(i) + Kind::from(substs_b.type_at(i)) } else { - ty + k } - }).collect(); - let substs = Substs::new(tcx, types, substs_a.regions().cloned().collect()); - 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) @@ -2639,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!() @@ -2753,7 +2751,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { 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 = 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/context.rs b/src/librustc/ty/context.rs index e4e69c395a6fb..e048e618e84d6 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1152,7 +1152,7 @@ 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| { - substs.types().any(keep_local) || substs.regions().any(keep_local) + substs.params().iter().any(keep_local) }) -> Substs<'tcx>, bare_fn: mk_bare_fn(BareFnTy<'tcx>, |fty: &BareFnTy| { keep_local(&fty.sig) diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 20235cf6d79d6..1afd49ab47fbf 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -208,11 +208,11 @@ impl FlagComputation { } fn add_substs(&mut self, substs: &Substs) { - for &ty in substs.types() { + for ty in substs.types() { self.add_ty(ty); } - for &r in substs.regions() { + for r in substs.regions() { self.add_region(r); } } 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 3079deff1b641..759dc30037210 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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 @@ -755,6 +740,20 @@ pub struct Generics<'tcx> { pub has_self: bool, } +impl<'tcx> Generics<'tcx> { + pub fn parent_count(&self) -> usize { + self.parent_regions as usize + self.parent_types as usize + } + + pub fn own_count(&self) -> usize { + self.regions.len() + self.types.len() + } + + pub fn count(&self) -> usize { + self.parent_count() + self.own_count() + } +} + /// Bounds on generics. #[derive(Clone)] pub struct GenericPredicates<'tcx> { @@ -963,7 +962,7 @@ impl<'tcx> TraitPredicate<'tcx> { DepNode::TraitSelect(self.def_id(), def_ids) } - pub fn input_types(&self) -> slice::Iter> { + pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator> + 'a { self.trait_ref.input_types() } @@ -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.skip_binder().input_types().cloned().collect() + data.skip_binder().input_types().collect() } ty::Predicate::Rfc1592(ref data) => { return data.walk_tys() @@ -1123,9 +1122,7 @@ impl<'tcx> Predicate<'tcx> { } ty::Predicate::Projection(ref data) => { let trait_inputs = data.0.projection_ty.trait_ref.input_types(); - trait_inputs.cloned() - .chain(Some(data.0.ty)) - .collect() + trait_inputs.chain(Some(data.0.ty)).collect() } ty::Predicate::WellFormed(data) => { vec![data] @@ -1208,7 +1205,7 @@ impl<'tcx> TraitRef<'tcx> { self.substs.type_at(0) } - pub fn input_types(&self) -> slice::Iter> { + 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 @@ -1865,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) { @@ -2592,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))) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8aa390cdd64e2..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; @@ -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,17 +147,18 @@ pub fn relate_substs<'a, 'gcx, 'tcx, R>(relation: &mut R, { let tcx = relation.tcx(); - let types = a_subst.types().zip(b_subst.types()).enumerate().map(|(i, (a_ty, b_ty))| { - 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().zip(b_subst.regions()).enumerate().map(|(i, (a_r, b_r))| { - 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> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 5e0f3bc5e26f7..0e3f18c4474ea 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -21,7 +21,6 @@ use collections::enum_set::{self, EnumSet, CLike}; use std::fmt; use std::mem; use std::ops; -use std::slice; use syntax::abi; use syntax::ast::{self, Name}; use syntax::parse::token::keywords; @@ -336,7 +335,7 @@ impl<'tcx> PolyTraitRef<'tcx> { self.0.substs } - pub fn input_types(&self) -> slice::Iter> { + 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() } @@ -361,7 +360,7 @@ pub struct ExistentialTraitRef<'tcx> { } impl<'tcx> ExistentialTraitRef<'tcx> { - pub fn input_types(&self) -> slice::Iter>{ + 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 @@ -377,7 +376,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { self.0.def_id } - pub fn input_types(&self) -> slice::Iter> { + 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() } @@ -1229,13 +1228,13 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyEnum(_, substs) | TyStruct(_, substs) | TyAnon(_, substs) => { - substs.regions().cloned().collect() + substs.regions().collect() } TyClosure(_, ref substs) => { - substs.func_substs.regions().cloned().collect() + substs.func_substs.regions().collect() } TyProjection(ref data) => { - data.trait_ref.substs.regions().cloned().collect() + data.trait_ref.substs.regions().collect() } TyFnDef(..) | TyFnPtr(_) | diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index b20c17c8a6677..0ccfea2330999 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -18,38 +18,151 @@ use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; -use std::slice; +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, Debug, Hash)] pub struct Substs<'tcx> { - types: Vec>, - 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, @@ -65,16 +178,13 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { 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, @@ -89,41 +199,59 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { 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 types(&self) -> slice::Iter> { - self.types.iter() + pub fn params(&self) -> &[Kind<'tcx>] { + &self.params } #[inline] - pub fn regions(&self) -> slice::Iter { - self.regions.iter() + 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.types[i] + 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.regions[i] + self.params[i].as_region().unwrap_or_else(|| { + bug!("expected region for param #{} in {:?}", i, self.params); + }) } #[inline] @@ -146,19 +274,19 @@ 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 types = self.types.fold_with(folder); - let regions = self.regions.fold_with(folder); - Substs::new(folder.tcx(), types, regions) + 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 { @@ -166,7 +294,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.types.visit_with(visitor) || self.regions.visit_with(visitor) + self.params.visit_with(visitor) } } @@ -263,8 +391,10 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> { // the specialized routine `ty::replace_late_regions()`. 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 => { @@ -318,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!( @@ -331,7 +462,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { source_ty, p.idx, self.root_ty, - self.substs); + self.substs.params); } }; @@ -407,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) } } } @@ -421,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) } } } @@ -444,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 96f432587b10e..dd5c6a9758abf 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -693,7 +693,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { return false; } - substs_a.types().zip(substs_b.types()).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 5a94ba3cf6cd2..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(ts) => { - push_reversed(stack, 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,20 +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<'a, 'tcx: 'a, I>(stack: &mut Vec>, tys: I) - where I: IntoIterator>, - I::IntoIter: DoubleEndedIterator -{ - // 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.into_iter().rev() { - stack.push(ty); - } + stack.extend(sig.0.inputs.iter().cloned().rev()); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 4b6234e8815ef..24b68c66e4667 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -143,14 +143,14 @@ pub fn parameterized(f: &mut fmt::Formatter, } }; - let print_regions = |f: &mut fmt::Formatter, start: &str, regions| { + let print_regions = |f: &mut fmt::Formatter, start: &str, skip, count| { // Don't print any regions if they're all erased. - if Iterator::all(&mut Clone::clone(®ions), - |r: &ty::Region| *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 { @@ -173,12 +173,12 @@ pub fn parameterized(f: &mut fmt::Formatter, Ok(()) }; - print_regions(f, "<", substs.regions().take(num_regions).skip(0))?; + print_regions(f, "<", 0, num_regions)?; let tps = substs.types().take(num_types - num_supplied_defaults) .skip(has_self as usize); - for &ty in tps { + for ty in tps { start_or_continue(f, "<", ", ")?; write!(f, "{}", ty)?; } @@ -204,7 +204,7 @@ pub fn parameterized(f: &mut fmt::Formatter, write!(f, "::{}", item_name)?; } - print_regions(f, "::<", substs.regions().take(usize::MAX).skip(num_regions))?; + print_regions(f, "::<", num_regions, usize::MAX)?; // FIXME: consider being smart with defaults here too for ty in substs.types().skip(num_types) { @@ -655,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) 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_driver/test.rs b/src/librustc_driver/test.rs index a99262d30eee3..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; @@ -676,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) @@ -711,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)) @@ -773,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/csearch.rs b/src/librustc_metadata/csearch.rs index d5c3a4a6bb0dc..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) diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index ccd8bb70f652d..bbda089b1c2a8 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -991,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 3b022448efa5d..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> { diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs index f502ec4554328..7255eae61d453 100644 --- a/src/librustc_metadata/tyencode.rs +++ b/src/librustc_metadata/tyencode.rs @@ -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, "]"); } 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/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_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/collector.rs b/src/librustc_trans/collector.rs index b0afc147e6f9d..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, diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs index 49aa19557309f..67d4a0e044c9c 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_trans/debuginfo/metadata.rs @@ -345,7 +345,7 @@ impl<'tcx> TypeMap<'tcx> { if substs.types().next().is_some() { output.push('<'); - for &type_parameter in substs.types() { + 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 72a91f50be35e..4d8a9a2ac40d7 100644 --- a/src/librustc_trans/debuginfo/mod.rs +++ b/src/librustc_trans/debuginfo/mod.rs @@ -354,7 +354,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } name_to_append_suffix_to.push('<'); - for (i, &actual_type) in substs.types().enumerate() { + for (i, actual_type) in substs.types().enumerate() { if i != 0 { name_to_append_suffix_to.push_str(","); } @@ -372,7 +372,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { let names = get_type_parameter_names(cx, generics); substs.types().zip(names).map(|(ty, name)| { - let actual_type = cx.tcx().normalize_associated_type(ty); + 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 9337f7e58ffcc..f757578e6954d 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_trans/debuginfo/type_names.rs @@ -181,7 +181,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, 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/trans_item.rs b/src/librustc_trans/trans_item.rs index 93302ab3b3be1..2c91c408487b8 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -541,7 +541,7 @@ fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, output.push('<'); - for &type_parameter in substs.types() { + for type_parameter in substs.types() { push_unique_type_name(tcx, type_parameter, output); output.push_str(", "); } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 79c4a9af8295c..f24a7cf2121eb 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -473,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, _| { - tcx.mk_region(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; @@ -482,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 { 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/coercion.rs b/src/librustc_typeck/check/coercion.rs index 7126478f2c426..26a4705528976 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -458,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/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 9197bdaa030cd..be77ca435a18c 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -327,21 +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, _| { let i = def.index as usize; - if i < substs.regions().count() { + if i < substs.params().len() { substs.region_at(i) } else { self.region_var_for_def(self.span, def) } }, |def, cur_substs| { let i = def.index as usize; - if i < substs.types().count() { + 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[i - substs.types().count()] + 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 e38d6aa7a00d7..a64982cd1bf81 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -1237,7 +1237,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } else { let substs = Substs::for_item(self.tcx, method.def_id, |def, _| { let i = def.index as usize; - if i < substs.regions().count() { + if i < substs.params().len() { substs.region_at(i) } else { // In general, during probe we erase regions. See @@ -1246,7 +1246,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> { } }, |def, cur_substs| { let i = def.index as usize; - if i < substs.types().count() { + if i < substs.params().len() { substs.type_at(i) } else { self.type_var_for_def(self.span, def, cur_substs) 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 cc7eadefeb099..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 { @@ -1899,7 +1899,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// 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); } } @@ -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 5f5cda358ff2f..cef2bb07e35ca 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1447,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); } @@ -1577,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); } diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index b3f26c6c8386c..38ec7ba686f6f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -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().cloned().collect() + trait_ref.substs.types().collect() } None => { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 6a738032adf0a..3bd0e890bb811 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -104,7 +104,12 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { let gcx = fcx.tcx.global_tcx(); let free_substs = fcx.parameter_environment.free_substs; - for (i, r) in free_substs.regions().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, _), .. diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index c522d9fce0e99..7d6cee7b3bac1 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -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 2b2b1d3154f5a..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 { diff --git a/src/librustc_typeck/variance/constraints.rs b/src/librustc_typeck/variance/constraints.rs index 5fd03cbd054b0..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); @@ -488,8 +485,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { 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 e0a6f40c86033..c8620254b6f42 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -643,7 +643,7 @@ 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().filter_map(|v| v.clean(cx)).collect(); - let types = substs.types().skip(has_self as usize).cloned().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 @@ -741,7 +741,7 @@ impl<'tcx> Clean for ty::TraitRef<'tcx> { // collect any late bound regions let mut late_bounds = vec![]; - for &ty_s in self.input_types().skip(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 { 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) From 668d63132e23999f5a74fe65c8c0590a4d9ca215 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 27 Aug 2016 11:33:02 +0530 Subject: [PATCH 10/10] Fixup rustbuild on #35124 --- src/bootstrap/lib.rs | 4 ---- src/bootstrap/step.rs | 7 ++----- 2 files changed, 2 insertions(+), 9 deletions(-) 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), ];