Skip to content

Commit 6ab8f33

Browse files
committed
fix accidental type variable resolution in array coercion
1 parent 61cb1e9 commit 6ab8f33

File tree

2 files changed

+50
-1
lines changed

2 files changed

+50
-1
lines changed

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1817,11 +1817,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18171817
let element_ty = if !args.is_empty() {
18181818
let coerce_to = expected
18191819
.to_option(self)
1820-
.and_then(|uty| self.try_structurally_resolve_type(expr.span, uty).builtin_index())
1820+
.and_then(|uty| {
1821+
self.try_structurally_resolve_type(expr.span, uty)
1822+
.builtin_index()
1823+
// Avoid using the original type variable as the coerce_to type, as it may resolve
1824+
// during the first coercion instead of being the LUB type.
1825+
.filter(|t| !self.try_structurally_resolve_type(expr.span, *t).is_ty_var())
1826+
})
18211827
.unwrap_or_else(|| self.next_ty_var(expr.span));
18221828
let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
18231829
assert_eq!(self.diverges.get(), Diverges::Maybe);
18241830
for e in args {
1831+
// FIXME: the element expectation should use
1832+
// `try_structurally_resolve_and_adjust_for_branches` just like in `if` and `match`.
1833+
// While that fixes nested coercion, it will break [some
1834+
// code like this](https://github.com/rust-lang/rust/pull/140283#issuecomment-2958776528).
1835+
// If we find a way to support recursive tuple coercion, this break can be avoided.
18251836
let e_ty = self.check_expr_with_hint(e, coerce_to);
18261837
let cause = self.misc(e.span);
18271838
coerce.coerce(self, &cause, e, e_ty);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//@ run-pass
2+
// Check that least upper bound coercions don't resolve type variable merely based on the first
3+
// coercion. Check issue #136420.
4+
5+
fn foo() {}
6+
fn bar() {}
7+
8+
fn infer<T>(_: T) {}
9+
10+
fn infer_array_element<T>(_: [T; 2]) {}
11+
12+
fn main() {
13+
// Previously the element type's ty var will be unified with `foo`.
14+
let _: [_; 2] = [foo, bar];
15+
infer_array_element([foo, bar]);
16+
17+
let _ = if false {
18+
foo
19+
} else {
20+
bar
21+
};
22+
infer(if false {
23+
foo
24+
} else {
25+
bar
26+
});
27+
28+
let _ = match false {
29+
true => foo,
30+
false => bar,
31+
};
32+
infer(match false {
33+
true => foo,
34+
false => bar,
35+
});
36+
37+
38+
}

0 commit comments

Comments
 (0)