about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-06-12 11:53:52 -0400
committerMichael Goulet <michael@errs.io>2024-07-02 16:39:57 -0400
commitecdaff240da6938473d14f784f8ba9a8c5f3611b (patch)
tree8fd0a0095443d88abb7333e2b627677549e55df0
parent49ff3909fbd499218a28a31d3a33e88365496a55 (diff)
downloadrust-ecdaff240da6938473d14f784f8ba9a8c5f3611b.tar.gz
rust-ecdaff240da6938473d14f784f8ba9a8c5f3611b.zip
Actually report normalization-based type errors correctly for alias-relate obligations in new solver
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs149
-rw-r--r--tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr5
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr5
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr5
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr5
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr5
-rw-r--r--tests/ui/traits/next-solver/async.fail.stderr6
-rw-r--r--tests/ui/traits/next-solver/async.rs2
-rw-r--r--tests/ui/traits/next-solver/more-object-bound.stderr15
9 files changed, 140 insertions, 57 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index adf1076a7c9..ff263eaac34 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -1586,60 +1586,113 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
 
         self.probe(|_| {
-            let ocx = ObligationCtxt::new(self);
-
             // try to find the mismatched types to report the error with.
             //
             // this can fail if the problem was higher-ranked, in which
             // cause I have no idea for a good error message.
             let bound_predicate = predicate.kind();
-            let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
-                bound_predicate.skip_binder()
-            {
-                let data = self.instantiate_binder_with_fresh_vars(
-                    obligation.cause.span,
-                    infer::BoundRegionConversionTime::HigherRankedType,
-                    bound_predicate.rebind(data),
-                );
-                let unnormalized_term = data.projection_term.to_term(self.tcx);
-                // FIXME(-Znext-solver): For diagnostic purposes, it would be nice
-                // to deeply normalize this type.
-                let normalized_term =
-                    ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
-
-                debug!(?obligation.cause, ?obligation.param_env);
-
-                debug!(?normalized_term, data.ty = ?data.term);
+            let (values, err) = match bound_predicate.skip_binder() {
+                ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
+                    let ocx = ObligationCtxt::new(self);
+
+                    let data = self.instantiate_binder_with_fresh_vars(
+                        obligation.cause.span,
+                        infer::BoundRegionConversionTime::HigherRankedType,
+                        bound_predicate.rebind(data),
+                    );
+                    let unnormalized_term = data.projection_term.to_term(self.tcx);
+                    // FIXME(-Znext-solver): For diagnostic purposes, it would be nice
+                    // to deeply normalize this type.
+                    let normalized_term =
+                        ocx.normalize(&obligation.cause, obligation.param_env, unnormalized_term);
+
+                    let is_normalized_term_expected = !matches!(
+                        obligation.cause.code().peel_derives(),
+                        ObligationCauseCode::WhereClause(..)
+                            | ObligationCauseCode::WhereClauseInExpr(..)
+                            | ObligationCauseCode::Coercion { .. }
+                    );
 
-                let is_normalized_term_expected = !matches!(
-                    obligation.cause.code().peel_derives(),
-                    |ObligationCauseCode::WhereClause(..)| ObligationCauseCode::WhereClauseInExpr(
-                        ..
-                    ) | ObligationCauseCode::Coercion { .. }
-                );
+                    let (expected, actual) = if is_normalized_term_expected {
+                        (normalized_term, data.term)
+                    } else {
+                        (data.term, normalized_term)
+                    };
 
-                let (expected, actual) = if is_normalized_term_expected {
-                    (normalized_term, data.term)
-                } else {
-                    (data.term, normalized_term)
-                };
+                    // constrain inference variables a bit more to nested obligations from normalize so
+                    // we can have more helpful errors.
+                    //
+                    // we intentionally drop errors from normalization here,
+                    // since the normalization is just done to improve the error message.
+                    let _ = ocx.select_where_possible();
 
-                // constrain inference variables a bit more to nested obligations from normalize so
-                // we can have more helpful errors.
-                //
-                // we intentionally drop errors from normalization here,
-                // since the normalization is just done to improve the error message.
-                let _ = ocx.select_where_possible();
+                    if let Err(new_err) =
+                        ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
+                    {
+                        (
+                            Some((
+                                data.projection_term,
+                                is_normalized_term_expected,
+                                self.resolve_vars_if_possible(normalized_term),
+                                data.term,
+                            )),
+                            new_err,
+                        )
+                    } else {
+                        (None, error.err)
+                    }
+                }
+                ty::PredicateKind::AliasRelate(lhs, rhs, _) => {
+                    let derive_better_type_error =
+                        |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| {
+                            let ocx = ObligationCtxt::new(self);
+                            let normalized_term = match expected_term.unpack() {
+                                ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(),
+                                ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(),
+                            };
+                            ocx.register_obligation(Obligation::new(
+                                self.tcx,
+                                ObligationCause::dummy(),
+                                obligation.param_env,
+                                ty::PredicateKind::NormalizesTo(ty::NormalizesTo {
+                                    alias: alias_term,
+                                    term: normalized_term,
+                                }),
+                            ));
+                            let _ = ocx.select_where_possible();
+                            if let Err(terr) = ocx.eq(
+                                &ObligationCause::dummy(),
+                                obligation.param_env,
+                                expected_term,
+                                normalized_term,
+                            ) {
+                                Some((terr, self.resolve_vars_if_possible(normalized_term)))
+                            } else {
+                                None
+                            }
+                        };
 
-                if let Err(new_err) =
-                    ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
-                {
-                    (Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
-                } else {
-                    (None, error.err)
+                    if let Some(lhs) = lhs.to_alias_term()
+                        && let Some((better_type_err, expected_term)) =
+                            derive_better_type_error(lhs, rhs)
+                    {
+                        (
+                            Some((lhs, true, self.resolve_vars_if_possible(expected_term), rhs)),
+                            better_type_err,
+                        )
+                    } else if let Some(rhs) = rhs.to_alias_term()
+                        && let Some((better_type_err, expected_term)) =
+                            derive_better_type_error(rhs, lhs)
+                    {
+                        (
+                            Some((rhs, true, self.resolve_vars_if_possible(expected_term), lhs)),
+                            better_type_err,
+                        )
+                    } else {
+                        (None, error.err)
+                    }
                 }
-            } else {
-                (None, error.err)
+                _ => (None, error.err),
             };
 
             let msg = values
@@ -1737,15 +1790,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
     fn maybe_detailed_projection_msg(
         &self,
-        pred: ty::ProjectionPredicate<'tcx>,
+        projection_term: ty::AliasTerm<'tcx>,
         normalized_ty: ty::Term<'tcx>,
         expected_ty: ty::Term<'tcx>,
     ) -> Option<String> {
-        let trait_def_id = pred.projection_term.trait_def_id(self.tcx);
-        let self_ty = pred.projection_term.self_ty();
+        let trait_def_id = projection_term.trait_def_id(self.tcx);
+        let self_ty = projection_term.self_ty();
 
         with_forced_trimmed_paths! {
-            if self.tcx.is_lang_item(pred.projection_term.def_id,LangItem::FnOnceOutput) {
+            if self.tcx.is_lang_item(projection_term.def_id, LangItem::FnOnceOutput) {
                 let fn_kind = self_ty.prefix_string(self.tcx);
                 let item = match self_ty.kind() {
                     ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
index d189d2dbded..a686b913c55 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
@@ -29,7 +29,10 @@ error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Tex
   --> $DIR/as_expression.rs:57:5
    |
 LL |     SelectInt.check("bar");
-   |     ^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     ^^^^^^^^^^^^^^^^^^^^^^ expected `Integer`, found `Text`
+   |
+   = note: expected struct `Integer`
+              found struct `Text`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr
index 4a949e90d85..03536dca1e8 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.nn.stderr
@@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
   --> $DIR/issue-100222.rs:34:12
    |
 LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
+   |            ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output`
+   |
+   = note:      expected unit type `()`
+           found mutable reference `&mut <() as Index>::Output`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr
index 1bfce48d26a..6a70a503606 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.ny.stderr
@@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
   --> $DIR/issue-100222.rs:25:12
    |
 LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
+   |            ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output`
+   |
+   = note:      expected unit type `()`
+           found mutable reference `&mut <() as Index>::Output`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr
index 4a949e90d85..03536dca1e8 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yn.stderr
@@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
   --> $DIR/issue-100222.rs:34:12
    |
 LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
+   |            ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output`
+   |
+   = note:      expected unit type `()`
+           found mutable reference `&mut <() as Index>::Output`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr
index 1bfce48d26a..6a70a503606 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/issue-100222.yy.stderr
@@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
   --> $DIR/issue-100222.rs:25:12
    |
 LL |     fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
-   |            ^^^^^^^^^ types differ
+   |            ^^^^^^^^^ expected `()`, found `&mut <() as Index>::Output`
+   |
+   = note:      expected unit type `()`
+           found mutable reference `&mut <() as Index>::Output`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr
index 83d520341bc..e47da338736 100644
--- a/tests/ui/traits/next-solver/async.fail.stderr
+++ b/tests/ui/traits/next-solver/async.fail.stderr
@@ -1,11 +1,13 @@
-error[E0271]: type mismatch resolving `<{async block@$DIR/async.rs:12:17: 12:22} as Future>::Output == i32`
+error[E0271]: expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
   --> $DIR/async.rs:12:17
    |
 LL |     needs_async(async {});
-   |     ----------- ^^^^^^^^ types differ
+   |     ----------- ^^^^^^^^ expected `()`, found `i32`
    |     |
    |     required by a bound introduced by this call
    |
+   = note: expected unit type `()`
+                   found type `i32`
 note: required by a bound in `needs_async`
   --> $DIR/async.rs:8:31
    |
diff --git a/tests/ui/traits/next-solver/async.rs b/tests/ui/traits/next-solver/async.rs
index 129e4cfaa02..fded7743547 100644
--- a/tests/ui/traits/next-solver/async.rs
+++ b/tests/ui/traits/next-solver/async.rs
@@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
 #[cfg(fail)]
 fn main() {
     needs_async(async {});
-    //[fail]~^ ERROR type mismatch
+    //[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:22}` to be a future that resolves to `i32`, but it resolves to `()`
 }
 
 #[cfg(pass)]
diff --git a/tests/ui/traits/next-solver/more-object-bound.stderr b/tests/ui/traits/next-solver/more-object-bound.stderr
index 8cc2a51ee2b..043cbdff9ab 100644
--- a/tests/ui/traits/next-solver/more-object-bound.stderr
+++ b/tests/ui/traits/next-solver/more-object-bound.stderr
@@ -1,9 +1,22 @@
 error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
   --> $DIR/more-object-bound.rs:12:5
    |
+LL | fn transmute<A, B>(x: A) -> B {
+   |              -  -
+   |              |  |
+   |              |  expected type parameter
+   |              |  found type parameter
+   |              found type parameter
+   |              expected type parameter
 LL |     foo::<A, B, dyn Trait<A = A, B = B>>(x)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `A`, found type parameter `B`
    |
+   = note: expected type parameter `A`
+              found type parameter `B`
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+   = note: a type parameter was expected, but a different one was found; you might be missing a type parameter or trait bound
+   = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
    = note: required because it appears within the type `dyn Trait<A = A, B = B>`
 note: required by a bound in `foo`
   --> $DIR/more-object-bound.rs:18:8