about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs36
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr4
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr26
-rw-r--r--tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs5
-rw-r--r--tests/ui/mismatched_types/closure-mismatch.current.stderr (renamed from tests/ui/mismatched_types/closure-mismatch.stderr)8
-rw-r--r--tests/ui/mismatched_types/closure-mismatch.next.stderr67
-rw-r--r--tests/ui/mismatched_types/closure-mismatch.rs14
7 files changed, 122 insertions, 38 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index 3a939df25e0..9cbe4147fb4 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -291,6 +291,34 @@ impl<'tcx> BestObligation<'tcx> {
         }
     }
 
+    /// When a higher-ranked projection goal fails, check that the corresponding
+    /// higher-ranked trait goal holds or not. This is because the process of
+    /// instantiating and then re-canonicalizing the binder of the projection goal
+    /// forces us to be unable to see that the leak check failed in the nested
+    /// `NormalizesTo` goal, so we don't fall back to the rigid projection check
+    /// that should catch when a projection goal fails due to an unsatisfied trait
+    /// goal.
+    fn detect_error_in_higher_ranked_projection(
+        &mut self,
+        goal: &inspect::InspectGoal<'_, 'tcx>,
+    ) -> ControlFlow<PredicateObligation<'tcx>> {
+        let tcx = goal.infcx().tcx;
+        if let Some(projection_clause) = goal.goal().predicate.as_projection_clause()
+            && !projection_clause.bound_vars().is_empty()
+        {
+            let pred = projection_clause.map_bound(|proj| proj.projection_term.trait_ref(tcx));
+            self.with_derived_obligation(self.obligation.with(tcx, pred), |this| {
+                goal.infcx().visit_proof_tree_at_depth(
+                    goal.goal().with(tcx, pred),
+                    goal.depth() + 1,
+                    this,
+                )
+            })
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
     /// It is likely that `NormalizesTo` failed without any applicable candidates
     /// because the alias is not well-formed.
     ///
@@ -374,7 +402,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             source: CandidateSource::Impl(impl_def_id),
             result: _,
         } = candidate.kind()
-            && goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
+            && tcx.do_not_recommend_impl(impl_def_id)
         {
             trace!("#[do_not_recommend] -> exit");
             return ControlFlow::Break(self.obligation.clone());
@@ -486,7 +514,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             if let Some(obligation) = goal
                 .infcx()
                 .visit_proof_tree_at_depth(
-                    goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(lhs.into())),
+                    goal.goal().with(tcx, ty::ClauseKind::WellFormed(lhs.into())),
                     goal.depth() + 1,
                     self,
                 )
@@ -496,7 +524,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             } else if let Some(obligation) = goal
                 .infcx()
                 .visit_proof_tree_at_depth(
-                    goal.goal().with(goal.infcx().tcx, ty::ClauseKind::WellFormed(rhs.into())),
+                    goal.goal().with(tcx, ty::ClauseKind::WellFormed(rhs.into())),
                     goal.depth() + 1,
                     self,
                 )
@@ -506,6 +534,8 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
             }
         }
 
+        self.detect_error_in_higher_ranked_projection(goal)?;
+
         ControlFlow::Break(self.obligation.clone())
     }
 }
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr
index 7b9fd6bb4c5..c8394575e71 100644
--- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.current.stderr
@@ -13,7 +13,7 @@ LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
    |                                          ^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
-  --> $DIR/candidate-from-env-universe-err-project.rs:53:30
+  --> $DIR/candidate-from-env-universe-err-project.rs:52:30
    |
 LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
@@ -22,7 +22,7 @@ LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
               found associated type `<T as Trait<'a>>::Assoc`
 
 error[E0308]: mismatched types
-  --> $DIR/candidate-from-env-universe-err-project.rs:53:30
+  --> $DIR/candidate-from-env-universe-err-project.rs:52:30
    |
 LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr
index 6e0ec5620da..468dc3b082e 100644
--- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr
@@ -22,38 +22,20 @@ note: required by a bound in `projection_bound`
 LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
    |                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `projection_bound`
 
-error[E0271]: type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
-  --> $DIR/candidate-from-env-universe-err-project.rs:38:24
-   |
-LL |     projection_bound::<T>();
-   |                        ^ type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
-   |
-note: types differ
-  --> $DIR/candidate-from-env-universe-err-project.rs:14:18
-   |
-LL |     type Assoc = usize;
-   |                  ^^^^^
-note: required by a bound in `projection_bound`
-  --> $DIR/candidate-from-env-universe-err-project.rs:18:42
-   |
-LL | fn projection_bound<T: for<'a> Trait<'a, Assoc = usize>>() {}
-   |                                          ^^^^^^^^^^^^^ required by this bound in `projection_bound`
-
 error: higher-ranked subtype error
-  --> $DIR/candidate-from-env-universe-err-project.rs:53:30
+  --> $DIR/candidate-from-env-universe-err-project.rs:52:30
    |
 LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: higher-ranked subtype error
-  --> $DIR/candidate-from-env-universe-err-project.rs:53:30
+  --> $DIR/candidate-from-env-universe-err-project.rs:52:30
    |
 LL |     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
index a77d87f6fa7..d70e3922382 100644
--- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
@@ -36,9 +36,8 @@ fn function2<T: Trait<'static, Assoc = usize>>() {
     // does not use the leak check when trying the where-bound, causing us
     // to prefer it over the impl, resulting in a placeholder error.
     projection_bound::<T>();
-    //[next]~^ ERROR type mismatch resolving `<T as Trait<'a>>::Assoc == usize`
-    //[next]~| ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
-    //[current]~^^^ ERROR mismatched types
+    //[next]~^ ERROR the trait bound `for<'a> T: Trait<'a>` is not satisfied
+    //[current]~^^ ERROR mismatched types
 }
 
 fn function3<T: Trait<'static, Assoc = usize>>() {
diff --git a/tests/ui/mismatched_types/closure-mismatch.stderr b/tests/ui/mismatched_types/closure-mismatch.current.stderr
index 802110c6511..378fe83ea89 100644
--- a/tests/ui/mismatched_types/closure-mismatch.stderr
+++ b/tests/ui/mismatched_types/closure-mismatch.current.stderr
@@ -1,5 +1,5 @@
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/closure-mismatch.rs:8:5
+  --> $DIR/closure-mismatch.rs:12:5
    |
 LL |     baz(|_| ());
    |     ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@@ -8,7 +8,7 @@ LL |     baz(|_| ());
    = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
 
 error: implementation of `Fn` is not general enough
-  --> $DIR/closure-mismatch.rs:8:5
+  --> $DIR/closure-mismatch.rs:12:5
    |
 LL |     baz(|_| ());
    |     ^^^^^^^^^^^ implementation of `Fn` is not general enough
@@ -17,7 +17,7 @@ LL |     baz(|_| ());
    = note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2`
 
 error: implementation of `FnOnce` is not general enough
-  --> $DIR/closure-mismatch.rs:11:5
+  --> $DIR/closure-mismatch.rs:16:5
    |
 LL |     baz(|x| ());
    |     ^^^^^^^^^^^ implementation of `FnOnce` is not general enough
@@ -26,7 +26,7 @@ LL |     baz(|x| ());
    = note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`
 
 error: implementation of `Fn` is not general enough
-  --> $DIR/closure-mismatch.rs:11:5
+  --> $DIR/closure-mismatch.rs:16:5
    |
 LL |     baz(|x| ());
    |     ^^^^^^^^^^^ implementation of `Fn` is not general enough
diff --git a/tests/ui/mismatched_types/closure-mismatch.next.stderr b/tests/ui/mismatched_types/closure-mismatch.next.stderr
new file mode 100644
index 00000000000..6b4620aa8d1
--- /dev/null
+++ b/tests/ui/mismatched_types/closure-mismatch.next.stderr
@@ -0,0 +1,67 @@
+error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}: Foo` is not satisfied
+  --> $DIR/closure-mismatch.rs:12:9
+   |
+LL |     baz(|_| ());
+   |     --- ^^^^^^ unsatisfied trait bound
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}`
+   = note: expected a closure with signature `for<'a> fn(&'a ())`
+              found a closure with signature `fn(&())`
+note: this is a known limitation of the trait solver that will be lifted in the future
+  --> $DIR/closure-mismatch.rs:12:9
+   |
+LL |     baz(|_| ());
+   |     ----^^^----
+   |     |   |
+   |     |   the trait solver is unable to infer the generic types that should be inferred from this argument
+   |     add turbofish arguments to this call to specify the types manually, even if it's redundant
+note: required for `{closure@$DIR/closure-mismatch.rs:12:9: 12:12}` to implement `Foo`
+  --> $DIR/closure-mismatch.rs:7:18
+   |
+LL | impl<T: Fn(&())> Foo for T {}
+   |         -------  ^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `baz`
+  --> $DIR/closure-mismatch.rs:9:11
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   |           ^^^ required by this bound in `baz`
+
+error[E0277]: the trait bound `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}: Foo` is not satisfied
+  --> $DIR/closure-mismatch.rs:16:9
+   |
+LL |     baz(|x| ());
+   |     --- ^^^^^^ unsatisfied trait bound
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `for<'a> FnOnce(&'a ())` is not implemented for closure `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}`
+   = note: expected a closure with signature `for<'a> fn(&'a ())`
+              found a closure with signature `fn(&())`
+note: this is a known limitation of the trait solver that will be lifted in the future
+  --> $DIR/closure-mismatch.rs:16:9
+   |
+LL |     baz(|x| ());
+   |     ----^^^----
+   |     |   |
+   |     |   the trait solver is unable to infer the generic types that should be inferred from this argument
+   |     add turbofish arguments to this call to specify the types manually, even if it's redundant
+note: required for `{closure@$DIR/closure-mismatch.rs:16:9: 16:12}` to implement `Foo`
+  --> $DIR/closure-mismatch.rs:7:18
+   |
+LL | impl<T: Fn(&())> Foo for T {}
+   |         -------  ^^^     ^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required by a bound in `baz`
+  --> $DIR/closure-mismatch.rs:9:11
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   |           ^^^ required by this bound in `baz`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/mismatched_types/closure-mismatch.rs b/tests/ui/mismatched_types/closure-mismatch.rs
index efaed4dc1b9..1a24c760a6a 100644
--- a/tests/ui/mismatched_types/closure-mismatch.rs
+++ b/tests/ui/mismatched_types/closure-mismatch.rs
@@ -1,3 +1,7 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 trait Foo {}
 
 impl<T: Fn(&())> Foo for T {}
@@ -6,9 +10,11 @@ fn baz<T: Foo>(_: T) {}
 
 fn main() {
     baz(|_| ());
-    //~^ ERROR implementation of `FnOnce` is not general enough
-    //~| ERROR implementation of `Fn` is not general enough
+    //[current]~^ ERROR implementation of `FnOnce` is not general enough
+    //[current]~| ERROR implementation of `Fn` is not general enough
+    //[next]~^^^ ERROR Foo` is not satisfied
     baz(|x| ());
-    //~^ ERROR implementation of `FnOnce` is not general enough
-    //~| ERROR implementation of `Fn` is not general enough
+    //[current]~^ ERROR implementation of `FnOnce` is not general enough
+    //[current]~| ERROR implementation of `Fn` is not general enough
+    //[next]~^^^ ERROR Foo` is not satisfied
 }