From a2b61e16b13226ba6ae3cecce9752eee6a6999aa Mon Sep 17 00:00:00 2001 From: Lorenz Date: Sat, 30 May 2015 14:25:58 +0200 Subject: [PATCH 01/11] Extend rust reference with a section about subtyping --- src/doc/reference.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index 8d1b93ce3c8b9..68c17c04079bf 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3608,6 +3608,26 @@ The notation `&self` is a shorthand for `self: &Self`. In this case, in the impl, `Self` refers to the value of type `String` that is the receiver for a call to the method `make_string`. +## Subtyping + +Subtyping is implicit and can occur at any stage in type checking or +inference. Subtyping in Rust is very restricted and occurs only due to +variance with respect to lifetimes and between types with higher ranked +lifetimes. If we were to erase lifetimes from types, then the only subtyping +would be due to type equality. + +Consider the following example: string literals always have `'static` +lifetime. Nevertheless, we can assign `s` to `t`: + +``` +fn bar<'a>() { + let s: &'static str = "hi"; + let t: &'a str = s; +} +``` +Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of +`&'a str`. + # Special traits Several traits define special evaluation behavior. From babb2684d80aee86ba73ffb1af04617fb2943a06 Mon Sep 17 00:00:00 2001 From: Lorenz Date: Sat, 30 May 2015 14:26:50 +0200 Subject: [PATCH 02/11] Extend rust reference with a section about type coercions --- src/doc/reference.md | 120 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index 68c17c04079bf..cb595c22a251c 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3628,6 +3628,126 @@ fn bar<'a>() { Since `'static` "lives longer" than `'a`, `&'static str` is a subtype of `&'a str`. +## Type coercions + +Coercions are defined in [RFC401]. A coercion is implicit and has no syntax. + +[RFC401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md + +### Coercion sites + +A coercion can only occur at certain coercion sites in a program; these are +typically places where the desired type is explicit or can be dervied by +propagation from explicit types (without type inference). Possible coercion +sites are: + +* `let` statements where an explicit type is given. + + In `let _: U = e;`, `e` is coerced to have type `U`. + +* `static` and `const` statements (similar to `let` statements). + +* arguments for function calls. + + The value being coerced is the + actual parameter and it is coerced to the type of the formal parameter. For + example, let `foo` be defined as `fn foo(x: U) { ... }` and call it as + `foo(e);`. Then `e` is coerced to have type `U`; + +* instantiations of struct or variant fields. + + Assume we have a `struct + Foo { x: U }` and instantiate it as `Foo { x: e }`. Then `e` is coerced to + have type `U`. + +* function results (either the final line of a block if it is not semicolon +terminated or any expression in a `return` statement). + + In `fn foo() -> U { e }`, `e` is coerced to to have type `U`. + +If the expression in one of these coercion sites is a coercion-propagating +expression, then the relevant sub-expressions in that expression are also +coercion sites. Propagation recurses from these new coercion sites. +Propagating expressions and their relevant sub-expressions are: + +* array literals, where the array has type `[U; n]`. Each sub-expression in +the array literal is a coercion site for coercion to type `U`. + +* array literals with repeating syntax, where the array has type `[U; n]`. The +repeated sub-expression is a coercion site for coercion to type `U`. + +* tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`. +Each sub-expression is a coercion site to the respective type, e.g. the +zeroth sub-expression is a coercion site to type `U_0`. + +* parenthesised sub-expressions (`(e)`). If the expression has type `U`, then +the sub-expression is a coercion site to `U`. + +* blocks. If a block has type `U`, then the last expression in the block (if +it is not semicolon-terminated) is a coercion site to `U`. This includes +blocks which are part of control flow statements, such as `if`/`else`, if +the block has a known type. + +### Coercion types + +Coercion is allowed between the following types: + +* `T` to `U` if `T` is a subtype of `U` (*reflexive case*). + +* `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` +(*transitive case*). + + Note that this is not fully supported yet + +* `&mut T` to `&T`. + +* `*mut T` to `*const T`. + +* `&T` to `*const T`. + +* `&mut T` to `*mut T`. + +* `&T` to `&U` if `T` implements `Deref`. For example: + ``` + use std::ops::Deref; + + struct CharContainer { + value: char + } + + impl Deref for CharContainer { + type Target = char; + + fn deref<'a>(&'a self) -> &'a char { + &self.value + } + } + + fn foo(arg: &char) {} + + fn main() { + let x = &mut CharContainer { value: 'y' }; + foo(x); //&mut CharContainer is coerced to &char. + } + ``` +* `&mut T` to `&mut U` if `T` implements `DerefMut`. + +* TyCtor(`T`) to TyCtor(coerce_inner(`T`)), where TyCtor(`T`) is one of + - `&T` + - `&mut T` + - `*const T` + - `*mut T` + - `Box` + + and where + - coerce_inner(`[T, ..n]`) = `[T]` + - coerce_inner(`T`) = `U` where `T` is a concrete type which implements the + trait `U`. + + In the future, coerce_inner will be recursively extended to tuples and + structs. In addition, coercions from sub-traits to super-traits will be + added. See [RFC401] for more details. + # Special traits Several traits define special evaluation behavior. From 01ddbe9f33f409a5274d36cd7f0609263eab4764 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 3 Jun 2015 14:34:24 +0200 Subject: [PATCH 03/11] Fix the dropck doc formatting to avoid hitting four-space indent. This was causing `rustdoc` to interpret the part starting with `(A.) ...` as a code block based on its four-space indentation, which then was treated by `rustdoc` as a *Rust* code snippet, and thus was attempting (and failing) to parse my english as Rust code. Thus causing the compiler-docs build to fail. Independently, we should probably change `rustdoc` to not interpret four-space indents as code that needs to be tested; it seems too perilous to me at least. (But the formatting here needed to be changed either way.) cc Issue #25699. --- src/librustc_typeck/check/dropck.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index fd90d662bd141..28e48cb6f2544 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -238,14 +238,12 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( /// Let `v` be some value (either temporary or named) and 'a be some /// lifetime (scope). If the type of `v` owns data of type `D`, where /// -/// (1.) `D` has a lifetime- or type-parametric Drop implementation, and -/// (2.) the structure of `D` can reach a reference of type `&'a _`, and -/// (3.) either: -/// -/// (A.) the Drop impl for `D` instantiates `D` at 'a directly, +/// * (1.) `D` has a lifetime- or type-parametric Drop implementation, and +/// * (2.) the structure of `D` can reach a reference of type `&'a _`, and +/// * (3.) either: +/// * (A.) the Drop impl for `D` instantiates `D` at 'a directly, /// i.e. `D<'a>`, or, -/// -/// (B.) the Drop impl for `D` has some type parameter with a +/// * (B.) the Drop impl for `D` has some type parameter with a /// trait bound `T` where `T` is a trait that has at least /// one method, /// From 9634bcbd3d120e7a13b62bb47e882fc9ce6338cd Mon Sep 17 00:00:00 2001 From: Carol Nichols Date: Wed, 3 Jun 2015 10:12:16 -0400 Subject: [PATCH 04/11] Improve `try!` docs to make clearer it returns `Result`. The API documentation is not explicit enough that because `try!` returns `Err` early for you, you can only use it in functions that return `Result`. The book mentions this, but if you come across `try!` outside of the book and look it up in the docs, this restriction on the return type of the function is not particularly clear. --- src/libcore/result.rs | 4 +++- src/libstd/macros.rs | 28 +++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/libcore/result.rs b/src/libcore/result.rs index e909946ece402..003c4b2b78c5c 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -223,7 +223,9 @@ //! } //! ``` //! -//! `try!` is imported by the prelude, and is available everywhere. +//! `try!` is imported by the prelude and is available everywhere, but it can only +//! be used in functions that return `Result` because of the early return of +//! `Err` that it provides. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 32193b4089d30..a7c18783025e0 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -117,7 +117,33 @@ macro_rules! println { } /// Helper macro for unwrapping `Result` values while returning early with an -/// error if the value of the expression is `Err`. +/// error if the value of the expression is `Err`. Can only be used in +/// functions that return `Result` because of the early return of `Err` that +/// it provides. +/// +/// # Examples +/// +/// ``` +/// use std::io; +/// use std::fs::File; +/// +/// fn write_to_file_using_try() -> Result<(), io::Error> { +/// let mut file = try!(File::create("my_best_friends.txt")); +/// try!(file.write_line("This is a list of my best friends.")); +/// println!("I wrote to the file"); +/// Ok() +/// } +/// // This is equivalent to: +/// fn write_to_file_using_match() -> Result<(), io::Error> { +/// let mut file = try!(File::create("my_best_friends.txt")); +/// match file.write_line("This is a list of my best friends.") { +/// Ok(_) => (), +/// Err(e) => return Err(e), +/// } +/// println!("I wrote to the file"); +/// Ok() +/// } +/// ``` #[macro_export] #[stable(feature = "rust1", since = "1.0.0")] macro_rules! try { From d328d6472e6a61820c92ed7a910dbbff734fe235 Mon Sep 17 00:00:00 2001 From: Carol Nichols Date: Wed, 3 Jun 2015 13:15:50 -0400 Subject: [PATCH 05/11] Add prelude to get Write --- src/libstd/macros.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index a7c18783025e0..1a3fda53366f4 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -126,6 +126,7 @@ macro_rules! println { /// ``` /// use std::io; /// use std::fs::File; +/// use std::io::prelude::*; /// /// fn write_to_file_using_try() -> Result<(), io::Error> { /// let mut file = try!(File::create("my_best_friends.txt")); From a41fd590a8142b524d6a6d34e8977906d6787368 Mon Sep 17 00:00:00 2001 From: Carol Nichols Date: Wed, 3 Jun 2015 13:23:20 -0400 Subject: [PATCH 06/11] Use write_all instead of write_line --- src/libstd/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 1a3fda53366f4..cbb2880445942 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -130,14 +130,14 @@ macro_rules! println { /// /// fn write_to_file_using_try() -> Result<(), io::Error> { /// let mut file = try!(File::create("my_best_friends.txt")); -/// try!(file.write_line("This is a list of my best friends.")); +/// try!(file.write_all(b"This is a list of my best friends.")); /// println!("I wrote to the file"); /// Ok() /// } /// // This is equivalent to: /// fn write_to_file_using_match() -> Result<(), io::Error> { /// let mut file = try!(File::create("my_best_friends.txt")); -/// match file.write_line("This is a list of my best friends.") { +/// match file.write_all(b"This is a list of my best friends.") { /// Ok(_) => (), /// Err(e) => return Err(e), /// } From 80322e2e970bc7d2d36c14fb63f753fe39acf63e Mon Sep 17 00:00:00 2001 From: Carol Nichols Date: Wed, 3 Jun 2015 13:23:40 -0400 Subject: [PATCH 07/11] Return Ok(()) instead of Ok() --- src/libstd/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index cbb2880445942..26ace45890c36 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -132,7 +132,7 @@ macro_rules! println { /// let mut file = try!(File::create("my_best_friends.txt")); /// try!(file.write_all(b"This is a list of my best friends.")); /// println!("I wrote to the file"); -/// Ok() +/// Ok(()) /// } /// // This is equivalent to: /// fn write_to_file_using_match() -> Result<(), io::Error> { @@ -142,7 +142,7 @@ macro_rules! println { /// Err(e) => return Err(e), /// } /// println!("I wrote to the file"); -/// Ok() +/// Ok(()) /// } /// ``` #[macro_export] From c692d75b5a595ef5939473aef20e1751d4e0e1f5 Mon Sep 17 00:00:00 2001 From: Carol Nichols Date: Wed, 3 Jun 2015 13:23:55 -0400 Subject: [PATCH 08/11] Indent 4 spaces instead of 2 --- src/libstd/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 26ace45890c36..706571b67c9ac 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -138,8 +138,8 @@ macro_rules! println { /// fn write_to_file_using_match() -> Result<(), io::Error> { /// let mut file = try!(File::create("my_best_friends.txt")); /// match file.write_all(b"This is a list of my best friends.") { -/// Ok(_) => (), -/// Err(e) => return Err(e), +/// Ok(_) => (), +/// Err(e) => return Err(e), /// } /// println!("I wrote to the file"); /// Ok(()) From 24808fa076a2cf86c32e138d95c68e3ee4c7a0fc Mon Sep 17 00:00:00 2001 From: webmobster Date: Wed, 3 Jun 2015 13:47:07 +0100 Subject: [PATCH 09/11] Add priority policy to RWLock API Documentation --- src/libstd/sync/rwlock.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index e7c3d744c179a..857d8889b7c25 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -24,6 +24,10 @@ use sys_common::rwlock as sys; /// of the underlying data (exclusive access) and the read portion of this lock /// typically allows for read-only access (shared access). /// +/// The priority policy of the lock is dependent on the underlying operating +/// system's implementation, and this type does not guarantee that any +/// particular policy will be used. +/// /// The type parameter `T` represents the data that this lock protects. It is /// required that `T` satisfies `Send` to be shared across threads and `Sync` to /// allow concurrent access through readers. The RAII guards returned from the From 0000d4c62a9508c30354e8064c1866312839bb7a Mon Sep 17 00:00:00 2001 From: Marcus Klaas Date: Wed, 3 Jun 2015 23:51:51 +0200 Subject: [PATCH 10/11] Fix span for ExprPath variants --- src/libsyntax/parse/parser.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 539d594cb8be2..420b27b83957b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2070,10 +2070,9 @@ impl<'a> Parser<'a> { } _ => { if try!(self.eat_lt()){ - let (qself, path) = try!(self.parse_qualified_path(LifetimeAndTypesWithColons)); - + hi = path.span.hi; return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path))); } if try!(self.eat_keyword(keywords::Move) ){ From fd3b6ca508ed99004a11291ef1d2c64104102a41 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Thu, 4 Jun 2015 11:26:31 +0530 Subject: [PATCH 11/11] =?UTF-8?q?Fix=20doctest=20(fixup=20=C2=96#25900)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/doc/reference.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/doc/reference.md b/src/doc/reference.md index 045481d7bbd6f..d56ecb360cfed 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3699,28 +3699,29 @@ Coercion is allowed between the following types: * `&mut T` to `*mut T`. * `&T` to `&U` if `T` implements `Deref`. For example: - ``` - use std::ops::Deref; - struct CharContainer { - value: char - } +```rust +use std::ops::Deref; - impl Deref for CharContainer { - type Target = char; +struct CharContainer { + value: char +} - fn deref<'a>(&'a self) -> &'a char { - &self.value - } +impl Deref for CharContainer { + type Target = char; + + fn deref<'a>(&'a self) -> &'a char { + &self.value } +} - fn foo(arg: &char) {} +fn foo(arg: &char) {} - fn main() { - let x = &mut CharContainer { value: 'y' }; - foo(x); //&mut CharContainer is coerced to &char. - } - ``` +fn main() { + let x = &mut CharContainer { value: 'y' }; + foo(x); //&mut CharContainer is coerced to &char. +} +``` * `&mut T` to `&mut U` if `T` implements `DerefMut`. * TyCtor(`T`) to TyCtor(coerce_inner(`T`)), where TyCtor(`T`) is one of