Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actually report normalization-based type errors correctly for alias-relate obligations in new solver #126403

Merged
merged 1 commit into from
Jul 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
6 changes: 4 additions & 2 deletions tests/ui/traits/next-solver/async.fail.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/traits/next-solver/async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
15 changes: 14 additions & 1 deletion tests/ui/traits/next-solver/more-object-bound.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Loading