Skip to content

Commit c0a25be

Browse files
authored
Rollup merge of #72791 - lcnr:coerce-refactor, r=estebank
update coerce docs and unify relevant tests Merges `test/ui/coerce` with `test/ui/coercion`. Updates the documentation of `librustc_typeck/check/coercion.rs`. Adds 2 new coercion tests.
2 parents 218b90f + 06a237f commit c0a25be

22 files changed

+140
-128
lines changed

src/librustc_typeck/check/coercion.rs

+18-31
Original file line numberDiff line numberDiff line change
@@ -10,45 +10,30 @@
1010
//!
1111
//! Note that if we are expecting a reference, we will *reborrow*
1212
//! 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
1515
//! 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
1717
//! examples of where this is useful.
1818
//!
1919
//! ## Subtle note
2020
//!
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:
2523
//!
26-
//! fn foo<A>(a: A, b: A) { ... }
24+
//! ```rust
25+
//! fn foo<T>(a: T, b: T) {
26+
//! // ...
27+
//! }
2728
//!
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`.
3332
//!
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+
//! ```
5237
5338
use crate::astconv::AstConv;
5439
use crate::check::FnCtxt;
@@ -96,6 +81,8 @@ impl<'a, 'tcx> Deref for Coerce<'a, 'tcx> {
9681

9782
type CoerceResult<'tcx> = InferResult<'tcx, (Vec<Adjustment<'tcx>>, Ty<'tcx>)>;
9883

84+
/// Coercing a mutable reference to an immutable works, while
85+
/// coercing `&T` to `&mut T` should be forbidden.
9986
fn coerce_mutbls<'tcx>(
10087
from_mutbl: hir::Mutability,
10188
to_mutbl: hir::Mutability,

src/test/ui/coerce/coerce-overloaded-autoderef.rs

-68
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
fn borrow_mut<T>(x: &mut T) -> &mut T { x }
2+
fn borrow<T>(x: &T) -> &T { x }
3+
4+
fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
5+
fn borrow2<T>(_: &mut T, _: &T) {}
6+
7+
fn double_mut_borrow<T>(x: &mut Box<T>) {
8+
let y = borrow_mut(x);
9+
let z = borrow_mut(x);
10+
//~^ ERROR cannot borrow `*x` as mutable more than once at a time
11+
drop((y, z));
12+
}
13+
14+
fn double_imm_borrow(x: &mut Box<i32>) {
15+
let y = borrow(x);
16+
let z = borrow(x);
17+
**x += 1;
18+
//~^ ERROR cannot assign to `**x` because it is borrowed
19+
drop((y, z));
20+
}
21+
22+
fn double_mut_borrow2<T>(x: &mut Box<T>) {
23+
borrow_mut2(x, x);
24+
//~^ ERROR cannot borrow `*x` as mutable more than once at a time
25+
}
26+
27+
fn double_borrow2<T>(x: &mut Box<T>) {
28+
borrow2(x, x);
29+
//~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable
30+
}
31+
32+
pub fn main() {}

src/test/ui/coercion/coerce-overloaded-autoderef.stderr renamed to src/test/ui/coercion/coerce-overloaded-autoderef-fail.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0499]: cannot borrow `*x` as mutable more than once at a time
2-
--> $DIR/coerce-overloaded-autoderef.rs:9:24
2+
--> $DIR/coerce-overloaded-autoderef-fail.rs:9:24
33
|
44
LL | let y = borrow_mut(x);
55
| - first mutable borrow occurs here
@@ -10,7 +10,7 @@ LL | drop((y, z));
1010
| - first borrow later used here
1111

1212
error[E0506]: cannot assign to `**x` because it is borrowed
13-
--> $DIR/coerce-overloaded-autoderef.rs:17:5
13+
--> $DIR/coerce-overloaded-autoderef-fail.rs:17:5
1414
|
1515
LL | let y = borrow(x);
1616
| - borrow of `**x` occurs here
@@ -22,7 +22,7 @@ LL | drop((y, z));
2222
| - borrow later used here
2323

2424
error[E0499]: cannot borrow `*x` as mutable more than once at a time
25-
--> $DIR/coerce-overloaded-autoderef.rs:23:20
25+
--> $DIR/coerce-overloaded-autoderef-fail.rs:23:20
2626
|
2727
LL | borrow_mut2(x, x);
2828
| ----------- - ^ second mutable borrow occurs here
@@ -31,7 +31,7 @@ LL | borrow_mut2(x, x);
3131
| first borrow later used by call
3232

3333
error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable
34-
--> $DIR/coerce-overloaded-autoderef.rs:28:5
34+
--> $DIR/coerce-overloaded-autoderef-fail.rs:28:5
3535
|
3636
LL | borrow2(x, x);
3737
| -------^^^^-^
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,68 @@
1-
fn borrow_mut<T>(x: &mut T) -> &mut T { x }
2-
fn borrow<T>(x: &T) -> &T { x }
1+
// run-pass
2+
#![allow(unused_braces)]
3+
#![allow(dead_code)]
4+
// pretty-expanded FIXME #23616
35

4-
fn borrow_mut2<T>(_: &mut T, _: &mut T) {}
5-
fn borrow2<T>(_: &mut T, _: &T) {}
6+
use std::rc::Rc;
67

7-
fn double_mut_borrow<T>(x: &mut Box<T>) {
8-
let y = borrow_mut(x);
9-
let z = borrow_mut(x);
10-
//~^ ERROR cannot borrow `*x` as mutable more than once at a time
11-
drop((y, z));
8+
// Examples from the "deref coercions" RFC, at rust-lang/rfcs#241.
9+
10+
fn use_ref<T>(_: &T) {}
11+
fn use_mut<T>(_: &mut T) {}
12+
13+
fn use_rc<T>(t: Rc<T>) {
14+
use_ref(&*t); // what you have to write today
15+
use_ref(&t); // what you'd be able to write
16+
use_ref(&&&&&&t);
17+
use_ref(&mut &&&&&t);
18+
use_ref(&&&mut &&&t);
19+
}
20+
21+
fn use_mut_box<T>(mut t: &mut Box<T>) {
22+
use_mut(&mut *t); // what you have to write today
23+
use_mut(t); // what you'd be able to write
24+
use_mut(&mut &mut &mut t);
25+
26+
use_ref(&*t); // what you have to write today
27+
use_ref(t); // what you'd be able to write
28+
use_ref(&&&&&&t);
29+
use_ref(&mut &&&&&t);
30+
use_ref(&&&mut &&&t);
1231
}
1332

14-
fn double_imm_borrow(x: &mut Box<i32>) {
15-
let y = borrow(x);
16-
let z = borrow(x);
17-
**x += 1;
18-
//~^ ERROR cannot assign to `**x` because it is borrowed
19-
drop((y, z));
33+
fn use_nested<T>(t: &Box<T>) {
34+
use_ref(&**t); // what you have to write today
35+
use_ref(t); // what you'd be able to write (note: recursive deref)
36+
use_ref(&&&&&&t);
37+
use_ref(&mut &&&&&t);
38+
use_ref(&&&mut &&&t);
39+
}
40+
41+
fn use_slice(_: &[u8]) {}
42+
fn use_slice_mut(_: &mut [u8]) {}
43+
44+
fn use_vec(mut v: Vec<u8>) {
45+
use_slice_mut(&mut v[..]); // what you have to write today
46+
use_slice_mut(&mut v); // what you'd be able to write
47+
use_slice_mut(&mut &mut &mut v);
48+
49+
use_slice(&v[..]); // what you have to write today
50+
use_slice(&v); // what you'd be able to write
51+
use_slice(&&&&&&v);
52+
use_slice(&mut &&&&&v);
53+
use_slice(&&&mut &&&v);
2054
}
2155

22-
fn double_mut_borrow2<T>(x: &mut Box<T>) {
23-
borrow_mut2(x, x);
24-
//~^ ERROR cannot borrow `*x` as mutable more than once at a time
56+
fn use_vec_ref(v: &Vec<u8>) {
57+
use_slice(&v[..]); // what you have to write today
58+
use_slice(v); // what you'd be able to write
59+
use_slice(&&&&&&v);
60+
use_slice(&mut &&&&&v);
61+
use_slice(&&&mut &&&v);
2562
}
2663

27-
fn double_borrow2<T>(x: &mut Box<T>) {
28-
borrow2(x, x);
29-
//~^ ERROR cannot borrow `*x` as mutable because it is also borrowed as immutable
64+
fn use_op_rhs(s: &mut String) {
65+
*s += {&String::from(" ")};
3066
}
3167

3268
pub fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fn test<T>(_a: T, _b: T) {}
2+
3+
fn main() {
4+
test(&mut 7, &7);
5+
//~^ mismatched types
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/coerce-reborrow-multi-arg-fail.rs:4:18
3+
|
4+
LL | test(&mut 7, &7);
5+
| ^^ types differ in mutability
6+
|
7+
= note: expected mutable reference `&mut {integer}`
8+
found reference `&{integer}`
9+
10+
error: aborting due to previous error
11+
12+
For more information about this error, try `rustc --explain E0308`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// build-pass
2+
fn test<T>(_a: T, _b: T) {}
3+
4+
fn main() {
5+
test(&7, &7);
6+
test(&7, &mut 7);
7+
test::<&i32>(&mut 7, &7);
8+
test::<&i32>(&mut 7, &mut 7);
9+
}

src/test/ui/coercion/coerce-to-bang-cast.rs

-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
#![feature(never_type)]
22

3-
fn foo(x: usize, y: !, z: usize) { }
4-
53
fn cast_a() {
64
let y = {return; 22} as !;
75
//~^ ERROR non-primitive cast

src/test/ui/coercion/coerce-to-bang-cast.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
error[E0605]: non-primitive cast: `i32` as `!`
2-
--> $DIR/coerce-to-bang-cast.rs:6:13
2+
--> $DIR/coerce-to-bang-cast.rs:4:13
33
|
44
LL | let y = {return; 22} as !;
55
| ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
66

77
error[E0605]: non-primitive cast: `i32` as `!`
8-
--> $DIR/coerce-to-bang-cast.rs:11:13
8+
--> $DIR/coerce-to-bang-cast.rs:9:13
99
|
1010
LL | let y = 22 as !;
1111
| ^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object

0 commit comments

Comments
 (0)