Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement defaults for associated types #25796

Merged
merged 4 commits into from
May 28, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
52 changes: 28 additions & 24 deletions src/librustc/middle/traits/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -857,37 +857,41 @@ 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;
// 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.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!())
// It is not in the impl - get the default from the trait.
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Loading