From b7e5112e88b8e73a5bff5a84f37f1d2a608e821c Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 29 Dec 2015 13:37:34 -0800 Subject: [PATCH] Implement default associated type inheritance. This commit leverages the specialization graph infrastructure to allow specializing trait implementations to leave off associated types for which their parents have provided defaults. It also modifies the type projection code to avoid projecting associated types unless either (1) all input types are fully known or (2) the available associated type is "final", i.e. not marked `default`. This restriction is required for soundness, due to examples like: ```rust trait Foo { type Assoc; } impl Foo for T { default type Assoc = (); } impl Foo for u8 { type Assoc = String; } fn generic() -> ::Assoc { () //~ ERROR } fn main() { let s: String = generic::(); println!("{}", s); // bad news } ``` --- src/librustc/middle/traits/project.rs | 74 ++++++++++++++++----------- src/librustc_typeck/check/mod.rs | 24 ++++----- 2 files changed, 55 insertions(+), 43 deletions(-) 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 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(); - - // 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); - } - } - } + let VtableImplData { substs, nested, impl_def_id } = impl_vtable; - // 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); } } } -- 2.44.0