Auto merge of #25796 - arielb1:default-assoc, r=eddyb
r? @eddyb Fixes #19476.
This commit is contained in:
commit
f3819f063c
@ -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);
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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,
|
||||
|
@ -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));
|
||||
@ -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);
|
||||
|
||||
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
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!())
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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> {
|
||||
|
@ -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> {
|
||||
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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) => {
|
||||
@ -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) => {
|
||||
@ -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) => {
|
||||
@ -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(", "));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -717,15 +717,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
|
||||
});
|
||||
@ -878,18 +880,11 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
||||
"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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -972,9 +967,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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -2291,10 +2291,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 {
|
||||
|
@ -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)),
|
||||
|
@ -2737,43 +2737,40 @@ impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for ty::AssociatedType {
|
||||
impl<'tcx> Clean<Item> for ty::AssociatedType<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
// When loading a cross-crate associated type, the bounds for this type
|
||||
// are actually located on the trait/impl itself, so we need to load
|
||||
// all of the generics from there and then look for bounds that are
|
||||
// applied to this associated type in question.
|
||||
let predicates = ty::lookup_predicates(cx.tcx(), self.container.id());
|
||||
let generics = match self.container {
|
||||
ty::TraitContainer(did) => {
|
||||
let def = ty::lookup_trait_def(cx.tcx(), did);
|
||||
(&def.generics, &predicates, subst::TypeSpace).clean(cx)
|
||||
}
|
||||
ty::ImplContainer(did) => {
|
||||
let ty = ty::lookup_item_type(cx.tcx(), did);
|
||||
(&ty.generics, &predicates, subst::TypeSpace).clean(cx)
|
||||
}
|
||||
};
|
||||
let my_name = self.name.clean(cx);
|
||||
let mut bounds = generics.where_predicates.iter().filter_map(|pred| {
|
||||
let (name, self_type, trait_, bounds) = match *pred {
|
||||
WherePredicate::BoundPredicate {
|
||||
ty: QPath { ref name, ref self_type, ref trait_ },
|
||||
ref bounds
|
||||
} => (name, self_type, trait_, bounds),
|
||||
_ => return None,
|
||||
};
|
||||
if *name != my_name { return None }
|
||||
match **trait_ {
|
||||
ResolvedPath { did, .. } if did == self.container.id() => {}
|
||||
_ => return None,
|
||||
}
|
||||
match **self_type {
|
||||
Generic(ref s) if *s == "Self" => {}
|
||||
_ => return None,
|
||||
}
|
||||
Some(bounds)
|
||||
}).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>();
|
||||
|
||||
let mut bounds = if let ty::TraitContainer(did) = self.container {
|
||||
// When loading a cross-crate associated type, the bounds for this type
|
||||
// are actually located on the trait/impl itself, so we need to load
|
||||
// all of the generics from there and then look for bounds that are
|
||||
// applied to this associated type in question.
|
||||
let def = ty::lookup_trait_def(cx.tcx(), did);
|
||||
let predicates = ty::lookup_predicates(cx.tcx(), did);
|
||||
let generics = (&def.generics, &predicates, subst::TypeSpace).clean(cx);
|
||||
generics.where_predicates.iter().filter_map(|pred| {
|
||||
let (name, self_type, trait_, bounds) = match *pred {
|
||||
WherePredicate::BoundPredicate {
|
||||
ty: QPath { ref name, ref self_type, ref trait_ },
|
||||
ref bounds
|
||||
} => (name, self_type, trait_, bounds),
|
||||
_ => return None,
|
||||
};
|
||||
if *name != my_name { return None }
|
||||
match **trait_ {
|
||||
ResolvedPath { did, .. } if did == self.container.id() => {}
|
||||
_ => return None,
|
||||
}
|
||||
match **self_type {
|
||||
Generic(ref s) if *s == "Self" => {}
|
||||
_ => return None,
|
||||
}
|
||||
Some(bounds)
|
||||
}).flat_map(|i| i.iter().cloned()).collect::<Vec<_>>()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
// Our Sized/?Sized bound didn't get handled when creating the generics
|
||||
// because we didn't actually get our whole set of bounds until just now
|
||||
@ -2789,7 +2786,7 @@ impl Clean<Item> for ty::AssociatedType {
|
||||
source: DUMMY_SP.clean(cx),
|
||||
name: Some(self.name.clean(cx)),
|
||||
attrs: inline::load_attrs(cx, cx.tcx(), self.def_id),
|
||||
inner: AssociatedTypeItem(bounds, None),
|
||||
inner: AssociatedTypeItem(bounds, self.ty.clean(cx)),
|
||||
visibility: self.vis.clean(cx),
|
||||
def_id: self.def_id,
|
||||
stability: stability::lookup(cx.tcx(), self.def_id).clean(cx),
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
trait Expr : PartialEq<Self::Item> {
|
||||
//~^ ERROR: unsupported cyclic reference between types/traits detected
|
||||
type Item = Expr;
|
||||
type Item;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
17
src/test/compile-fail/issue-23073.rs
Normal file
17
src/test/compile-fail/issue-23073.rs
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait Foo { type T; }
|
||||
trait Bar {
|
||||
type Foo: Foo;
|
||||
type FooT = <<Self as Bar>::Foo>::T; //~ ERROR ambiguous associated type
|
||||
}
|
||||
|
||||
fn main() {}
|
30
src/test/run-pass/default-associated-types.rs
Normal file
30
src/test/run-pass/default-associated-types.rs
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
trait Foo<T> {
|
||||
type Out = T;
|
||||
fn foo(&self) -> Self::Out;
|
||||
}
|
||||
|
||||
impl Foo<u32> for () {
|
||||
fn foo(&self) -> u32 {
|
||||
4u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Foo<u64> for bool {
|
||||
type Out = ();
|
||||
fn foo(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(<() as Foo<u32>>::foo(&()), 4u32);
|
||||
assert_eq!(<bool as Foo<u64>>::foo(&true), ());
|
||||
}
|
36
src/test/run-pass/issue-25339.rs
Normal file
36
src/test/run-pass/issue-25339.rs
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub trait Routing<I> {
|
||||
type Output;
|
||||
fn resolve(&self, input: I);
|
||||
}
|
||||
|
||||
pub trait ToRouting {
|
||||
type Input;
|
||||
type Routing : ?Sized = Routing<Self::Input, Output=()>;
|
||||
fn to_routing(self) -> Self::Routing;
|
||||
}
|
||||
|
||||
pub struct Mount<I, R: Routing<I>> {
|
||||
action: R,
|
||||
_marker: PhantomData<I>
|
||||
}
|
||||
|
||||
impl<I, R: Routing<I>> Mount<I, R> {
|
||||
pub fn create<T: ToRouting<Routing=R>>(mount: &str, input: T) {
|
||||
input.to_routing();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user