Slightly improve mismatched GAT where clause error

This commit is contained in:
Michael Goulet 2022-07-16 23:41:43 +00:00
parent c32dcbba18
commit 6bb7581a59
8 changed files with 62 additions and 90 deletions

View file

@ -2,17 +2,17 @@
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, Subtype};
use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
use crate::infer::Subtype;
use crate::traits::ObligationCauseCode::{CompareImplMethodObligation, CompareImplTypeObligation};
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::print::RegionHighlightMode;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::{Span, Symbol};
use rustc_span::Span;
use std::ops::ControlFlow;
@ -22,38 +22,23 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
let error = self.error.as_ref()?;
debug!("try_report_impl_not_conforming_to_trait {:?}", error);
if let RegionResolutionError::SubSupConflict(
_, var_origin, sub_origin, _sub, sup_origin, _sup, _,
_,
var_origin,
sub_origin,
_sub,
sup_origin,
_sup,
_,
) = error.clone()
&& let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin)
&& let (
sub_expected_found @ Some((sub_expected, sub_found)),
sup_expected_found @ Some(_),
CompareImplMethodObligation { trait_item_def_id, .. },
) = (sub_trace.values.ty(), sup_trace.values.ty(), sub_trace.cause.code())
&& let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
&& let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
&& let sup_expected_found @ Some(_) = sup_trace.values.ty()
&& let CompareImplMethodObligation { trait_item_def_id, .. }
| CompareImplTypeObligation { trait_item_def_id, .. } = sub_trace.cause.code()
&& sup_expected_found == sub_expected_found
{
let guar = self.emit_err(
var_origin.span(),
sub_expected,
sub_found,
*trait_item_def_id,
);
return Some(guar);
}
if let RegionResolutionError::ConcreteFailure(origin, _, _)
| RegionResolutionError::GenericBoundFailure(origin, _, _) = error.clone()
&& let SubregionOrigin::CompareImplTypeObligation {
span,
impl_item_def_id,
trait_item_def_id,
} = origin
{
let guar = self.emit_associated_type_err(
span,
self.infcx.tcx.item_name(impl_item_def_id.to_def_id()),
impl_item_def_id,
trait_item_def_id,
);
let guar =
self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
return Some(guar);
}
None
@ -147,25 +132,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
}
err.emit()
}
fn emit_associated_type_err(
&self,
span: Span,
item_name: Symbol,
impl_item_def_id: LocalDefId,
trait_item_def_id: DefId,
) -> ErrorGuaranteed {
let impl_sp = self.tcx().def_span(impl_item_def_id);
let trait_sp = self.tcx().def_span(trait_item_def_id);
let mut err = self
.tcx()
.sess
.struct_span_err(span, &format!("`impl` associated type signature for `{}` doesn't match `trait` associated type signature", item_name));
err.span_label(impl_sp, "found");
err.span_label(trait_sp, "expected");
err.emit()
}
}
struct TypeParamSpanVisitor<'tcx> {

View file

@ -1212,15 +1212,6 @@ fn compare_type_predicate_entailment<'tcx>(
// `ObligationCause` (and the `FnCtxt`). This is what
// `regionck_item` expects.
let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
let cause = ObligationCause::new(
impl_ty_span,
impl_ty_hir_id,
ObligationCauseCode::CompareImplTypeObligation {
impl_item_def_id: impl_ty.def_id.expect_local(),
trait_item_def_id: trait_ty.def_id,
},
);
debug!("compare_type_predicate_entailment: trait_to_impl_substs={:?}", trait_to_impl_substs);
// The predicates declared by the impl definition, the trait and the
@ -1239,7 +1230,7 @@ fn compare_type_predicate_entailment<'tcx>(
Reveal::UserFacing,
hir::Constness::NotConst,
);
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause.clone());
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
tcx.infer_ctxt().enter(|infcx| {
let ocx = ObligationCtxt::new(&infcx);
@ -1247,12 +1238,24 @@ fn compare_type_predicate_entailment<'tcx>(
let mut selcx = traits::SelectionContext::new(&infcx);
for predicate in impl_ty_own_bounds.predicates {
assert_eq!(impl_ty_own_bounds.predicates.len(), impl_ty_own_bounds.spans.len());
for (span, predicate) in
std::iter::zip(impl_ty_own_bounds.spans, impl_ty_own_bounds.predicates)
{
let cause = ObligationCause::misc(span, impl_ty_hir_id);
let traits::Normalized { value: predicate, obligations } =
traits::normalize(&mut selcx, param_env, normalize_cause.clone(), predicate);
traits::normalize(&mut selcx, param_env, cause, predicate);
let cause = ObligationCause::new(
span,
impl_ty_hir_id,
ObligationCauseCode::CompareImplTypeObligation {
impl_item_def_id: impl_ty.def_id.expect_local(),
trait_item_def_id: trait_ty.def_id,
},
);
ocx.register_obligations(obligations);
ocx.register_obligation(traits::Obligation::new(cause.clone(), param_env, predicate));
ocx.register_obligation(traits::Obligation::new(cause, param_env, predicate));
}
// Check that all obligations are satisfied by the implementation's

View file

@ -11,13 +11,13 @@ LL | type Assoc2<T: std::fmt::Display> = Vec<T>;
| +++++++++++++++++++
error[E0276]: impl has stricter requirements than trait
--> $DIR/generic-associated-types-where.rs:22:5
--> $DIR/generic-associated-types-where.rs:22:38
|
LL | type Assoc3<T>;
| -------------- definition of `Assoc3` from trait
...
LL | type Assoc3<T> = Vec<T> where T: Iterator;
| ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
| ^^^^^^^^ impl has extra requirement `T: Iterator`
error: aborting due to 2 previous errors

View file

@ -13,9 +13,9 @@ struct Fooy<T>(T);
impl<T> Foo for Fooy<T> {
type A<'a> = (&'a ()) where Self: 'static;
//~^ ERROR `impl` associated type
//~^ ERROR the parameter type `T` may not live long enoug
type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
//~^ ERROR `impl` associated type
//~^ ERROR impl has stricter requirements than trait
//~| ERROR lifetime bound not satisfied
type C = String where Self: Copy;
//~^ ERROR the trait bound `T: Copy` is not satisfied

View file

@ -1,20 +1,22 @@
error: `impl` associated type signature for `A` doesn't match `trait` associated type signature
--> $DIR/impl_bounds.rs:15:5
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/impl_bounds.rs:15:39
|
LL | type A<'a> where Self: 'a;
| ---------- expected
...
LL | type A<'a> = (&'a ()) where Self: 'static;
| ^^^^^^^^^^ found
| ^^^^^^^ ...so that the definition in impl matches the definition from the trait
|
help: consider adding an explicit lifetime bound...
|
LL | impl<T: 'static> Foo for Fooy<T> {
| +++++++++
error: `impl` associated type signature for `B` doesn't match `trait` associated type signature
--> $DIR/impl_bounds.rs:17:5
error[E0276]: impl has stricter requirements than trait
--> $DIR/impl_bounds.rs:17:48
|
LL | type B<'a, 'b> where 'a: 'b;
| -------------- expected
| -------------- definition of `B` from trait
...
LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
| ^^^^^^^^^^^^^^ found
| ^^ impl has extra requirement `'b: 'a`
error[E0478]: lifetime bound not satisfied
--> $DIR/impl_bounds.rs:17:22
@ -37,10 +39,10 @@ LL | type B<'a, 'b> = (&'a(), &'b ()) where 'b: 'a;
| ^^
error[E0277]: the trait bound `T: Copy` is not satisfied
--> $DIR/impl_bounds.rs:20:5
--> $DIR/impl_bounds.rs:20:33
|
LL | type C = String where Self: Copy;
| ^^^^^^ the trait `Copy` is not implemented for `T`
| ^^^^ the trait `Copy` is not implemented for `T`
|
note: required because of the requirements on the impl of `Copy` for `Fooy<T>`
--> $DIR/impl_bounds.rs:11:10
@ -88,5 +90,5 @@ LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
error: aborting due to 5 previous errors
Some errors have detailed explanations: E0277, E0478.
For more information about an error, try `rustc --explain E0277`.
Some errors have detailed explanations: E0276, E0277, E0310, E0478.
For more information about an error, try `rustc --explain E0276`.

View file

@ -1,11 +1,11 @@
error[E0276]: impl has stricter requirements than trait
--> $DIR/issue-47206-where-clause.rs:12:5
--> $DIR/issue-47206-where-clause.rs:12:38
|
LL | type Assoc3<T>;
| -------------- definition of `Assoc3` from trait
...
LL | type Assoc3<T> = Vec<T> where T: Iterator;
| ^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator`
| ^^^^^^^^ impl has extra requirement `T: Iterator`
error: aborting due to previous error

View file

@ -7,7 +7,7 @@ trait Foo {
}
impl Foo for () {
type Assoc<'a, 'b> = () where 'a: 'b;
//~^ `impl` associated type
//~^ impl has stricter requirements than trait
}
fn main() {}

View file

@ -1,11 +1,12 @@
error: `impl` associated type signature for `Assoc` doesn't match `trait` associated type signature
--> $DIR/missing-where-clause-on-trait.rs:9:5
error[E0276]: impl has stricter requirements than trait
--> $DIR/missing-where-clause-on-trait.rs:9:39
|
LL | type Assoc<'a, 'b>;
| ------------------ expected
| ------------------ definition of `Assoc` from trait
...
LL | type Assoc<'a, 'b> = () where 'a: 'b;
| ^^^^^^^^^^^^^^^^^^ found
| ^^ impl has extra requirement `'a: 'b`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0276`.