diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs index 87b7f3406ff7..a85a99145435 100644 --- a/crates/hir-ty/src/infer/expr.rs +++ b/crates/hir-ty/src/infer/expr.rs @@ -1164,7 +1164,9 @@ impl InferenceContext<'_> { expected: &Expectation, ) -> chalk_ir::Ty { let elem_ty = match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(Interner)) { - Some(TyKind::Array(st, _) | TyKind::Slice(st)) => st.clone(), + // Avoid using a type variable as the coerce_to type, as it may resolve + // during the first coercion instead of being based on the common type. + Some(TyKind::Array(st, _) | TyKind::Slice(st)) if !st.is_ty_var() => st.clone(), _ => self.table.new_type_var(), }; diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs index ddc5b715194d..d420fe05774e 100644 --- a/crates/hir-ty/src/tests/coercion.rs +++ b/crates/hir-ty/src/tests/coercion.rs @@ -96,7 +96,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test() { let x = if true { foo(&[1]) - // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?7, Not)), Pointer(Unsize) } else { &[1] }; @@ -148,7 +148,7 @@ fn foo(x: &[T]) -> &[T] { x } fn test(i: i32) { let x = match i { 2 => foo(&[2]), - // ^^^^ adjustments: Deref(None), Borrow(Ref('?8, Not)), Pointer(Unsize) + // ^^^^ adjustments: Deref(None), Borrow(Ref('?7, Not)), Pointer(Unsize) 1 => &[1], _ => &[3], }; @@ -957,3 +957,35 @@ fn f() { "#, ); } + +#[test] +fn coerce_array_elements() { + check_no_mismatches( + r#" +// Check that least upper bound coercions don't resolve type variable merely based on the first +// coercion. Check issue rust-lang/rust#136420. + +fn foo() {} +fn bar() {} + +fn infer(_: T) {} + +fn infer_array_element(_: [T; 2]) {} + +fn main() { + infer(if false { + foo + } else { + bar + }); + + infer(match false { + true => foo, + false => bar, + }); + + infer_array_element([foo, bar]); +} + "#, + ); +}