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 d3096cf4b52ce..5fb0dd08beb30 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<'tcx> TypeErrCtxt<'_, '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<'tcx> TypeErrCtxt<'_, '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 { - 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 d189d2dbdedc8..a686b913c55ef 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 `::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/traits/next-solver/async.fail.stderr b/tests/ui/traits/next-solver/async.fail.stderr index 83d520341bcc3..e47da338736f4 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 129e4cfaa028b..7f18b3ef915c5 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) {} #[cfg(fail)] fn main() { needs_async(async {}); - //[fail]~^ ERROR type mismatch + //[fail]~^ ERROR expected `{async block@$DIR/async.rs:12:17: 12:25}` 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 8cc2a51ee2b6c..043cbdff9ab9d 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 ` as SuperTrait>::A == B` --> $DIR/more-object-bound.rs:12:5 | +LL | fn transmute(x: A) -> B { + | - - + | | | + | | expected type parameter + | | found type parameter + | found type parameter + | expected type parameter LL | foo::>(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` note: required by a bound in `foo` --> $DIR/more-object-bound.rs:18:8