|
10 | 10 | //! |
11 | 11 | //! Note that if we are expecting a reference, we will *reborrow* |
12 | 12 | //! even if the argument provided was already a reference. This is |
13 | | -//! useful for freezing mut/const things (that is, when the expected is &T |
14 | | -//! but you have &const T or &mut T) and also for avoiding the linearity |
| 13 | +//! useful for freezing mut things (that is, when the expected type is &T |
| 14 | +//! but you have &mut T) and also for avoiding the linearity |
15 | 15 | //! of mut things (when the expected is &mut T and you have &mut T). See |
16 | | -//! the various `src/test/ui/coerce-reborrow-*.rs` tests for |
| 16 | +//! the various `src/test/ui/coerce/*.rs` tests for |
17 | 17 | //! examples of where this is useful. |
18 | 18 | //! |
19 | 19 | //! ## Subtle note |
20 | 20 | //! |
21 | | -//! When deciding what type coercions to consider, we do not attempt to |
22 | | -//! resolve any type variables we may encounter. This is because `b` |
23 | | -//! represents the expected type "as the user wrote it", meaning that if |
24 | | -//! the user defined a generic function like |
| 21 | +//! When infering the generic arguments of functions, the argument |
| 22 | +//! order is relevant, which can lead to the following edge case: |
25 | 23 | //! |
26 | | -//! fn foo<A>(a: A, b: A) { ... } |
| 24 | +//! ```rust |
| 25 | +//! fn foo<T>(a: T, b: T) { |
| 26 | +//! // ... |
| 27 | +//! } |
27 | 28 | //! |
28 | | -//! and then we wrote `foo(&1, @2)`, we will not auto-borrow |
29 | | -//! either argument. In older code we went to some lengths to |
30 | | -//! resolve the `b` variable, which could mean that we'd |
31 | | -//! auto-borrow later arguments but not earlier ones, which |
32 | | -//! seems very confusing. |
| 29 | +//! foo(&7i32, &mut 7i32); |
| 30 | +//! // This compiles, as we first infer `T` to be `&i32`, |
| 31 | +//! // and then coerce `&mut 7i32` to `&7i32`. |
33 | 32 | //! |
34 | | -//! ## Subtler note |
35 | | -//! |
36 | | -//! However, right now, if the user manually specifies the |
37 | | -//! values for the type variables, as so: |
38 | | -//! |
39 | | -//! foo::<&int>(@1, @2) |
40 | | -//! |
41 | | -//! then we *will* auto-borrow, because we can't distinguish this from a |
42 | | -//! function that declared `&int`. This is inconsistent but it's easiest |
43 | | -//! at the moment. The right thing to do, I think, is to consider the |
44 | | -//! *unsubstituted* type when deciding whether to auto-borrow, but the |
45 | | -//! *substituted* type when considering the bounds and so forth. But most |
46 | | -//! of our methods don't give access to the unsubstituted type, and |
47 | | -//! rightly so because they'd be error-prone. So maybe the thing to do is |
48 | | -//! to actually determine the kind of coercions that should occur |
49 | | -//! separately and pass them in. Or maybe it's ok as is. Anyway, it's |
50 | | -//! sort of a minor point so I've opted to leave it for later -- after all, |
51 | | -//! we may want to adjust precisely when coercions occur. |
| 33 | +//! foo(&mut 7i32, &7i32); |
| 34 | +//! // This does not compile, as we first infer `T` to be `&mut i32` |
| 35 | +//! // and are then unable to coerce `&7i32` to `&mut i32`. |
| 36 | +//! ``` |
52 | 37 |
|
53 | 38 | use crate::astconv::AstConv; |
54 | 39 | use crate::check::{FnCtxt, Needs}; |
@@ -96,6 +81,8 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> { |
96 | 81 |
|
97 | 82 | type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>; |
98 | 83 |
|
| 84 | +/// Coercing a mutable reference to an immutable works, while |
| 85 | +/// coercing `&T` to `&mut T` should be forbidden. |
99 | 86 | fn coerce_mutbls<'tcx>( |
100 | 87 | from_mutbl: hir::Mutability, |
101 | 88 | to_mutbl: hir::Mutability, |
|
0 commit comments