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`
This commit is contained in:
Matthias Krüger 2023-06-05 23:47:59 +02:00 committed by GitHub
commit ff43249b0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 89 additions and 39 deletions

View File

@ -3592,8 +3592,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// Extract `<U as Deref>::Target` assoc type and check that it is `T`
&& let Some(deref_target_did) = tcx.lang_items().deref_target()
&& let projection = tcx.mk_projection(deref_target_did, tcx.mk_substs(&[ty::GenericArg::from(found_ty)]))
&& let Ok(deref_target) = tcx.try_normalize_erasing_regions(param_env, projection)
&& deref_target == target_ty
&& let InferOk { value: deref_target, obligations } = infcx.at(&ObligationCause::dummy(), param_env).normalize(projection)
&& obligations.iter().all(|obligation| infcx.predicate_must_hold_modulo_regions(obligation))
&& infcx.can_eq(param_env, deref_target, target_ty)
{
let help = if let hir::Mutability::Mut = needs_mut
&& let Some(deref_mut_did) = tcx.lang_items().deref_mut_trait()

View File

@ -0,0 +1,9 @@
fn deref_int(a: &i32) -> i32 {
*a
}
fn main() {
// https://github.com/rust-lang/rust/issues/112293
let _has_inference_vars: Option<i32> = Some(0).map(deref_int);
//~^ ERROR type mismatch in function arguments
}

View File

@ -0,0 +1,24 @@
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef-inference-var.rs:7:56
|
LL | fn deref_int(a: &i32) -> i32 {
| ---------------------------- found signature defined here
...
LL | let _has_inference_vars: Option<i32> = Some(0).map(deref_int);
| --- ^^^^^^^^^ expected due to this
| |
| required by a bound introduced by this call
|
= note: expected function signature `fn({integer}) -> _`
found function signature `for<'a> fn(&'a i32) -> _`
note: required by a bound in `Option::<T>::map`
--> $SRC_DIR/core/src/option.rs:LL:COL
help: do not borrow the argument
|
LL - fn deref_int(a: &i32) -> i32 {
LL + fn deref_int(a: i32) -> i32 {
|
error: aborting due to previous error
For more information about this error, try `rustc --explain E0631`.

View File

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

View File

@ -1,5 +1,5 @@
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef-unfixable.rs:28:40
--> $DIR/suggest-option-asderef-unfixable.rs:24:40
|
LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
| ------------------------------------------------------ found signature defined here
@ -15,7 +15,7 @@ note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> extern "C" fn(&'a str) -> Option<()> {takes_str_but_wrong_abi}`
--> $DIR/suggest-option-asderef-unfixable.rs:30:40
--> $DIR/suggest-option-asderef-unfixable.rs:26:40
|
LL | let _ = produces_string().and_then(takes_str_but_wrong_abi);
| -------- ^^^^^^^^^^^^^^^^^^^^^^^ 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`
--> $SRC_DIR/core/src/option.rs:LL:COL
error[E0277]: expected a `FnOnce<(String,)>` closure, found `for<'a> unsafe fn(&'a str) -> Option<()> {takes_str_but_unsafe}`
--> $DIR/suggest-option-asderef-unfixable.rs:32:40
--> $DIR/suggest-option-asderef-unfixable.rs:28:40
|
LL | let _ = produces_string().and_then(takes_str_but_unsafe);
| -------- ^^^^^^^^^^^^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
@ -40,7 +40,7 @@ note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
error[E0593]: function is expected to take 1 argument, but it takes 0 arguments
--> $DIR/suggest-option-asderef-unfixable.rs:34:40
--> $DIR/suggest-option-asderef-unfixable.rs:30:40
|
LL | fn no_args() -> Option<()> {
| -------------------------- takes 0 arguments
@ -54,28 +54,7 @@ note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef-unfixable.rs:36:40
|
LL | fn generic_ref<T>(_: &T) -> Option<()> {
| -------------------------------------- found signature defined here
...
LL | let _ = produces_string().and_then(generic_ref);
| -------- ^^^^^^^^^^^ expected due to this
| |
| required by a bound introduced by this call
|
= note: expected function signature `fn(String) -> _`
found function signature `for<'a> fn(&'a _) -> _`
note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
help: do not borrow the argument
|
LL - fn generic_ref<T>(_: &T) -> Option<()> {
LL + fn generic_ref<T>(_: T) -> Option<()> {
|
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef-unfixable.rs:38:45
--> $DIR/suggest-option-asderef-unfixable.rs:32:45
|
LL | fn takes_str_but_too_many_refs(_: &&str) -> Option<()> {
| ------------------------------------------------------ found signature defined here
@ -90,7 +69,7 @@ LL | let _ = Some(TypeWithoutDeref).and_then(takes_str_but_too_many_refs);
note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
error: aborting due to 6 previous errors
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0277, E0593, E0631.
For more information about an error, try `rustc --explain E0277`.

View File

@ -16,6 +16,11 @@ fn generic<T>(_: T) -> Option<()> {
Some(())
}
fn generic_ref<T>(_: T) -> Option<()> {
//~^ HELP do not borrow the argument
Some(())
}
fn main() {
let _: Option<()> = produces_string().as_deref().and_then(takes_str);
//~^ ERROR type mismatch in function arguments
@ -27,4 +32,8 @@ fn main() {
//~^ ERROR type mismatch in function arguments
//~| HELP call `Option::as_deref_mut()` first
let _ = produces_string().and_then(generic);
let _ = produces_string().as_deref().and_then(generic_ref);
//~^ ERROR type mismatch in function arguments
//~| HELP call `Option::as_deref()` first
}

View File

@ -16,6 +16,11 @@ fn generic<T>(_: T) -> Option<()> {
Some(())
}
fn generic_ref<T>(_: &T) -> Option<()> {
//~^ HELP do not borrow the argument
Some(())
}
fn main() {
let _: Option<()> = produces_string().and_then(takes_str);
//~^ ERROR type mismatch in function arguments
@ -27,4 +32,8 @@ fn main() {
//~^ ERROR type mismatch in function arguments
//~| HELP call `Option::as_deref_mut()` first
let _ = produces_string().and_then(generic);
let _ = produces_string().and_then(generic_ref);
//~^ ERROR type mismatch in function arguments
//~| HELP call `Option::as_deref()` first
}

View File

@ -1,5 +1,5 @@
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef.rs:20:52
--> $DIR/suggest-option-asderef.rs:25:52
|
LL | fn takes_str(_: &str) -> Option<()> {
| ----------------------------------- found signature defined here
@ -19,7 +19,7 @@ LL | let _: Option<()> = produces_string().as_deref().and_then(takes_str);
| +++++++++++
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef.rs:23:55
--> $DIR/suggest-option-asderef.rs:28:55
|
LL | fn takes_str(_: &str) -> Option<()> {
| ----------------------------------- found signature defined here
@ -39,7 +39,7 @@ LL | let _: Option<Option<()>> = produces_string().as_deref().map(takes_str)
| +++++++++++
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef.rs:26:55
--> $DIR/suggest-option-asderef.rs:31:55
|
LL | fn takes_str_mut(_: &mut str) -> Option<()> {
| ------------------------------------------- found signature defined here
@ -58,6 +58,31 @@ help: call `Option::as_deref_mut()` first
LL | let _: Option<Option<()>> = produces_string().as_deref_mut().map(takes_str_mut);
| +++++++++++++++
error: aborting due to 3 previous errors
error[E0631]: type mismatch in function arguments
--> $DIR/suggest-option-asderef.rs:36:40
|
LL | fn generic_ref<T>(_: &T) -> Option<()> {
| -------------------------------------- found signature defined here
...
LL | let _ = produces_string().and_then(generic_ref);
| -------- ^^^^^^^^^^^ expected due to this
| |
| required by a bound introduced by this call
|
= note: expected function signature `fn(String) -> _`
found function signature `for<'a> fn(&'a _) -> _`
note: required by a bound in `Option::<T>::and_then`
--> $SRC_DIR/core/src/option.rs:LL:COL
help: do not borrow the argument
|
LL - fn generic_ref<T>(_: &T) -> Option<()> {
LL + fn generic_ref<T>(_: T) -> Option<()> {
|
help: call `Option::as_deref()` first
|
LL | let _ = produces_string().as_deref().and_then(generic_ref);
| +++++++++++
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0631`.