diff --git a/src/doc/reference.md b/src/doc/reference.md index eb3dbfbf13616..d56ecb360cfed 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -3599,6 +3599,147 @@ 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`. + +## 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: + +```rust +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. 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/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, /// diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 32193b4089d30..706571b67c9ac 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -117,7 +117,34 @@ 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; +/// use std::io::prelude::*; +/// +/// fn write_to_file_using_try() -> Result<(), io::Error> { +/// 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(()) +/// } +/// // 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_all(b"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 { 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 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) ){