about summary refs log tree commit diff
diff options
context:
space:
mode:
-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`.