Skip to content

Commit ff43249

Browse files
authored
Rollup merge of #112303 - Nilstrieb:as-deref, r=compiler-errors
Normalize in infcx instead of globally for `Option::as_deref` suggestion fixes #112293 The projection may contain inference variables. These inference variables are local to the local inference context. Using `tcx.normalize_erasing_regions` doesn't work here because this method is global and does not have access to the inference context. It's therefore unable to deal with the inference variables. We normalize in the local inference context instead, which knowns about the inference variables. The test looks a little different than the issue example, I made it more minimal and verified that it still ICEs on nightly. Also contains a drive-by fix to properly compare the types. r? `@compiler-errors`
2 parents 9ce0c79 + c12575d commit ff43249

8 files changed

+89
-39
lines changed

Diff for: compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -3592,8 +3592,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
35923592
// Extract `<U as Deref>::Target` assoc type and check that it is `T`
35933593
&& let Some(deref_target_did) = tcx.lang_items().deref_target()
35943594
&& let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
3595-
&& let Ok(deref_target) = tcx.try_normalize_erasing_regions(param_env, projection)
3596-
&& deref_target == target_ty
3595+
&& let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
3596+
&& obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
3597+
&& infcx.can_eq(param_env, deref_target, target_ty)
35973598
{
35983599
let help = if let hir::Mutability::Mut = needs_mut
35993600
&& let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
fn deref_int(a: &i32) -> i32 {
2+
*a
3+
}
4+
5+
fn main() {
6+
// https://github.com/rust-lang/rust/issues/112293
7+
let _has_inference_vars: Option<i32> = Some(0).map(deref_int);
8+
//~^ ERROR type mismatch in function arguments
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error[E0631]: type mismatch in function arguments
2+
--> $DIR/suggest-option-asderef-inference-var.rs:7:56
3+
|
4+
LL | fn deref_int(a: &i32) -> i32 {
5+
| ---------------------------- found signature defined here
6+
...
7+
LL | let _has_inference_vars: Option<i32> = Some(0).map(deref_int);
8+
| --- ^^^^^^^^^ expected due to this
9+
| |
10+
| required by a bound introduced by this call
11+
|
12+
= note: expected function signature `fn({integer}) -> _`
13+
found function signature `for<'a> fn(&'a i32) -> _`
14+
note: required by a bound in `Option::<T>::map`
15+
--> $SRC_DIR/core/src/option.rs:LL:COL
16+
help: do not borrow the argument
17+
|
18+
LL - fn deref_int(a: &i32) -> i32 {
19+
LL + fn deref_int(a: i32) -> i32 {
20+
|
21+
22+
error: aborting due to previous error
23+
24+
For more information about this error, try `rustc --explain E0631`.

Diff for: tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs

-6
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,6 @@ fn no_args() -> Option<()> {
1010
Some(())
1111
}
1212

13-
fn generic_ref<T>(_: &T) -> Option<()> {
14-
Some(())
15-
}
16-
1713
extern "C" fn takes_str_but_wrong_abi(_: &str) -> Option<()> {
1814
Some(())
1915
}
@@ -33,8 +29,6 @@ fn main() {
3329
//~^ ERROR expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
3430
let _ = produces_string().and_then(no_args);
3531
//~^ ERROR function is expected to take 1 argument, but it takes 0 arguments
36-
let _ = produces_string().and_then(generic_ref);
37-
//~^ ERROR type mismatch in function arguments
3832
let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs);
3933
//~^ ERROR type mismatch in function arguments
4034
}

Diff for: tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr

+6-27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0631]: type mismatch in function arguments
2-
--> $DIR/suggest-option-asderef-unfixable.rs:28:40
2+
--> $DIR/suggest-option-asderef-unfixable.rs:24:40
33
|
44
LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
55
| ------------------------------------------------------ found signature defined here
@@ -15,7 +15,7 @@ note: required by a bound in `Option::<T>::and_then`
1515
--> $SRC_DIR/core/src/option.rs:LL:COL
1616

1717
error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
18-
--> $DIR/suggest-option-asderef-unfixable.rs:30:40
18+
--> $DIR/suggest-option-asderef-unfixable.rs:26:40
1919
|
2020
LL | let _ = produces_string().and_then(takes_str_but_wrong_abi);
2121
| -------- ^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
@@ -27,7 +27,7 @@ note: required by a bound in `Option::<T>::and_then`
2727
--> $SRC_DIR/core/src/option.rs:LL:COL
2828

2929
error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
30-
--> $DIR/suggest-option-asderef-unfixable.rs:32:40
30+
--> $DIR/suggest-option-asderef-unfixable.rs:28:40
3131
|
3232
LL | let _ = produces_string().and_then(takes_str_but_unsafe);
3333
| -------- ^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@@ -40,7 +40,7 @@ note: required by a bound in `Option::<T>::and_then`
4040
--> $SRC_DIR/core/src/option.rs:LL:COL
4141

4242
error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
43-
--> $DIR/suggest-option-asderef-unfixable.rs:34:40
43+
--> $DIR/suggest-option-asderef-unfixable.rs:30:40
4444
|
4545
LL | fn no_args() -> Option<()> {
4646
| -------------------------- takes 0 arguments
@@ -54,28 +54,7 @@ note: required by a bound in `Option::<T>::and_then`
5454
--> $SRC_DIR/core/src/option.rs:LL:COL
5555

5656
error[E0631]: type mismatch in function arguments
57-
--> $DIR/suggest-option-asderef-unfixable.rs:36:40
58-
|
59-
LL | fn generic_ref<T>(_: &T) -> Option<()> {
60-
| -------------------------------------- found signature defined here
61-
...
62-
LL | let _ = produces_string().and_then(generic_ref);
63-
| -------- ^^^^^^^^^^^ expected due to this
64-
| |
65-
| required by a bound introduced by this call
66-
|
67-
= note: expected function signature `fn(String) -> _`
68-
found function signature `for<'a> fn(&'a _) -> _`
69-
note: required by a bound in `Option::<T>::and_then`
70-
--> $SRC_DIR/core/src/option.rs:LL:COL
71-
help: do not borrow the argument
72-
|
73-
LL - fn generic_ref<T>(_: &T) -> Option<()> {
74-
LL + fn generic_ref<T>(_: T) -> Option<()> {
75-
|
76-
77-
error[E0631]: type mismatch in function arguments
78-
--> $DIR/suggest-option-asderef-unfixable.rs:38:45
57+
--> $DIR/suggest-option-asderef-unfixable.rs:32:45
7958
|
8059
LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
8160
| ------------------------------------------------------ found signature defined here
@@ -90,7 +69,7 @@ LL | let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs);
9069
note: required by a bound in `Option::<T>::and_then`
9170
--> $SRC_DIR/core/src/option.rs:LL:COL
9271

93-
error: aborting due to 6 previous errors
72+
error: aborting due to 5 previous errors
9473

9574
Some errors have detailed explanations: E0277, E0593, E0631.
9675
For more information about an error, try `rustc --explain E0277`.

Diff for: tests/ui/mismatched_types/suggest-option-asderef.fixed

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ fn generic<T>(_: T) -> Option<()> {
1616
Some(())
1717
}
1818

19+
fn generic_ref<T>(_: T) -> Option<()> {
20+
//~^ HELP do not borrow the argument
21+
Some(())
22+
}
23+
1924
fn main() {
2025
let _: Option<()> = produces_string().as_deref().and_then(takes_str);
2126
//~^ ERROR type mismatch in function arguments
@@ -27,4 +32,8 @@ fn main() {
2732
//~^ ERROR type mismatch in function arguments
2833
//~| HELP call `Option::as_deref_mut()` first
2934
let _ = produces_string().and_then(generic);
35+
36+
let _ = produces_string().as_deref().and_then(generic_ref);
37+
//~^ ERROR type mismatch in function arguments
38+
//~| HELP call `Option::as_deref()` first
3039
}

Diff for: tests/ui/mismatched_types/suggest-option-asderef.rs

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ fn generic<T>(_: T) -> Option<()> {
1616
Some(())
1717
}
1818

19+
fn generic_ref<T>(_: &T) -> Option<()> {
20+
//~^ HELP do not borrow the argument
21+
Some(())
22+
}
23+
1924
fn main() {
2025
let _: Option<()> = produces_string().and_then(takes_str);
2126
//~^ ERROR type mismatch in function arguments
@@ -27,4 +32,8 @@ fn main() {
2732
//~^ ERROR type mismatch in function arguments
2833
//~| HELP call `Option::as_deref_mut()` first
2934
let _ = produces_string().and_then(generic);
35+
36+
let _ = produces_string().and_then(generic_ref);
37+
//~^ ERROR type mismatch in function arguments
38+
//~| HELP call `Option::as_deref()` first
3039
}

Diff for: tests/ui/mismatched_types/suggest-option-asderef.stderr

+29-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0631]: type mismatch in function arguments
2-
--> $DIR/suggest-option-asderef.rs:20:52
2+
--> $DIR/suggest-option-asderef.rs:25:52
33
|
44
LL | fn takes_str(_: &str) -> Option<()> {
55
| ----------------------------------- found signature defined here
@@ -19,7 +19,7 @@ LL | let _: Option<()> = produces_string().as_deref().and_then(takes_str);
1919
| +++++++++++
2020

2121
error[E0631]: type mismatch in function arguments
22-
--> $DIR/suggest-option-asderef.rs:23:55
22+
--> $DIR/suggest-option-asderef.rs:28:55
2323
|
2424
LL | fn takes_str(_: &str) -> Option<()> {
2525
| ----------------------------------- found signature defined here
@@ -39,7 +39,7 @@ LL | let _: Option<Option<()>> = produces_string().as_deref().map(takes_str)
3939
| +++++++++++
4040

4141
error[E0631]: type mismatch in function arguments
42-
--> $DIR/suggest-option-asderef.rs:26:55
42+
--> $DIR/suggest-option-asderef.rs:31:55
4343
|
4444
LL | fn takes_str_mut(_: &mut str) -> Option<()> {
4545
| ------------------------------------------- found signature defined here
@@ -58,6 +58,31 @@ help: call `Option::as_deref_mut()` first
5858
LL | let _: Option<Option<()>> = produces_string().as_deref_mut().map(takes_str_mut);
5959
| +++++++++++++++
6060

61-
error: aborting due to 3 previous errors
61+
error[E0631]: type mismatch in function arguments
62+
--> $DIR/suggest-option-asderef.rs:36:40
63+
|
64+
LL | fn generic_ref<T>(_: &T) -> Option<()> {
65+
| -------------------------------------- found signature defined here
66+
...
67+
LL | let _ = produces_string().and_then(generic_ref);
68+
| -------- ^^^^^^^^^^^ expected due to this
69+
| |
70+
| required by a bound introduced by this call
71+
|
72+
= note: expected function signature `fn(String) -> _`
73+
found function signature `for<'a> fn(&'a _) -> _`
74+
note: required by a bound in `Option::<T>::and_then`
75+
--> $SRC_DIR/core/src/option.rs:LL:COL
76+
help: do not borrow the argument
77+
|
78+
LL - fn generic_ref<T>(_: &T) -> Option<()> {
79+
LL + fn generic_ref<T>(_: T) -> Option<()> {
80+
|
81+
help: call `Option::as_deref()` first
82+
|
83+
LL | let _ = produces_string().as_deref().and_then(generic_ref);
84+
| +++++++++++
85+
86+
error: aborting due to 4 previous errors
6287

6388
For more information about this error, try `rustc --explain E0631`.

0 commit comments

Comments
 (0)