Point at associated type for some obligations

This commit is contained in:
Esteban Küber 2019-10-10 16:20:42 -07:00
parent 57bfb80962
commit 58c6591cde
10 changed files with 93 additions and 41 deletions

View File

@ -2199,6 +2199,12 @@ fn note_obligation_cause_code<T>(&self,
);
}
}
ObligationCauseCode::AssocTypeBound(impl_span, orig) => {
err.span_label(orig, "associated type defined here");
if let Some(sp) = impl_span {
err.span_label(sp, "in this `impl` item");
}
}
}
}

View File

@ -268,6 +268,8 @@ pub enum ObligationCauseCode<'tcx> {
/// #[feature(trivial_bounds)] is not enabled
TrivialBound,
AssocTypeBound(/*impl*/ Option<Span>, /*original*/ Span),
}
// `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.

View File

@ -544,6 +544,7 @@ fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
super::MethodReceiver => Some(super::MethodReceiver),
super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)),
super::TrivialBound => Some(super::TrivialBound),
super::AssocTypeBound(impl_sp, sp) => Some(super::AssocTypeBound(impl_sp, sp)),
}
}
}

View File

@ -3139,6 +3139,7 @@ pub fn adjust_ident_and_get_scope(self, mut ident: Ident, scope: DefId, block: h
}
}
#[derive(Clone)]
pub struct AssocItemsIterator<'tcx> {
tcx: TyCtxt<'tcx>,
def_ids: &'tcx [DefId],

View File

@ -22,11 +22,14 @@ pub fn obligations<'a, 'tcx>(
ty: Ty<'tcx>,
span: Span,
) -> Option<Vec<traits::PredicateObligation<'tcx>>> {
let mut wf = WfPredicates { infcx,
param_env,
body_id,
span,
out: vec![] };
let mut wf = WfPredicates {
infcx,
param_env,
body_id,
span,
out: vec![],
item: None,
};
if wf.compute(ty) {
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out);
let result = wf.normalize();
@ -47,8 +50,9 @@ pub fn trait_obligations<'a, 'tcx>(
body_id: hir::HirId,
trait_ref: &ty::TraitRef<'tcx>,
span: Span,
item: Option<&'tcx hir::Item>,
) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item };
wf.compute_trait_ref(trait_ref, Elaborate::All);
wf.normalize()
}
@ -60,7 +64,7 @@ pub fn predicate_obligations<'a, 'tcx>(
predicate: &ty::Predicate<'tcx>,
span: Span,
) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![] };
let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None };
// (*) ok to skip binders, because wf code is prepared for it
match *predicate {
@ -107,6 +111,7 @@ struct WfPredicates<'a, 'tcx> {
body_id: hir::HirId,
span: Span,
out: Vec<traits::PredicateObligation<'tcx>>,
item: Option<&'tcx hir::Item>,
}
/// Controls whether we "elaborate" supertraits and so forth on the WF
@ -157,33 +162,54 @@ fn normalize(&mut self) -> Vec<traits::PredicateObligation<'tcx>> {
.collect()
}
/// Pushes the obligations required for `trait_ref` to be WF into
/// `self.out`.
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elaborate) {
let obligations = self.nominal_obligations(trait_ref.def_id, trait_ref.substs);
let assoc_items = self.infcx.tcx.associated_items(trait_ref.def_id);
let cause = self.cause(traits::MiscObligation);
let param_env = self.param_env;
if let Elaborate::All = elaborate {
let predicates = obligations.iter()
.map(|obligation| obligation.predicate.clone())
.collect();
.map(|obligation| obligation.predicate.clone())
.collect();
let implied_obligations = traits::elaborate_predicates(self.infcx.tcx, predicates);
let item_span: Option<Span> = self.item.map(|i| i.span);
let item = &self.item;
let implied_obligations = implied_obligations.map(|pred| {
traits::Obligation::new(cause.clone(), param_env, pred)
let mut cause = cause.clone();
if let ty::Predicate::Trait(proj) = &pred {
if let (
ty::Projection(ty::ProjectionTy { item_def_id, .. }),
Some(hir::ItemKind::Impl(.., bounds)),
) = (&proj.skip_binder().self_ty().kind, item.map(|i| &i.kind)) {
if let Some((bound, assoc_item)) = assoc_items.clone()
.filter(|i| i.def_id == *item_def_id)
.next()
.and_then(|assoc_item| bounds.iter()
.filter(|b| b.ident == assoc_item.ident)
.next()
.map(|bound| (bound, assoc_item)))
{
cause.span = bound.span;
cause.code = traits::AssocTypeBound(item_span, assoc_item.ident.span);
}
}
}
traits::Obligation::new(cause, param_env, pred)
});
self.out.extend(implied_obligations);
}
self.out.extend(obligations);
self.out.extend(
trait_ref.substs.types()
.filter(|ty| !ty.has_escaping_bound_vars())
.map(|ty| traits::Obligation::new(cause.clone(),
param_env,
ty::Predicate::WellFormed(ty))));
self.out.extend(trait_ref.substs.types()
.filter(|ty| !ty.has_escaping_bound_vars())
.map(|ty| traits::Obligation::new(
cause.clone(),
param_env,
ty::Predicate::WellFormed(ty),
)));
}
/// Pushes the obligations required for `trait_ref::Item` to be WF

View File

@ -430,7 +430,7 @@ fn check_item_type(
fn check_impl<'tcx>(
tcx: TyCtxt<'tcx>,
item: &hir::Item,
item: &'tcx hir::Item,
ast_self_ty: &hir::Ty,
ast_trait_ref: &Option<hir::TraitRef>,
) {
@ -445,15 +445,18 @@ fn check_impl<'tcx>(
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
let trait_ref = fcx.tcx.impl_trait_ref(item_def_id).unwrap();
let trait_ref =
fcx.normalize_associated_types_in(
ast_trait_ref.path.span, &trait_ref);
let obligations =
ty::wf::trait_obligations(fcx,
fcx.param_env,
fcx.body_id,
&trait_ref,
ast_trait_ref.path.span);
let trait_ref = fcx.normalize_associated_types_in(
ast_trait_ref.path.span,
&trait_ref,
);
let obligations = ty::wf::trait_obligations(
fcx,
fcx.param_env,
fcx.body_id,
&trait_ref,
ast_trait_ref.path.span,
Some(item),
);
for obligation in obligations {
fcx.register_predicate(obligation);
}

View File

@ -10,8 +10,8 @@ impl<T> Partial<T> for T::Assoc where
{
}
impl<T> Complete for T { //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied
type Assoc = T;
impl<T> Complete for T {
type Assoc = T; //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied
}
fn main() {}

View File

@ -1,10 +1,17 @@
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
--> $DIR/issue-43784-associated-type.rs:13:9
--> $DIR/issue-43784-associated-type.rs:14:5
|
LL | impl<T> Complete for T {
| - ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
| |
| help: consider restricting this bound: `T: std::marker::Copy`
LL | type Assoc: Partial<Self>;
| ----- associated type defined here
...
LL | / impl<T> Complete for T {
| | - help: consider restricting this bound: `T: std::marker::Copy`
LL | | type Assoc = T;
| | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
LL | | }
| |_- in this `impl` item
|
= help: consider adding a `where T: std::marker::Copy` bound
error: aborting due to previous error

View File

@ -27,8 +27,8 @@ struct SalsaStorage {
_parse: <ParseQuery as Query<RootDatabase>>::Data, //~ ERROR overflow
}
impl Database for RootDatabase { //~ ERROR overflow
type Storage = SalsaStorage;
impl Database for RootDatabase {
type Storage = SalsaStorage; //~ ERROR overflow
}
impl HasQueryGroup for RootDatabase {}
impl<DB> Query<DB> for ParseQuery

View File

@ -7,10 +7,16 @@ LL | _parse: <ParseQuery as Query<RootDatabase>>::Data,
= note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
error[E0275]: overflow evaluating the requirement `RootDatabase: SourceDatabase`
--> $DIR/cycle-cache-err-60010.rs:30:6
--> $DIR/cycle-cache-err-60010.rs:31:5
|
LL | impl Database for RootDatabase {
| ^^^^^^^^
LL | type Storage;
| ------- associated type defined here
...
LL | / impl Database for RootDatabase {
LL | | type Storage = SalsaStorage;
| | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL | | }
| |_- in this `impl` item
|
= note: required because of the requirements on the impl of `Query<RootDatabase>` for `ParseQuery`
= note: required because it appears within the type `SalsaStorage`