Actually report normalization-based type errors correctly for alias-relate obligations in new solver
This commit is contained in:
parent
49ff3909fb
commit
ecdaff240d
9 changed files with 139 additions and 56 deletions
|
@ -1586,60 +1586,113 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.probe(|_| {
|
self.probe(|_| {
|
||||||
let ocx = ObligationCtxt::new(self);
|
|
||||||
|
|
||||||
// try to find the mismatched types to report the error with.
|
// try to find the mismatched types to report the error with.
|
||||||
//
|
//
|
||||||
// this can fail if the problem was higher-ranked, in which
|
// this can fail if the problem was higher-ranked, in which
|
||||||
// cause I have no idea for a good error message.
|
// cause I have no idea for a good error message.
|
||||||
let bound_predicate = predicate.kind();
|
let bound_predicate = predicate.kind();
|
||||||
let (values, err) = if let ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) =
|
let (values, err) = match bound_predicate.skip_binder() {
|
||||||
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);
|
|
||||||
|
|
||||||
debug!(?obligation.cause, ?obligation.param_env);
|
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!(?normalized_term, data.ty = ?data.term);
|
let is_normalized_term_expected = !matches!(
|
||||||
|
obligation.cause.code().peel_derives(),
|
||||||
|
ObligationCauseCode::WhereClause(..)
|
||||||
|
| ObligationCauseCode::WhereClauseInExpr(..)
|
||||||
|
| ObligationCauseCode::Coercion { .. }
|
||||||
|
);
|
||||||
|
|
||||||
let is_normalized_term_expected = !matches!(
|
let (expected, actual) = if is_normalized_term_expected {
|
||||||
obligation.cause.code().peel_derives(),
|
(normalized_term, data.term)
|
||||||
|ObligationCauseCode::WhereClause(..)| ObligationCauseCode::WhereClauseInExpr(
|
} else {
|
||||||
..
|
(data.term, normalized_term)
|
||||||
) | ObligationCauseCode::Coercion { .. }
|
};
|
||||||
);
|
|
||||||
|
|
||||||
let (expected, actual) = if is_normalized_term_expected {
|
// constrain inference variables a bit more to nested obligations from normalize so
|
||||||
(normalized_term, data.term)
|
// we can have more helpful errors.
|
||||||
} else {
|
//
|
||||||
(data.term, normalized_term)
|
// 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
|
if let Err(new_err) =
|
||||||
// we can have more helpful errors.
|
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
|
||||||
//
|
{
|
||||||
// we intentionally drop errors from normalization here,
|
(
|
||||||
// since the normalization is just done to improve the error message.
|
Some((
|
||||||
let _ = ocx.select_where_possible();
|
data.projection_term,
|
||||||
|
is_normalized_term_expected,
|
||||||
if let Err(new_err) =
|
self.resolve_vars_if_possible(normalized_term),
|
||||||
ocx.eq(&obligation.cause, obligation.param_env, expected, actual)
|
data.term,
|
||||||
{
|
)),
|
||||||
(Some((data, is_normalized_term_expected, normalized_term, data.term)), new_err)
|
new_err,
|
||||||
} else {
|
)
|
||||||
(None, error.err)
|
} else {
|
||||||
|
(None, error.err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
ty::PredicateKind::AliasRelate(lhs, rhs, _) => {
|
||||||
(None, error.err)
|
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 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (None, error.err),
|
||||||
};
|
};
|
||||||
|
|
||||||
let msg = values
|
let msg = values
|
||||||
|
@ -1737,15 +1790,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
|
|
||||||
fn maybe_detailed_projection_msg(
|
fn maybe_detailed_projection_msg(
|
||||||
&self,
|
&self,
|
||||||
pred: ty::ProjectionPredicate<'tcx>,
|
projection_term: ty::AliasTerm<'tcx>,
|
||||||
normalized_ty: ty::Term<'tcx>,
|
normalized_ty: ty::Term<'tcx>,
|
||||||
expected_ty: ty::Term<'tcx>,
|
expected_ty: ty::Term<'tcx>,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let trait_def_id = pred.projection_term.trait_def_id(self.tcx);
|
let trait_def_id = projection_term.trait_def_id(self.tcx);
|
||||||
let self_ty = pred.projection_term.self_ty();
|
let self_ty = projection_term.self_ty();
|
||||||
|
|
||||||
with_forced_trimmed_paths! {
|
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 fn_kind = self_ty.prefix_string(self.tcx);
|
||||||
let item = match self_ty.kind() {
|
let item = match self_ty.kind() {
|
||||||
ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
|
ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
|
||||||
|
|
|
@ -29,7 +29,10 @@ error[E0271]: type mismatch resolving `<SelectInt as Expression>::SqlType == Tex
|
||||||
--> $DIR/as_expression.rs:57:5
|
--> $DIR/as_expression.rs:57:5
|
||||||
|
|
|
|
||||||
LL | SelectInt.check("bar");
|
LL | SelectInt.check("bar");
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^ types differ
|
| ^^^^^^^^^^^^^^^^^^^^^^ expected `Integer`, found `Text`
|
||||||
|
|
|
||||||
|
= note: expected struct `Integer`
|
||||||
|
found struct `Text`
|
||||||
|
|
||||||
error: aborting due to 3 previous errors
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
|
||||||
--> $DIR/issue-100222.rs:34:12
|
--> $DIR/issue-100222.rs:34:12
|
||||||
|
|
|
|
||||||
LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
|
||||||
--> $DIR/issue-100222.rs:25:12
|
--> $DIR/issue-100222.rs:25:12
|
||||||
|
|
|
|
||||||
LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
|
||||||
--> $DIR/issue-100222.rs:34:12
|
--> $DIR/issue-100222.rs:34:12
|
||||||
|
|
|
|
||||||
LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,10 @@ error[E0271]: type mismatch resolving `<() as Index>::Output == &mut <() as Inde
|
||||||
--> $DIR/issue-100222.rs:25:12
|
--> $DIR/issue-100222.rs:25:12
|
||||||
|
|
|
|
||||||
LL | fn foo(&mut self, x: <Self as Index>::Output) -> <Self as Index>::Output
|
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
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
|
|
@ -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
|
--> $DIR/async.rs:12:17
|
||||||
|
|
|
|
||||||
LL | needs_async(async {});
|
LL | needs_async(async {});
|
||||||
| ----------- ^^^^^^^^ types differ
|
| ----------- ^^^^^^^^ expected `()`, found `i32`
|
||||||
| |
|
| |
|
||||||
| required by a bound introduced by this call
|
| required by a bound introduced by this call
|
||||||
|
|
|
|
||||||
|
= note: expected unit type `()`
|
||||||
|
found type `i32`
|
||||||
note: required by a bound in `needs_async`
|
note: required by a bound in `needs_async`
|
||||||
--> $DIR/async.rs:8:31
|
--> $DIR/async.rs:8:31
|
||||||
|
|
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ fn needs_async(_: impl Future<Output = i32>) {}
|
||||||
#[cfg(fail)]
|
#[cfg(fail)]
|
||||||
fn main() {
|
fn main() {
|
||||||
needs_async(async {});
|
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)]
|
#[cfg(pass)]
|
||||||
|
|
|
@ -1,9 +1,22 @@
|
||||||
error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
|
error[E0271]: type mismatch resolving `<dyn Trait<A = A, B = B> as SuperTrait>::A == B`
|
||||||
--> $DIR/more-object-bound.rs:12:5
|
--> $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)
|
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 because it appears within the type `dyn Trait<A = A, B = B>`
|
||||||
note: required by a bound in `foo`
|
note: required by a bound in `foo`
|
||||||
--> $DIR/more-object-bound.rs:18:8
|
--> $DIR/more-object-bound.rs:18:8
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue