Skip to content

Commit

Permalink
Implement defaults for associated types
Browse files Browse the repository at this point in the history
  • Loading branch information
Ariel Ben-Yehuda committed May 26, 2015
1 parent c654a07 commit ae10e47
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 120 deletions.
35 changes: 22 additions & 13 deletions src/librustc/metadata/decoder.rs
Expand Up @@ -252,6 +252,13 @@ fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx>
|_, did| translate_def_id(cdata, did))
}

fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option<Ty<'tcx>> {
reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
|_, did| translate_def_id(cdata, did))
})
}

fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>,
cdata: Cmd) -> ty::BareFnTy<'tcx> {
let tp = reader::get_doc(doc, tag_item_method_fty);
Expand Down Expand Up @@ -875,24 +882,24 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)
-> ty::ImplOrTraitItem<'tcx> {
let method_doc = lookup_item(id, cdata.data());
let item_doc = lookup_item(id, cdata.data());

let def_id = item_def_id(method_doc, cdata);
let def_id = item_def_id(item_doc, cdata);

let container_id = item_require_parent_item(cdata, method_doc);
let container_id = item_require_parent_item(cdata, item_doc);
let container_doc = lookup_item(container_id.node, cdata.data());
let container = match item_family(container_doc) {
Trait => TraitContainer(container_id),
_ => ImplContainer(container_id),
};

let name = item_name(&*intr, method_doc);
let vis = item_visibility(method_doc);
let name = item_name(&*intr, item_doc);
let vis = item_visibility(item_doc);

match item_sort(method_doc) {
match item_sort(item_doc) {
Some('C') => {
let ty = doc_type(method_doc, tcx, cdata);
let default = get_provided_source(method_doc, cdata);
let ty = doc_type(item_doc, tcx, cdata);
let default = get_provided_source(item_doc, cdata);
ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
name: name,
ty: ty,
Expand All @@ -903,11 +910,11 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
}))
}
Some('r') | Some('p') => {
let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
let fty = doc_method_fty(method_doc, tcx, cdata);
let explicit_self = get_explicit_self(method_doc);
let provided_source = get_provided_source(method_doc, cdata);
let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
let fty = doc_method_fty(item_doc, tcx, cdata);
let explicit_self = get_explicit_self(item_doc);
let provided_source = get_provided_source(item_doc, cdata);

ty::MethodTraitItem(Rc::new(ty::Method::new(name,
generics,
Expand All @@ -920,8 +927,10 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
provided_source)))
}
Some('t') => {
let ty = maybe_doc_type(item_doc, tcx, cdata);
ty::TypeTraitItem(Rc::new(ty::AssociatedType {
name: name,
ty: ty,
vis: vis,
def_id: def_id,
container: container,
Expand Down
23 changes: 14 additions & 9 deletions src/librustc/metadata/encoder.rs
Expand Up @@ -894,12 +894,12 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w.end_tag();
}

fn encode_info_for_associated_type(ecx: &EncodeContext,
rbml_w: &mut Encoder,
associated_type: &ty::AssociatedType,
impl_path: PathElems,
parent_id: NodeId,
impl_item_opt: Option<&ast::ImplItem>) {
fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
associated_type: &ty::AssociatedType<'tcx>,
impl_path: PathElems,
parent_id: NodeId,
impl_item_opt: Option<&ast::ImplItem>) {
debug!("encode_info_for_associated_type({:?},{:?})",
associated_type.def_id,
token::get_name(associated_type.name));
Expand All @@ -913,8 +913,6 @@ fn encode_info_for_associated_type(ecx: &EncodeContext,
encode_parent_item(rbml_w, local_def(parent_id));
encode_item_sort(rbml_w, 't');

encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id());

let stab = stability::lookup(ecx.tcx, associated_type.def_id);
encode_stability(rbml_w, stab);

Expand All @@ -923,7 +921,14 @@ fn encode_info_for_associated_type(ecx: &EncodeContext,

if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
encode_type(ecx, rbml_w, ty::node_id_to_type(ecx.tcx, ii.id));
} else {
encode_predicates(rbml_w, ecx,
&ty::lookup_predicates(ecx.tcx, associated_type.def_id),
tag_item_generics);
}

if let Some(ty) = associated_type.ty {
encode_type(ecx, rbml_w, ty);
}

rbml_w.end_tag();
Expand Down
50 changes: 26 additions & 24 deletions src/librustc/middle/traits/project.rs
Expand Up @@ -857,37 +857,39 @@ fn confirm_impl_candidate<'cx,'tcx>(
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
{
// there don't seem to be nicer accessors to these:
let impl_items_map = selcx.tcx().impl_items.borrow();
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();

let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap();
let mut impl_ty = None;
for impl_item in impl_items {
let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
};

if assoc_type.name != obligation.predicate.item_name {
continue;
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.into_vec());
}
}

let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
break;
}

match impl_ty {
Some(ty) => (ty, impl_vtable.nested.into_vec()),
None => {
// 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 ty_err.
(selcx.tcx().types.err, vec!())
let trait_ref = obligation.predicate.trait_ref;
for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() {
if let &ty::TypeTraitItem(ref assoc_ty) = trait_item {
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.into_vec());
} 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 ty_err.
return (selcx.tcx().types.err, vec!());
}
}
}
}

selcx.tcx().sess.span_bug(obligation.cause.span,
&format!("No associated type for {}",
trait_ref.repr(selcx.tcx())));
}

impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/middle/ty.rs
Expand Up @@ -136,7 +136,7 @@ impl ImplOrTraitItemContainer {
pub enum ImplOrTraitItem<'tcx> {
ConstTraitItem(Rc<AssociatedConst<'tcx>>),
MethodTraitItem(Rc<Method<'tcx>>),
TypeTraitItem(Rc<AssociatedType>),
TypeTraitItem(Rc<AssociatedType<'tcx>>),
}

impl<'tcx> ImplOrTraitItem<'tcx> {
Expand Down Expand Up @@ -267,8 +267,9 @@ pub struct AssociatedConst<'tcx> {
}

#[derive(Clone, Copy, Debug)]
pub struct AssociatedType {
pub struct AssociatedType<'tcx> {
pub name: ast::Name,
pub ty: Option<Ty<'tcx>>,
pub vis: ast::Visibility,
pub def_id: ast::DefId,
pub container: ImplOrTraitItemContainer,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/util/ppaux.rs
Expand Up @@ -1077,7 +1077,7 @@ impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
}
}

impl<'tcx> Repr<'tcx> for ty::AssociatedType {
impl<'tcx> Repr<'tcx> for ty::AssociatedType<'tcx> {
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
format!("AssociatedType(name: {}, vis: {}, def_id: {})",
self.name.repr(tcx),
Expand Down
17 changes: 9 additions & 8 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -1070,7 +1070,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
// Check for missing items from trait
let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id);
let mut missing_methods = Vec::new();
let mut missing_items = Vec::new();
for trait_item in &*trait_items {
match *trait_item {
ty::ConstTraitItem(ref associated_const) => {
Expand All @@ -1086,8 +1086,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
associated_consts.iter().any(|ac| ac.default.is_some() &&
ac.name == associated_const.name);
if !is_implemented && !is_provided {
missing_methods.push(format!("`{}`",
token::get_name(associated_const.name)));
missing_items.push(format!("`{}`",
token::get_name(associated_const.name)));
}
}
ty::MethodTraitItem(ref trait_method) => {
Expand All @@ -1103,7 +1103,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let is_provided =
provided_methods.iter().any(|m| m.name == trait_method.name);
if !is_implemented && !is_provided {
missing_methods.push(format!("`{}`", token::get_name(trait_method.name)));
missing_items.push(format!("`{}`", token::get_name(trait_method.name)));
}
}
ty::TypeTraitItem(ref associated_type) => {
Expand All @@ -1115,17 +1115,18 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
_ => false,
}
});
if !is_implemented {
missing_methods.push(format!("`{}`", token::get_name(associated_type.name)));
let is_provided = associated_type.ty.is_some();
if !is_implemented && !is_provided {
missing_items.push(format!("`{}`", token::get_name(associated_type.name)));
}
}
}
}

if !missing_methods.is_empty() {
if !missing_items.is_empty() {
span_err!(tcx.sess, impl_span, E0046,
"not all trait items implemented, missing: {}",
missing_methods.connect(", "));
missing_items.connect(", "));
}
}

Expand Down
48 changes: 24 additions & 24 deletions src/librustc_typeck/collect.rs
Expand Up @@ -718,15 +718,17 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
.insert(local_def(id), ty::ConstTraitItem(associated_const));
}

fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
ident: ast::Ident,
id: ast::NodeId,
vis: ast::Visibility)
fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
container: ImplOrTraitItemContainer,
ident: ast::Ident,
id: ast::NodeId,
vis: ast::Visibility,
ty: Option<Ty<'tcx>>)
{
let associated_type = Rc::new(ty::AssociatedType {
name: ident.name,
vis: vis,
ty: ty,
def_id: local_def(id),
container: container
});
Expand Down Expand Up @@ -876,21 +878,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
if let ast::TypeImplItem(ref ty) = impl_item.node {
if opt_trait_ref.is_none() {
span_err!(tcx.sess, impl_item.span, E0202,
"associated items are not allowed in inherent impls");
"associated types are not allowed in inherent impls");
}

as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
impl_item.ident, impl_item.id, impl_item.vis);

let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
TypeScheme {
generics: ty::Generics::empty(),
ty: typ,
});
tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
ty::GenericPredicates::empty());
write_ty_to_tcx(tcx, impl_item.id, typ);

convert_associated_type(ccx, ImplContainer(local_def(it.id)),
impl_item.ident, impl_item.id, impl_item.vis,
Some(typ));
}
}

Expand Down Expand Up @@ -973,9 +968,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
// Convert all the associated types.
for trait_item in trait_items {
match trait_item.node {
ast::TypeTraitItem(..) => {
as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
trait_item.ident, trait_item.id, ast::Public);
ast::TypeTraitItem(_, ref opt_ty) => {
let typ = opt_ty.as_ref().map({
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
});

convert_associated_type(ccx, TraitContainer(local_def(it.id)),
trait_item.ident, trait_item.id, ast::Public,
typ);
}
_ => {}
}
Expand Down Expand Up @@ -2292,10 +2292,10 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,

let lifetimes_in_associated_types: HashSet<_> =
impl_items.iter()
.filter_map(|item| match item.node {
ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)),
ast::ConstImplItem(..) | ast::MethodImplItem(..) |
ast::MacImplItem(..) => None,
.map(|item| ty::impl_or_trait_item(tcx, local_def(item.id)))
.filter_map(|item| match item {
ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
})
.flat_map(|ty| ctp::parameters_for_type(ty).into_iter())
.filter_map(|p| match p {
Expand Down
8 changes: 5 additions & 3 deletions src/librustdoc/clean/inline.rs
Expand Up @@ -362,11 +362,13 @@ pub fn build_impl(cx: &DocContext,
}
ty::TypeTraitItem(ref assoc_ty) => {
let did = assoc_ty.def_id;
let type_scheme = ty::lookup_item_type(tcx, did);
let predicates = ty::lookup_predicates(tcx, did);
let type_scheme = ty::TypeScheme {
ty: assoc_ty.ty.unwrap(),
generics: ty::Generics::empty()
};
// Not sure the choice of ParamSpace actually matters here,
// because an associated type won't have generics on the LHS
let typedef = (type_scheme, predicates,
let typedef = (type_scheme, ty::GenericPredicates::empty(),
subst::ParamSpace::TypeSpace).clean(cx);
Some(clean::Item {
name: Some(assoc_ty.name.clean(cx)),
Expand Down

0 comments on commit ae10e47

Please sign in to comment.