Skip to content

Commit ae10e47

Browse files
author
Ariel Ben-Yehuda
committed
Implement defaults for associated types
1 parent c654a07 commit ae10e47

File tree

10 files changed

+167
-120
lines changed

10 files changed

+167
-120
lines changed

src/librustc/metadata/decoder.rs

+22-13
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,13 @@ fn doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Ty<'tcx>
252252
|_, did| translate_def_id(cdata, did))
253253
}
254254

255+
fn maybe_doc_type<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>, cdata: Cmd) -> Option<Ty<'tcx>> {
256+
reader::maybe_get_doc(doc, tag_items_data_item_type).map(|tp| {
257+
parse_ty_data(tp.data, cdata.cnum, tp.start, tcx,
258+
|_, did| translate_def_id(cdata, did))
259+
})
260+
}
261+
255262
fn doc_method_fty<'tcx>(doc: rbml::Doc, tcx: &ty::ctxt<'tcx>,
256263
cdata: Cmd) -> ty::BareFnTy<'tcx> {
257264
let tp = reader::get_doc(doc, tag_item_method_fty);
@@ -875,24 +882,24 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
875882
id: ast::NodeId,
876883
tcx: &ty::ctxt<'tcx>)
877884
-> ty::ImplOrTraitItem<'tcx> {
878-
let method_doc = lookup_item(id, cdata.data());
885+
let item_doc = lookup_item(id, cdata.data());
879886

880-
let def_id = item_def_id(method_doc, cdata);
887+
let def_id = item_def_id(item_doc, cdata);
881888

882-
let container_id = item_require_parent_item(cdata, method_doc);
889+
let container_id = item_require_parent_item(cdata, item_doc);
883890
let container_doc = lookup_item(container_id.node, cdata.data());
884891
let container = match item_family(container_doc) {
885892
Trait => TraitContainer(container_id),
886893
_ => ImplContainer(container_id),
887894
};
888895

889-
let name = item_name(&*intr, method_doc);
890-
let vis = item_visibility(method_doc);
896+
let name = item_name(&*intr, item_doc);
897+
let vis = item_visibility(item_doc);
891898

892-
match item_sort(method_doc) {
899+
match item_sort(item_doc) {
893900
Some('C') => {
894-
let ty = doc_type(method_doc, tcx, cdata);
895-
let default = get_provided_source(method_doc, cdata);
901+
let ty = doc_type(item_doc, tcx, cdata);
902+
let default = get_provided_source(item_doc, cdata);
896903
ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
897904
name: name,
898905
ty: ty,
@@ -903,11 +910,11 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
903910
}))
904911
}
905912
Some('r') | Some('p') => {
906-
let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
907-
let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
908-
let fty = doc_method_fty(method_doc, tcx, cdata);
909-
let explicit_self = get_explicit_self(method_doc);
910-
let provided_source = get_provided_source(method_doc, cdata);
913+
let generics = doc_generics(item_doc, tcx, cdata, tag_method_ty_generics);
914+
let predicates = doc_predicates(item_doc, tcx, cdata, tag_method_ty_generics);
915+
let fty = doc_method_fty(item_doc, tcx, cdata);
916+
let explicit_self = get_explicit_self(item_doc);
917+
let provided_source = get_provided_source(item_doc, cdata);
911918

912919
ty::MethodTraitItem(Rc::new(ty::Method::new(name,
913920
generics,
@@ -920,8 +927,10 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
920927
provided_source)))
921928
}
922929
Some('t') => {
930+
let ty = maybe_doc_type(item_doc, tcx, cdata);
923931
ty::TypeTraitItem(Rc::new(ty::AssociatedType {
924932
name: name,
933+
ty: ty,
925934
vis: vis,
926935
def_id: def_id,
927936
container: container,

src/librustc/metadata/encoder.rs

+14-9
Original file line numberDiff line numberDiff line change
@@ -894,12 +894,12 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
894894
rbml_w.end_tag();
895895
}
896896

897-
fn encode_info_for_associated_type(ecx: &EncodeContext,
898-
rbml_w: &mut Encoder,
899-
associated_type: &ty::AssociatedType,
900-
impl_path: PathElems,
901-
parent_id: NodeId,
902-
impl_item_opt: Option<&ast::ImplItem>) {
897+
fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
898+
rbml_w: &mut Encoder,
899+
associated_type: &ty::AssociatedType<'tcx>,
900+
impl_path: PathElems,
901+
parent_id: NodeId,
902+
impl_item_opt: Option<&ast::ImplItem>) {
903903
debug!("encode_info_for_associated_type({:?},{:?})",
904904
associated_type.def_id,
905905
token::get_name(associated_type.name));
@@ -913,8 +913,6 @@ fn encode_info_for_associated_type(ecx: &EncodeContext,
913913
encode_parent_item(rbml_w, local_def(parent_id));
914914
encode_item_sort(rbml_w, 't');
915915

916-
encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id());
917-
918916
let stab = stability::lookup(ecx.tcx, associated_type.def_id);
919917
encode_stability(rbml_w, stab);
920918

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

924922
if let Some(ii) = impl_item_opt {
925923
encode_attributes(rbml_w, &ii.attrs);
926-
encode_type(ecx, rbml_w, ty::node_id_to_type(ecx.tcx, ii.id));
924+
} else {
925+
encode_predicates(rbml_w, ecx,
926+
&ty::lookup_predicates(ecx.tcx, associated_type.def_id),
927+
tag_item_generics);
928+
}
929+
930+
if let Some(ty) = associated_type.ty {
931+
encode_type(ecx, rbml_w, ty);
927932
}
928933

929934
rbml_w.end_tag();

src/librustc/middle/traits/project.rs

+26-24
Original file line numberDiff line numberDiff line change
@@ -857,37 +857,39 @@ fn confirm_impl_candidate<'cx,'tcx>(
857857
-> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
858858
{
859859
// there don't seem to be nicer accessors to these:
860-
let impl_items_map = selcx.tcx().impl_items.borrow();
861860
let impl_or_trait_items_map = selcx.tcx().impl_or_trait_items.borrow();
862861

863-
let impl_items = impl_items_map.get(&impl_vtable.impl_def_id).unwrap();
864-
let mut impl_ty = None;
865-
for impl_item in impl_items {
866-
let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() {
867-
ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(),
868-
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
869-
};
870-
871-
if assoc_type.name != obligation.predicate.item_name {
872-
continue;
862+
for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
863+
if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
864+
if assoc_ty.name == obligation.predicate.item_name {
865+
return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs),
866+
impl_vtable.nested.into_vec());
867+
}
873868
}
874-
875-
let impl_poly_ty = ty::lookup_item_type(selcx.tcx(), assoc_type.def_id);
876-
impl_ty = Some(impl_poly_ty.ty.subst(selcx.tcx(), &impl_vtable.substs));
877-
break;
878869
}
879870

880-
match impl_ty {
881-
Some(ty) => (ty, impl_vtable.nested.into_vec()),
882-
None => {
883-
// This means that the impl is missing a
884-
// definition for the associated type. This error
885-
// ought to be reported by the type checker method
886-
// `check_impl_items_against_trait`, so here we
887-
// just return ty_err.
888-
(selcx.tcx().types.err, vec!())
871+
let trait_ref = obligation.predicate.trait_ref;
872+
for trait_item in ty::trait_items(selcx.tcx(), trait_ref.def_id).iter() {
873+
if let &ty::TypeTraitItem(ref assoc_ty) = trait_item {
874+
if assoc_ty.name == obligation.predicate.item_name {
875+
if let Some(ty) = assoc_ty.ty {
876+
return (ty.subst(selcx.tcx(), trait_ref.substs),
877+
impl_vtable.nested.into_vec());
878+
} else {
879+
// This means that the impl is missing a
880+
// definition for the associated type. This error
881+
// ought to be reported by the type checker method
882+
// `check_impl_items_against_trait`, so here we
883+
// just return ty_err.
884+
return (selcx.tcx().types.err, vec!());
885+
}
886+
}
889887
}
890888
}
889+
890+
selcx.tcx().sess.span_bug(obligation.cause.span,
891+
&format!("No associated type for {}",
892+
trait_ref.repr(selcx.tcx())));
891893
}
892894

893895
impl<'tcx> Repr<'tcx> for ProjectionTyError<'tcx> {

src/librustc/middle/ty.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ impl ImplOrTraitItemContainer {
136136
pub enum ImplOrTraitItem<'tcx> {
137137
ConstTraitItem(Rc<AssociatedConst<'tcx>>),
138138
MethodTraitItem(Rc<Method<'tcx>>),
139-
TypeTraitItem(Rc<AssociatedType>),
139+
TypeTraitItem(Rc<AssociatedType<'tcx>>),
140140
}
141141

142142
impl<'tcx> ImplOrTraitItem<'tcx> {
@@ -267,8 +267,9 @@ pub struct AssociatedConst<'tcx> {
267267
}
268268

269269
#[derive(Clone, Copy, Debug)]
270-
pub struct AssociatedType {
270+
pub struct AssociatedType<'tcx> {
271271
pub name: ast::Name,
272+
pub ty: Option<Ty<'tcx>>,
272273
pub vis: ast::Visibility,
273274
pub def_id: ast::DefId,
274275
pub container: ImplOrTraitItemContainer,

src/librustc/util/ppaux.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1077,7 +1077,7 @@ impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
10771077
}
10781078
}
10791079

1080-
impl<'tcx> Repr<'tcx> for ty::AssociatedType {
1080+
impl<'tcx> Repr<'tcx> for ty::AssociatedType<'tcx> {
10811081
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
10821082
format!("AssociatedType(name: {}, vis: {}, def_id: {})",
10831083
self.name.repr(tcx),

src/librustc_typeck/check/mod.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
10701070
// Check for missing items from trait
10711071
let provided_methods = ty::provided_trait_methods(tcx, impl_trait_ref.def_id);
10721072
let associated_consts = ty::associated_consts(tcx, impl_trait_ref.def_id);
1073-
let mut missing_methods = Vec::new();
1073+
let mut missing_items = Vec::new();
10741074
for trait_item in &*trait_items {
10751075
match *trait_item {
10761076
ty::ConstTraitItem(ref associated_const) => {
@@ -1086,8 +1086,8 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
10861086
associated_consts.iter().any(|ac| ac.default.is_some() &&
10871087
ac.name == associated_const.name);
10881088
if !is_implemented && !is_provided {
1089-
missing_methods.push(format!("`{}`",
1090-
token::get_name(associated_const.name)));
1089+
missing_items.push(format!("`{}`",
1090+
token::get_name(associated_const.name)));
10911091
}
10921092
}
10931093
ty::MethodTraitItem(ref trait_method) => {
@@ -1103,7 +1103,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
11031103
let is_provided =
11041104
provided_methods.iter().any(|m| m.name == trait_method.name);
11051105
if !is_implemented && !is_provided {
1106-
missing_methods.push(format!("`{}`", token::get_name(trait_method.name)));
1106+
missing_items.push(format!("`{}`", token::get_name(trait_method.name)));
11071107
}
11081108
}
11091109
ty::TypeTraitItem(ref associated_type) => {
@@ -1115,17 +1115,18 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
11151115
_ => false,
11161116
}
11171117
});
1118-
if !is_implemented {
1119-
missing_methods.push(format!("`{}`", token::get_name(associated_type.name)));
1118+
let is_provided = associated_type.ty.is_some();
1119+
if !is_implemented && !is_provided {
1120+
missing_items.push(format!("`{}`", token::get_name(associated_type.name)));
11201121
}
11211122
}
11221123
}
11231124
}
11241125

1125-
if !missing_methods.is_empty() {
1126+
if !missing_items.is_empty() {
11261127
span_err!(tcx.sess, impl_span, E0046,
11271128
"not all trait items implemented, missing: {}",
1128-
missing_methods.connect(", "));
1129+
missing_items.connect(", "));
11291130
}
11301131
}
11311132

src/librustc_typeck/collect.rs

+24-24
Original file line numberDiff line numberDiff line change
@@ -718,15 +718,17 @@ fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
718718
.insert(local_def(id), ty::ConstTraitItem(associated_const));
719719
}
720720

721-
fn as_refsociated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
722-
container: ImplOrTraitItemContainer,
723-
ident: ast::Ident,
724-
id: ast::NodeId,
725-
vis: ast::Visibility)
721+
fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
722+
container: ImplOrTraitItemContainer,
723+
ident: ast::Ident,
724+
id: ast::NodeId,
725+
vis: ast::Visibility,
726+
ty: Option<Ty<'tcx>>)
726727
{
727728
let associated_type = Rc::new(ty::AssociatedType {
728729
name: ident.name,
729730
vis: vis,
731+
ty: ty,
730732
def_id: local_def(id),
731733
container: container
732734
});
@@ -876,21 +878,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
876878
if let ast::TypeImplItem(ref ty) = impl_item.node {
877879
if opt_trait_ref.is_none() {
878880
span_err!(tcx.sess, impl_item.span, E0202,
879-
"associated items are not allowed in inherent impls");
881+
"associated types are not allowed in inherent impls");
880882
}
881883

882-
as_refsociated_type(ccx, ImplContainer(local_def(it.id)),
883-
impl_item.ident, impl_item.id, impl_item.vis);
884-
885884
let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty);
886-
tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
887-
TypeScheme {
888-
generics: ty::Generics::empty(),
889-
ty: typ,
890-
});
891-
tcx.predicates.borrow_mut().insert(local_def(impl_item.id),
892-
ty::GenericPredicates::empty());
893-
write_ty_to_tcx(tcx, impl_item.id, typ);
885+
886+
convert_associated_type(ccx, ImplContainer(local_def(it.id)),
887+
impl_item.ident, impl_item.id, impl_item.vis,
888+
Some(typ));
894889
}
895890
}
896891

@@ -973,9 +968,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
973968
// Convert all the associated types.
974969
for trait_item in trait_items {
975970
match trait_item.node {
976-
ast::TypeTraitItem(..) => {
977-
as_refsociated_type(ccx, TraitContainer(local_def(it.id)),
978-
trait_item.ident, trait_item.id, ast::Public);
971+
ast::TypeTraitItem(_, ref opt_ty) => {
972+
let typ = opt_ty.as_ref().map({
973+
|ty| ccx.icx(&trait_predicates).to_ty(&ExplicitRscope, &ty)
974+
});
975+
976+
convert_associated_type(ccx, TraitContainer(local_def(it.id)),
977+
trait_item.ident, trait_item.id, ast::Public,
978+
typ);
979979
}
980980
_ => {}
981981
}
@@ -2292,10 +2292,10 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
22922292

22932293
let lifetimes_in_associated_types: HashSet<_> =
22942294
impl_items.iter()
2295-
.filter_map(|item| match item.node {
2296-
ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)),
2297-
ast::ConstImplItem(..) | ast::MethodImplItem(..) |
2298-
ast::MacImplItem(..) => None,
2295+
.map(|item| ty::impl_or_trait_item(tcx, local_def(item.id)))
2296+
.filter_map(|item| match item {
2297+
ty::TypeTraitItem(ref assoc_ty) => assoc_ty.ty,
2298+
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => None
22992299
})
23002300
.flat_map(|ty| ctp::parameters_for_type(ty).into_iter())
23012301
.filter_map(|p| match p {

src/librustdoc/clean/inline.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -362,11 +362,13 @@ pub fn build_impl(cx: &DocContext,
362362
}
363363
ty::TypeTraitItem(ref assoc_ty) => {
364364
let did = assoc_ty.def_id;
365-
let type_scheme = ty::lookup_item_type(tcx, did);
366-
let predicates = ty::lookup_predicates(tcx, did);
365+
let type_scheme = ty::TypeScheme {
366+
ty: assoc_ty.ty.unwrap(),
367+
generics: ty::Generics::empty()
368+
};
367369
// Not sure the choice of ParamSpace actually matters here,
368370
// because an associated type won't have generics on the LHS
369-
let typedef = (type_scheme, predicates,
371+
let typedef = (type_scheme, ty::GenericPredicates::empty(),
370372
subst::ParamSpace::TypeSpace).clean(cx);
371373
Some(clean::Item {
372374
name: Some(assoc_ty.name.clean(cx)),

0 commit comments

Comments
 (0)