Commit 35a31ba
committed
Auto merge of rust-lang#140283 - adwinwhite:fn-pointer-coercion, r=jackh726
Fix accidental type inference in array coercion
Fixes rust-lang#136420.
If the expectation of array element is a type variable, we should avoid resolving it to the first element's type and wait until LUB coercion is completed.
We create a free type variable instead which is only used in this `CoerceMany`.
[`check_expr_match`](https://github.com/rust-lang/rust/blob/847e3ee6b0e614937eee4e6d8f61094411eadcc0/compiler/rustc_hir_typeck/src/_match.rs#L72) and [`check_expr_if`](https://github.com/rust-lang/rust/blob/847e3ee6b0e614937eee4e6d8f61094411eadcc0/compiler/rustc_hir_typeck/src/expr.rs#L1329) where `CoerceMany` is also used do the [same](https://github.com/rust-lang/rust/blob/847e3ee6b0e614937eee4e6d8f61094411eadcc0/compiler/rustc_hir_typeck/src/expectation.rs#L50).
### [FCP Proposal](rust-lang#140283 (comment)):
> Array expressions normally lub their element expressions' types to ensure that things like `[5, 5_u8]` work and don't result in type mismatches. When invoking a generic function `fn foo<T>(_: [T; N])` with an array expression, we end up with an infer var for the element type of the array in the signature. So when typecking the first array element we compare its type with the infer var and thus subsequently require all other elements to be the same type.
>
> This PR changes that to instead fall back to "not knowing" that the argument type is array of infer var, but just having an infer var for the entire argument. Thus we typeck the array expression normally, lubbing the element expressions, and then in the end comparing the array expression's type with the array of infer var type.
>
> Things like
>
> ```rust
> fn foo() {}
> fn bar() {}
> fn f<T>(_: [T; 2]) {}
>
> f([foo, bar]);
> ```
>
> and
>
> ```rust
> struct Foo;
> struct Bar;
> trait Trait {}
> impl Trait for Foo {}
> impl Trait for Bar {}
> fn f<T>(_: [T; 2]) {}
>
> f([&Foo, &Bar as &dyn Trait]);
> ```
### Remaining inconsistency with `if` and `match`(rust-lang#145048):
The typeck of array always uses the element coercion target type as the expectation of element exprs while `if` and `match` use `NoExpectation` if the expected type is an infer var.
This causes that array doesn't support nested coercion.
```rust
fn foo() {}
fn bar() {}
fn main() {
let _ = [foo, if false { bar } else { foo }]; // type mismatch when trying to coerce `bar` into `foo` in if-then branch coercion.
}
```
But we can't simply change this behavior to be the same as `if` and `match` since [many code](rust-lang#140283 (comment)) depends on using the first element's type as expectation.File tree
5 files changed
+92
-1
lines changed- compiler/rustc_hir_typeck/src
- tests/ui/coercion
5 files changed
+92
-1
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1365 | 1365 | | |
1366 | 1366 | | |
1367 | 1367 | | |
| 1368 | + | |
1368 | 1369 | | |
1369 | 1370 | | |
1370 | 1371 | | |
| |||
1378 | 1379 | | |
1379 | 1380 | | |
1380 | 1381 | | |
| 1382 | + | |
| 1383 | + | |
| 1384 | + | |
| 1385 | + | |
| 1386 | + | |
| 1387 | + | |
| 1388 | + | |
| 1389 | + | |
| 1390 | + | |
| 1391 | + | |
| 1392 | + | |
| 1393 | + | |
| 1394 | + | |
| 1395 | + | |
| 1396 | + | |
| 1397 | + | |
| 1398 | + | |
| 1399 | + | |
| 1400 | + | |
| 1401 | + | |
| 1402 | + | |
| 1403 | + | |
1381 | 1404 | | |
1382 | 1405 | | |
1383 | 1406 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1670 | 1670 | | |
1671 | 1671 | | |
1672 | 1672 | | |
1673 | | - | |
| 1673 | + | |
| 1674 | + | |
| 1675 | + | |
| 1676 | + | |
| 1677 | + | |
| 1678 | + | |
| 1679 | + | |
1674 | 1680 | | |
1675 | 1681 | | |
1676 | 1682 | | |
1677 | 1683 | | |
| 1684 | + | |
| 1685 | + | |
| 1686 | + | |
| 1687 | + | |
| 1688 | + | |
1678 | 1689 | | |
1679 | 1690 | | |
1680 | 1691 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
0 commit comments