about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-06-05 23:47:59 +0200
committerGitHub <noreply@github.com>2023-06-05 23:47:59 +0200
commitff43249b0efd274322cbd53441ff15fcdb7096ba (patch)
tree12b88e1283e15bc709000578948d56ef04eea717
parent9ce0c7951c3f36d81809e43584c601536badb45f (diff)
parentc12575d3173eb6ba985482808a87e54f23ad328e (diff)
downloadrust-ff43249b0efd274322cbd53441ff15fcdb7096ba.tar.gz
rust-ff43249b0efd274322cbd53441ff15fcdb7096ba.zip
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`
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs5
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs9
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr24
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs6
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr33
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.fixed9
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.rs9
-rw-r--r--tests/ui/mismatched_types/suggest-option-asderef.stderr33
8 files changed, 89 insertions, 39 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 42038dbc3d8..80d0faca670 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -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()
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs
new file mode 100644
index 00000000000..5febbbe392b
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.rs
@@ -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
+}
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr
new file mode 100644
index 00000000000..71c4729e310
--- /dev/null
+++ b/tests/ui/mismatched_types/suggest-option-asderef-inference-var.stderr
@@ -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`.
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
index cc9ba5514fe..ac0831ce655 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
+++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.rs
@@ -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
 }
diff --git a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
index 079909eb48d..ecfbd27b180 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
+++ b/tests/ui/mismatched_types/suggest-option-asderef-unfixable.stderr
@@ -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`.
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.fixed b/tests/ui/mismatched_types/suggest-option-asderef.fixed
index 08805999341..5c42ece3c5d 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef.fixed
+++ b/tests/ui/mismatched_types/suggest-option-asderef.fixed
@@ -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
 }
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.rs b/tests/ui/mismatched_types/suggest-option-asderef.rs
index 3cfb2ffa828..a5278b8fb16 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef.rs
+++ b/tests/ui/mismatched_types/suggest-option-asderef.rs
@@ -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
 }
diff --git a/tests/ui/mismatched_types/suggest-option-asderef.stderr b/tests/ui/mismatched_types/suggest-option-asderef.stderr
index 46da19d2bf4..01341603dde 100644
--- a/tests/ui/mismatched_types/suggest-option-asderef.stderr
+++ b/tests/ui/mismatched_types/suggest-option-asderef.stderr
@@ -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`.