diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index e36307feddb..dc279aae32c 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -11,6 +11,7 @@ //! Code for projecting associated types out of trait references. use super::elaborate_predicates; +use super::get_impl_item_or_default; use super::report_overflow_error; use super::Obligation; use super::ObligationCause; @@ -23,8 +24,9 @@ use super::util; use middle::infer::{self, TypeOrigin}; use middle::subst::Subst; -use middle::ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; +use middle::ty::{self, ToPredicate, RegionEscape, HasTypeFlags, ToPolyTraitRef, Ty, TyCtxt}; use middle::ty::fold::{TypeFoldable, TypeFolder}; +use rustc_front::hir; use syntax::parse::token; use util::common::FN_OUTPUT_NAME; @@ -742,6 +744,28 @@ fn assemble_candidates_from_impls<'cx,'tcx>( match vtable { super::VtableImpl(data) => { + if data.substs.types.needs_infer() { + let assoc_ty_opt = get_impl_item_or_default(selcx.tcx(), data.impl_def_id, |cand| { + if let &ty::TypeTraitItem(ref assoc_ty) = cand { + if assoc_ty.name == obligation.predicate.item_name { + return Some(assoc_ty.defaultness); + } + } + None + }); + + if let Some((defaultness, source)) = assoc_ty_opt { + if !source.is_from_trait() && defaultness == hir::Defaultness::Default { + // FIXME: is it OK to not mark as ambiguous? + return Ok(()); + } + } else { + selcx.tcx().sess.span_bug(obligation.cause.span, + &format!("No associated type for {:?}", + obligation_trait_ref)); + } + } + debug!("assemble_candidates_from_impls: impl candidate {:?}", data); @@ -941,43 +965,31 @@ fn confirm_impl_candidate<'cx,'tcx>( impl_vtable: VtableImplData<'tcx, PredicateObligation<'tcx>>) -> (Ty<'tcx>, Vec>) { - // there don't seem to be nicer accessors to these: - let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow(); + let VtableImplData { substs, nested, impl_def_id } = impl_vtable; - // Look for the associated type in the impl - for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] { - if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] { - if assoc_ty.name == obligation.predicate.item_name { - return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs), - impl_vtable.nested); - } - } - } - - // It is not in the impl - get the default from the trait. - let trait_ref = obligation.predicate.trait_ref; - for trait_item in selcx.tcx().trait_items(trait_ref.def_id).iter() { - if let &ty::TypeTraitItem(ref assoc_ty) = trait_item { + get_impl_item_or_default(selcx.tcx(), impl_def_id, |cand| { + if let &ty::TypeTraitItem(ref assoc_ty) = cand { if assoc_ty.name == obligation.predicate.item_name { if let Some(ty) = assoc_ty.ty { - return (ty.subst(selcx.tcx(), trait_ref.substs), - impl_vtable.nested); + return Some(ty) } else { - // This means that the impl is missing a - // definition for the associated type. This error - // ought to be reported by the type checker method - // `check_impl_items_against_trait`, so here we - // just return TyError. + // This means that the impl is missing a definition for the + // associated type. This error will be reported by the type + // checker method `check_impl_items_against_trait`, so here + // we just return TyError. debug!("confirm_impl_candidate: no associated type {:?} for {:?}", assoc_ty.name, - trait_ref); - return (selcx.tcx().types.err, vec!()); + obligation.predicate.trait_ref); + return Some(selcx.tcx().types.err); } } } - } - - selcx.tcx().sess.span_bug(obligation.cause.span, - &format!("No associated type for {:?}", - trait_ref)); + None + }).map(|(ty, source)| { + (ty.subst(selcx.tcx(), &source.translate_substs(selcx.tcx(), substs)), nested) + }).unwrap_or_else(|| { + selcx.tcx().sess.span_bug(obligation.cause.span, + &format!("No associated type for {:?}", + obligation.predicate.trait_ref)); + }) } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index b6a1337dce0..be2f63d1d1b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1053,22 +1053,22 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, missing_items.push(trait_method.name); } } - ty::TypeTraitItem(ref associated_type) => { - let is_implemented = impl_items.iter().any(|ii| { - match ii.node { - hir::ImplItemKind::Type(_) => { - ii.name == associated_type.name + ty::TypeTraitItem(ref trait_assoc_ty) => { + let search_result = traits::get_impl_item_or_default(tcx, impl_id, |cand| { + if let &ty::TypeTraitItem(ref assoc_ty) = cand { + if assoc_ty.name == trait_assoc_ty.name && assoc_ty.ty.is_some() { + return Some(()); } - _ => false, } + None }); - let is_provided = associated_type.ty.is_some(); - if !is_implemented { - if !is_provided { - missing_items.push(associated_type.name); - } else if associated_type_overridden { - invalidated_items.push(associated_type.name); + + if let Some((_, source)) = search_result { + if source.is_from_trait() && associated_type_overridden { + invalidated_items.push(trait_assoc_ty.name); } + } else { + missing_items.push(trait_assoc_ty.name); } } }