diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index dd3f292fb5684..aac4466b6abab 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -10,45 +10,30 @@ //! //! Note that if we are expecting a reference, we will *reborrow* //! even if the argument provided was already a reference. This is -//! useful for freezing mut/const things (that is, when the expected is &T -//! but you have &const T or &mut T) and also for avoiding the linearity +//! useful for freezing mut things (that is, when the expected type is &T +//! but you have &mut T) and also for avoiding the linearity //! of mut things (when the expected is &mut T and you have &mut T). See -//! the various `src/test/ui/coerce-reborrow-*.rs` tests for +//! the various `src/test/ui/coerce/*.rs` tests for //! examples of where this is useful. //! //! ## Subtle note //! -//! When deciding what type coercions to consider, we do not attempt to -//! resolve any type variables we may encounter. This is because `b` -//! represents the expected type "as the user wrote it", meaning that if -//! the user defined a generic function like +//! When infering the generic arguments of functions, the argument +//! order is relevant, which can lead to the following edge case: //! -//! fn foo(a: A, b: A) { ... } +//! ```rust +//! fn foo(a: T, b: T) { +//! // ... +//! } //! -//! and then we wrote `foo(&1, @2)`, we will not auto-borrow -//! either argument. In older code we went to some lengths to -//! resolve the `b` variable, which could mean that we'd -//! auto-borrow later arguments but not earlier ones, which -//! seems very confusing. +//! foo(&7i32, &mut 7i32); +//! // This compiles, as we first infer `T` to be `&i32`, +//! // and then coerce `&mut 7i32` to `&7i32`. //! -//! ## Subtler note -//! -//! However, right now, if the user manually specifies the -//! values for the type variables, as so: -//! -//! foo::<&int>(@1, @2) -//! -//! then we *will* auto-borrow, because we can't distinguish this from a -//! function that declared `&int`. This is inconsistent but it's easiest -//! at the moment. The right thing to do, I think, is to consider the -//! *unsubstituted* type when deciding whether to auto-borrow, but the -//! *substituted* type when considering the bounds and so forth. But most -//! of our methods don't give access to the unsubstituted type, and -//! rightly so because they'd be error-prone. So maybe the thing to do is -//! to actually determine the kind of coercions that should occur -//! separately and pass them in. Or maybe it's ok as is. Anyway, it's -//! sort of a minor point so I've opted to leave it for later -- after all, -//! we may want to adjust precisely when coercions occur. +//! foo(&mut 7i32, &7i32); +//! // This does not compile, as we first infer `T` to be `&mut i32` +//! // and are then unable to coerce `&7i32` to `&mut i32`. +//! ``` use crate::astconv::AstConv; use crate::check::{FnCtxt, Needs}; @@ -96,6 +81,8 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { type CoerceResult<'tcx> = InferResult<'tcx, (Vec>, Ty<'tcx>)>; +/// Coercing a mutable reference to an immutable works, while +/// coercing `&T` to `&mut T` should be forbidden. fn coerce_mutbls<'tcx>( from_mutbl: hir::Mutability, to_mutbl: hir::Mutability,