Skip to content

Commit 0bdee9e

Browse files
Auto merge of #150097 - jackh726:coercion-cleanup, r=<try>
Coercion cleanup
2 parents f2c7087 + 6bae9c3 commit 0bdee9e

File tree

11 files changed

+632
-41
lines changed

11 files changed

+632
-41
lines changed

compiler/rustc_hir_typeck/src/_match.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7575
};
7676
CoerceMany::with_coercion_sites(coerce_first, arms)
7777
};
78+
coercion.force_lub();
7879

7980
let mut prior_non_diverging_arms = vec![]; // Used only for diagnostics.
8081
let mut prior_arm = None;

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1290,29 +1290,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12901290
let mut coerce = Coerce::new(self, cause.clone(), AllowTwoPhase::No, true);
12911291
coerce.use_lub = true;
12921292

1293-
// First try to coerce the new expression to the type of the previous ones,
1294-
// but only if the new expression has no coercion already applied to it.
1295-
let mut first_error = None;
1296-
if !self.typeck_results.borrow().adjustments().contains_key(new.hir_id) {
1297-
let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
1298-
match result {
1299-
Ok(ok) => {
1300-
let (adjustments, target) = self.register_infer_ok_obligations(ok);
1301-
self.apply_adjustments(new, adjustments);
1302-
debug!(
1303-
"coercion::try_find_coercion_lub: was able to coerce from new type {:?} to previous type {:?} ({:?})",
1304-
new_ty, prev_ty, target
1305-
);
1306-
return Ok(target);
1307-
}
1308-
Err(e) => first_error = Some(e),
1293+
// This might be okay, but we previously branched on this without any
1294+
// test, so I'm just keeping the assert to avoid surprising behavior.
1295+
assert!(!self.typeck_results.borrow().adjustments().contains_key(new.hir_id));
1296+
1297+
// First try to coerce the new expression to the type of the previous ones.
1298+
let result = self.commit_if_ok(|_| coerce.coerce(new_ty, prev_ty));
1299+
let first_error = match result {
1300+
Ok(ok) => {
1301+
let (adjustments, target) = self.register_infer_ok_obligations(ok);
1302+
self.apply_adjustments(new, adjustments);
1303+
debug!(
1304+
"coercion::try_find_coercion_lub: was able to coerce from new type {:?} to previous type {:?} ({:?})",
1305+
new_ty, prev_ty, target
1306+
);
1307+
return Ok(target);
13091308
}
1310-
}
1309+
Err(e) => e,
1310+
};
13111311

13121312
let ok = self
13131313
.commit_if_ok(|_| coerce.coerce(prev_ty, new_ty))
13141314
// Avoid giving strange errors on failed attempts.
1315-
.map_err(|e| first_error.unwrap_or(e))?;
1315+
.map_err(|_| first_error)?;
13161316

13171317
let (adjustments, target) = self.register_infer_ok_obligations(ok);
13181318
for expr in exprs {
@@ -1387,6 +1387,7 @@ pub(crate) struct CoerceMany<'tcx, 'exprs, E: AsCoercionSite> {
13871387
final_ty: Option<Ty<'tcx>>,
13881388
expressions: Expressions<'tcx, 'exprs, E>,
13891389
pushed: usize,
1390+
force_lub: bool,
13901391
}
13911392

13921393
/// The type of a `CoerceMany` that is storing up the expressions into
@@ -1416,7 +1417,13 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
14161417
}
14171418

14181419
fn make(expected_ty: Ty<'tcx>, expressions: Expressions<'tcx, 'exprs, E>) -> Self {
1419-
CoerceMany { expected_ty, final_ty: None, expressions, pushed: 0 }
1420+
CoerceMany { expected_ty, final_ty: None, expressions, pushed: 0, force_lub: false }
1421+
}
1422+
1423+
pub(crate) fn force_lub(&mut self) {
1424+
// Don't accidentally let someone switch this after coercing things
1425+
assert_eq!(self.pushed, 0);
1426+
self.force_lub = true;
14201427
}
14211428

14221429
/// Returns the "expected type" with which this coercion was
@@ -1529,10 +1536,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
15291536

15301537
// Handle the actual type unification etc.
15311538
let result = if let Some(expression) = expression {
1532-
if self.pushed == 0 {
1533-
// Special-case the first expression we are coercing.
1534-
// To be honest, I'm not entirely sure why we do this.
1535-
// We don't allow two-phase borrows, see comment in try_find_coercion_lub for why
1539+
if !self.force_lub && self.pushed == 0 {
1540+
// For this *first* expression, we do *not* use LUB
1541+
// (which `try_find_coercion_lub` does).
15361542
fcx.coerce(
15371543
expression,
15381544
expression_ty,

tests/ui/coercion/coerce-loop-issue-122561.stderr

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,6 @@ LL | | }
9090
|
9191
= note: expected type `!`
9292
found unit type `()`
93-
= note: `for` loops evaluate to unit type `()`
94-
help: consider adding a diverging expression here
95-
|
96-
LL ~ }
97-
LL + /* `loop {}` or `panic!("...")` */
98-
|
9993

10094
error[E0308]: mismatched types
10195
--> $DIR/coerce-loop-issue-122561.rs:35:32
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
//@ check-fail
2+
//@ known-bug: #148283
3+
4+
#![allow(static_mut_refs)]
5+
#![allow(dead_code)]
6+
use std::ops::Deref;
7+
8+
pub static mut ACTIONS: Vec<&'static str> = Vec::new();
9+
10+
pub struct Wrap<T: ?Sized>(T);
11+
12+
// Deref Chain: FinalType <- UnsizedArray <- IntWrapper <- ArrayWrapper <- TopType
13+
pub struct TopType;
14+
pub type ArrayWrapper = Wrap<[i32; 0]>;
15+
pub struct IntWrapper;
16+
pub type UnsizedArray = Wrap<[i32]>;
17+
pub struct FinalType;
18+
pub struct TopTypeNoTrait;
19+
20+
impl Deref for TopType {
21+
type Target = ArrayWrapper;
22+
fn deref(&self) -> &Self::Target {
23+
unsafe { ACTIONS.push("deref TopType->ArrayWrapper"); }
24+
&Wrap([])
25+
}
26+
}
27+
28+
impl Deref for ArrayWrapper {
29+
type Target = IntWrapper;
30+
fn deref(&self) -> &Self::Target {
31+
unsafe { ACTIONS.push("deref ArrayWrapper->IntWrapper"); }
32+
&IntWrapper
33+
}
34+
}
35+
36+
impl Deref for IntWrapper {
37+
type Target = UnsizedArray;
38+
fn deref(&self) -> &Self::Target {
39+
unsafe { ACTIONS.push("deref IntWrapper->UnsizedArray"); }
40+
&Wrap([])
41+
}
42+
}
43+
44+
impl Deref for UnsizedArray {
45+
type Target = FinalType;
46+
fn deref(&self) -> &Self::Target {
47+
unsafe { ACTIONS.push("deref UnsizedArray->FinalType"); }
48+
&FinalType
49+
}
50+
}
51+
52+
impl Deref for TopTypeNoTrait {
53+
type Target = ArrayWrapper;
54+
fn deref(&self) -> &Self::Target {
55+
unsafe { ACTIONS.push("deref TopTypeNoTrait->ArrayWrapper"); }
56+
&Wrap([])
57+
}
58+
}
59+
60+
trait Trait {
61+
fn self_ty(&self);
62+
63+
fn complete(&self) -> Vec<&'static str> {
64+
self.self_ty();
65+
let actions = unsafe { ACTIONS.clone() };
66+
unsafe { ACTIONS.clear() };
67+
actions
68+
}
69+
}
70+
71+
impl Trait for TopType {
72+
fn self_ty(&self) {
73+
unsafe { ACTIONS.push("self_ty TopType"); }
74+
}
75+
}
76+
77+
impl Trait for ArrayWrapper {
78+
fn self_ty(&self) {
79+
unsafe { ACTIONS.push("self_ty ArrayWrapper"); }
80+
}
81+
}
82+
83+
impl Trait for IntWrapper {
84+
fn self_ty(&self) {
85+
unsafe { ACTIONS.push("self_ty IntWrapper"); }
86+
}
87+
}
88+
89+
impl Trait for UnsizedArray {
90+
fn self_ty(&self) {
91+
unsafe { ACTIONS.push("self_ty UnsizedArray"); }
92+
}
93+
}
94+
95+
impl Trait for FinalType {
96+
fn self_ty(&self) {
97+
unsafe { ACTIONS.push("self_ty FinalType"); }
98+
}
99+
}
100+
101+
fn deref_to_dyn_direct() {
102+
let x = match 0 {
103+
0 => &TopTypeNoTrait as &TopTypeNoTrait,
104+
1 => &TopTypeNoTrait as &FinalType as &dyn Trait,
105+
_ => loop {},
106+
};
107+
}
108+
109+
fn main() {
110+
deref_to_dyn_direct();
111+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
error[E0277]: the trait bound `TopTypeNoTrait: Trait` is not satisfied
2+
--> $DIR/multistep-fail.rs:104:14
3+
|
4+
LL | 1 => &TopTypeNoTrait as &FinalType as &dyn Trait,
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound
6+
|
7+
help: the trait `Trait` is not implemented for `TopTypeNoTrait`
8+
--> $DIR/multistep-fail.rs:18:1
9+
|
10+
LL | pub struct TopTypeNoTrait;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
12+
= help: the following other types implement trait `Trait`:
13+
FinalType
14+
IntWrapper
15+
TopType
16+
Wrap<[i32; 0]>
17+
Wrap<[i32]>
18+
= note: required for the cast from `&TopTypeNoTrait` to `&dyn Trait`
19+
20+
error: aborting due to 1 previous error
21+
22+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)