Auto merge of #23606 - quantheory:associated_const, r=nikomatsakis
Closes #17841. The majority of the work should be done, e.g. trait and inherent impls, different forms of UFCS syntax, defaults, and cross-crate usage. It's probably enough to replace the constants in `f32`, `i8`, and so on, or close to good enough. There is still some significant functionality missing from this commit: - ~~Associated consts can't be used in match patterns at all. This is simply because I haven't updated the relevant bits in the parser or `resolve`, but it's *probably* not hard to get working.~~ - Since you can't select an impl for trait-associated consts until partway through type-checking, there are some problems with code that assumes that you can check constants earlier. Associated consts that are not in inherent impls cause ICEs if you try to use them in array sizes or match ranges. For similar reasons, `check_static_recursion` doesn't check them properly, so the stack goes ka-blooey if you use an associated constant that's recursively defined. That's a bit trickier to solve; I'm not entirely sure what the best approach is yet. - Dealing with consts associated with type parameters will raise some new issues (e.g. if you have a `T: Int` type parameter and want to use `<T>::ZERO`). See rust-lang/rfcs#865. - ~~Unused associated consts don't seem to trigger the `dead_code` lint when they should. Probably easy to fix.~~ Also, this is the first time I've been spelunking in rustc to such a large extent, so I've probably done some silly things in a couple of places.
This commit is contained in:
commit
857ef6e272
93 changed files with 2804 additions and 727 deletions
|
@ -2135,7 +2135,10 @@ The currently implemented features of the reference compiler are:
|
|||
semantics are likely to change, so this macro usage must be opted
|
||||
into.
|
||||
|
||||
* `associated_types` - Allows type aliases in traits. Experimental.
|
||||
* `associated_consts` - Allows constants to be defined in `impl` and `trait`
|
||||
blocks, so that they can be associated with a type or
|
||||
trait in a similar manner to methods and associated
|
||||
types.
|
||||
|
||||
* `box_patterns` - Allows `box` patterns, the exact semantics of which
|
||||
is subject to change.
|
||||
|
|
|
@ -505,10 +505,20 @@ trait_items
|
|||
;
|
||||
|
||||
trait_item
|
||||
: trait_type
|
||||
: trait_const
|
||||
| trait_type
|
||||
| trait_method
|
||||
;
|
||||
|
||||
trait_const
|
||||
: maybe_outer_attrs CONST ident maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 3, $1, $3, $4); }
|
||||
;
|
||||
|
||||
maybe_const_default
|
||||
: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
|
||||
| %empty { $$ = mk_none(); }
|
||||
;
|
||||
|
||||
trait_type
|
||||
: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
|
||||
;
|
||||
|
@ -611,7 +621,16 @@ impl_items
|
|||
impl_item
|
||||
: impl_method
|
||||
| item_macro
|
||||
| trait_type
|
||||
| impl_const
|
||||
| impl_type
|
||||
;
|
||||
|
||||
impl_const
|
||||
: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
|
||||
;
|
||||
|
||||
impl_type
|
||||
: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
|
||||
;
|
||||
|
||||
item_fn
|
||||
|
|
|
@ -175,6 +175,13 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
|
||||
}
|
||||
|
||||
pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
|
||||
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
|
||||
let cstore = &tcx.sess.cstore;
|
||||
let cdata = cstore.get_crate_data(def.krate);
|
||||
decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx)
|
||||
}
|
||||
|
||||
pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId)
|
||||
-> Option<ast::Name> {
|
||||
let cdata = cstore.get_crate_data(def.krate);
|
||||
|
|
|
@ -305,7 +305,25 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
|
|||
-> DefLike {
|
||||
let fam = item_family(item);
|
||||
match fam {
|
||||
Constant => DlDef(def::DefConst(did)),
|
||||
Constant => {
|
||||
// Check whether we have an associated const item.
|
||||
if item_sort(item) == Some('C') {
|
||||
// Check whether the associated const is from a trait or impl.
|
||||
// See the comment for methods below.
|
||||
let provenance = if reader::maybe_get_doc(
|
||||
item, tag_item_trait_parent_sort).is_some() {
|
||||
def::FromTrait(item_reqd_and_translated_parent_item(cnum,
|
||||
item))
|
||||
} else {
|
||||
def::FromImpl(item_reqd_and_translated_parent_item(cnum,
|
||||
item))
|
||||
};
|
||||
DlDef(def::DefAssociatedConst(did, provenance))
|
||||
} else {
|
||||
// Regular const item.
|
||||
DlDef(def::DefConst(did))
|
||||
}
|
||||
}
|
||||
ImmStatic => DlDef(def::DefStatic(did, false)),
|
||||
MutStatic => DlDef(def::DefStatic(did, true)),
|
||||
Struct => DlDef(def::DefStruct(did)),
|
||||
|
@ -826,6 +844,7 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
|
|||
tag_item_impl_item, |doc| {
|
||||
let def_id = item_def_id(doc, cdata);
|
||||
match item_sort(doc) {
|
||||
Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)),
|
||||
Some('r') | Some('p') => {
|
||||
impl_items.push(ty::MethodTraitItemId(def_id))
|
||||
}
|
||||
|
@ -877,6 +896,18 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
|
|||
let vis = item_visibility(method_doc);
|
||||
|
||||
match item_sort(method_doc) {
|
||||
Some('C') => {
|
||||
let ty = doc_type(method_doc, tcx, cdata);
|
||||
let default = get_provided_source(method_doc, cdata);
|
||||
ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
|
||||
name: name,
|
||||
ty: ty,
|
||||
vis: vis,
|
||||
def_id: def_id,
|
||||
container: container,
|
||||
default: default,
|
||||
}))
|
||||
}
|
||||
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);
|
||||
|
@ -914,6 +945,7 @@ pub fn get_trait_item_def_ids(cdata: Cmd, id: ast::NodeId)
|
|||
reader::tagged_docs(item, tag_item_trait_item, |mth| {
|
||||
let def_id = item_def_id(mth, cdata);
|
||||
match item_sort(mth) {
|
||||
Some('C') => result.push(ty::ConstTraitItemId(def_id)),
|
||||
Some('r') | Some('p') => {
|
||||
result.push(ty::MethodTraitItemId(def_id));
|
||||
}
|
||||
|
@ -951,11 +983,8 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
|
|||
cdata,
|
||||
did.node,
|
||||
tcx);
|
||||
match trait_item {
|
||||
ty::MethodTraitItem(ref method) => {
|
||||
result.push((*method).clone())
|
||||
}
|
||||
ty::TypeTraitItem(_) => {}
|
||||
if let ty::MethodTraitItem(ref method) = trait_item {
|
||||
result.push((*method).clone())
|
||||
}
|
||||
}
|
||||
true
|
||||
|
@ -964,6 +993,36 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
|
|||
return result;
|
||||
}
|
||||
|
||||
pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
|
||||
cdata: Cmd,
|
||||
id: ast::NodeId,
|
||||
tcx: &ty::ctxt<'tcx>)
|
||||
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
|
||||
let data = cdata.data();
|
||||
let item = lookup_item(id, data);
|
||||
let mut result = Vec::new();
|
||||
|
||||
for &tag in &[tag_item_trait_item, tag_item_impl_item] {
|
||||
reader::tagged_docs(item, tag, |ac_id| {
|
||||
let did = item_def_id(ac_id, cdata);
|
||||
let ac_doc = lookup_item(did.node, data);
|
||||
|
||||
if item_sort(ac_doc) == Some('C') {
|
||||
let trait_item = get_impl_or_trait_item(intr.clone(),
|
||||
cdata,
|
||||
did.node,
|
||||
tcx);
|
||||
if let ty::ConstTraitItem(ref ac) = trait_item {
|
||||
result.push((*ac).clone())
|
||||
}
|
||||
}
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn get_type_name_if_impl(cdata: Cmd,
|
||||
node_id: ast::NodeId) -> Option<ast::Name> {
|
||||
let item = lookup_item(node_id, cdata.data());
|
||||
|
|
|
@ -378,14 +378,11 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
|
|||
let impl_item = ty::impl_or_trait_item(
|
||||
ecx.tcx,
|
||||
method_did.def_id());
|
||||
match impl_item {
|
||||
ty::MethodTraitItem(ref m) => {
|
||||
encode_reexported_static_method(rbml_w,
|
||||
exp,
|
||||
m.def_id,
|
||||
m.name);
|
||||
}
|
||||
ty::TypeTraitItem(_) => {}
|
||||
if let ty::MethodTraitItem(ref m) = impl_item {
|
||||
encode_reexported_static_method(rbml_w,
|
||||
exp,
|
||||
m.def_id,
|
||||
m.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -802,6 +799,43 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
|||
encode_provided_source(rbml_w, method_ty.provided_source);
|
||||
}
|
||||
|
||||
fn encode_info_for_associated_const(ecx: &EncodeContext,
|
||||
rbml_w: &mut Encoder,
|
||||
associated_const: &ty::AssociatedConst,
|
||||
impl_path: PathElems,
|
||||
parent_id: NodeId,
|
||||
impl_item_opt: Option<&ast::ImplItem>) {
|
||||
debug!("encode_info_for_associated_const({:?},{:?})",
|
||||
associated_const.def_id,
|
||||
token::get_name(associated_const.name));
|
||||
|
||||
rbml_w.start_tag(tag_items_data_item);
|
||||
|
||||
encode_def_id(rbml_w, associated_const.def_id);
|
||||
encode_name(rbml_w, associated_const.name);
|
||||
encode_visibility(rbml_w, associated_const.vis);
|
||||
encode_family(rbml_w, 'C');
|
||||
encode_provided_source(rbml_w, associated_const.default);
|
||||
|
||||
encode_parent_item(rbml_w, local_def(parent_id));
|
||||
encode_item_sort(rbml_w, 'C');
|
||||
|
||||
encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());
|
||||
|
||||
let stab = stability::lookup(ecx.tcx, associated_const.def_id);
|
||||
encode_stability(rbml_w, stab);
|
||||
|
||||
let elem = ast_map::PathName(associated_const.name);
|
||||
encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
|
||||
|
||||
if let Some(ii) = impl_item_opt {
|
||||
encode_attributes(rbml_w, &ii.attrs);
|
||||
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ii));
|
||||
}
|
||||
|
||||
rbml_w.end_tag();
|
||||
}
|
||||
|
||||
fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
|
||||
rbml_w: &mut Encoder,
|
||||
m: &ty::Method<'tcx>,
|
||||
|
@ -1195,6 +1229,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
for &item_def_id in items {
|
||||
rbml_w.start_tag(tag_item_impl_item);
|
||||
match item_def_id {
|
||||
ty::ConstTraitItemId(item_def_id) => {
|
||||
encode_def_id(rbml_w, item_def_id);
|
||||
encode_item_sort(rbml_w, 'C');
|
||||
}
|
||||
ty::MethodTraitItemId(item_def_id) => {
|
||||
encode_def_id(rbml_w, item_def_id);
|
||||
encode_item_sort(rbml_w, 'r');
|
||||
|
@ -1232,6 +1270,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
});
|
||||
|
||||
match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
|
||||
ty::ConstTraitItem(ref associated_const) => {
|
||||
encode_info_for_associated_const(ecx,
|
||||
rbml_w,
|
||||
&*associated_const,
|
||||
path.clone(),
|
||||
item.id,
|
||||
ast_item)
|
||||
}
|
||||
ty::MethodTraitItem(ref method_type) => {
|
||||
encode_info_for_method(ecx,
|
||||
rbml_w,
|
||||
|
@ -1276,6 +1322,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
|
||||
rbml_w.start_tag(tag_item_trait_item);
|
||||
match method_def_id {
|
||||
ty::ConstTraitItemId(const_def_id) => {
|
||||
encode_def_id(rbml_w, const_def_id);
|
||||
encode_item_sort(rbml_w, 'C');
|
||||
}
|
||||
ty::MethodTraitItemId(method_def_id) => {
|
||||
encode_def_id(rbml_w, method_def_id);
|
||||
encode_item_sort(rbml_w, 'r');
|
||||
|
@ -1321,6 +1371,25 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
ty::impl_or_trait_item(tcx, item_def_id.def_id());
|
||||
let is_nonstatic_method;
|
||||
match trait_item_type {
|
||||
ty::ConstTraitItem(associated_const) => {
|
||||
encode_name(rbml_w, associated_const.name);
|
||||
encode_def_id(rbml_w, associated_const.def_id);
|
||||
encode_visibility(rbml_w, associated_const.vis);
|
||||
|
||||
encode_provided_source(rbml_w, associated_const.default);
|
||||
|
||||
let elem = ast_map::PathName(associated_const.name);
|
||||
encode_path(rbml_w,
|
||||
path.clone().chain(Some(elem).into_iter()));
|
||||
|
||||
encode_item_sort(rbml_w, 'C');
|
||||
encode_family(rbml_w, 'C');
|
||||
|
||||
encode_bounds_and_type_for_item(rbml_w, ecx,
|
||||
associated_const.def_id.local_id());
|
||||
|
||||
is_nonstatic_method = false;
|
||||
}
|
||||
ty::MethodTraitItem(method_ty) => {
|
||||
let method_def_id = item_def_id.def_id();
|
||||
|
||||
|
@ -1365,6 +1434,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
let trait_item = &*ms[i];
|
||||
encode_attributes(rbml_w, &trait_item.attrs);
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(_, _) => {
|
||||
encode_inlined_item(ecx, rbml_w,
|
||||
IITraitItemRef(def_id, trait_item));
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, ref body) => {
|
||||
// If this is a static method, we've already
|
||||
// encoded this.
|
||||
|
@ -1384,9 +1457,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
encode_method_argument_names(rbml_w, &sig.decl);
|
||||
}
|
||||
|
||||
ast::TypeTraitItem(..) => {
|
||||
encode_item_sort(rbml_w, 't');
|
||||
}
|
||||
ast::TypeTraitItem(..) => {}
|
||||
}
|
||||
|
||||
rbml_w.end_tag();
|
||||
|
|
|
@ -465,6 +465,9 @@ impl tr for def::Def {
|
|||
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
|
||||
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
|
||||
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
|
||||
def::DefAssociatedConst(did, p) => {
|
||||
def::DefAssociatedConst(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
|
||||
}
|
||||
def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
|
||||
def::DefVariant(e_did, v_did, is_s) => {
|
||||
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
|
||||
|
|
|
@ -105,6 +105,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||
match pat.node {
|
||||
ast::PatIdent(_, _, None) |
|
||||
ast::PatEnum(_, None) |
|
||||
ast::PatQPath(..) |
|
||||
ast::PatLit(..) |
|
||||
ast::PatRange(..) |
|
||||
ast::PatWild(_) => {
|
||||
|
|
|
@ -223,6 +223,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
|
||||
match t.node {
|
||||
ast::ConstTraitItem(_, ref default) => {
|
||||
if let Some(ref expr) = *default {
|
||||
self.global_expr(Mode::Const, &*expr);
|
||||
} else {
|
||||
visit::walk_trait_item(self, t);
|
||||
}
|
||||
}
|
||||
_ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, i: &'v ast::ImplItem) {
|
||||
match i.node {
|
||||
ast::ConstImplItem(_, ref expr) => {
|
||||
self.global_expr(Mode::Const, &*expr);
|
||||
}
|
||||
_ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self,
|
||||
fk: visit::FnKind<'v>,
|
||||
fd: &'v ast::FnDecl,
|
||||
|
@ -468,13 +490,16 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
|
|||
Mode::Var => v.add_qualif(NOT_CONST)
|
||||
}
|
||||
}
|
||||
Some(def::DefConst(did)) => {
|
||||
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did) {
|
||||
Some(def::DefConst(did)) |
|
||||
Some(def::DefAssociatedConst(did, _)) => {
|
||||
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
|
||||
Some(e.id)) {
|
||||
let inner = v.global_expr(Mode::Const, expr);
|
||||
v.add_qualif(inner);
|
||||
} else {
|
||||
v.tcx.sess.span_bug(e.span, "DefConst doesn't point \
|
||||
to an ItemConst");
|
||||
v.tcx.sess.span_bug(e.span,
|
||||
"DefConst or DefAssociatedConst \
|
||||
doesn't point to a constant");
|
||||
}
|
||||
}
|
||||
def => {
|
||||
|
|
|
@ -439,10 +439,11 @@ impl<'map> ast_util::IdVisitingOperation for RenamingRecorder<'map> {
|
|||
impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
|
||||
fn fold_pat(&mut self, pat: P<Pat>) -> P<Pat> {
|
||||
return match pat.node {
|
||||
ast::PatIdent(..) | ast::PatEnum(..) => {
|
||||
ast::PatIdent(..) | ast::PatEnum(..) | ast::PatQPath(..) => {
|
||||
let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def());
|
||||
match def {
|
||||
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did) {
|
||||
Some(DefAssociatedConst(did, _)) |
|
||||
Some(DefConst(did)) => match lookup_const_by_id(self.tcx, did, Some(pat.id)) {
|
||||
Some(const_expr) => {
|
||||
const_expr_to_pat(self.tcx, const_expr, pat.span).map(|new_pat| {
|
||||
|
||||
|
@ -746,7 +747,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
|||
match pat.node {
|
||||
ast::PatIdent(..) =>
|
||||
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
||||
Some(DefConst(..)) =>
|
||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
|
||||
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
||||
been rewritten"),
|
||||
Some(DefStruct(_)) => vec!(Single),
|
||||
|
@ -755,15 +756,18 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
|||
},
|
||||
ast::PatEnum(..) =>
|
||||
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
||||
Some(DefConst(..)) =>
|
||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
|
||||
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
||||
been rewritten"),
|
||||
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
|
||||
_ => vec!(Single)
|
||||
},
|
||||
ast::PatQPath(..) =>
|
||||
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
||||
been rewritten"),
|
||||
ast::PatStruct(..) =>
|
||||
match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) {
|
||||
Some(DefConst(..)) =>
|
||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
|
||||
cx.tcx.sess.span_bug(pat.span, "const pattern should've \
|
||||
been rewritten"),
|
||||
Some(DefVariant(_, id, _)) => vec!(Variant(id)),
|
||||
|
@ -861,7 +865,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
ast::PatIdent(_, _, _) => {
|
||||
let opt_def = cx.tcx.def_map.borrow().get(&pat_id).map(|d| d.full_def());
|
||||
match opt_def {
|
||||
Some(DefConst(..)) =>
|
||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) =>
|
||||
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
||||
been rewritten"),
|
||||
Some(DefVariant(_, id, _)) => if *constructor == Variant(id) {
|
||||
|
@ -876,7 +880,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
ast::PatEnum(_, ref args) => {
|
||||
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
|
||||
match def {
|
||||
DefConst(..) =>
|
||||
DefConst(..) | DefAssociatedConst(..) =>
|
||||
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
||||
been rewritten"),
|
||||
DefVariant(_, id, _) if *constructor != Variant(id) => None,
|
||||
|
@ -890,11 +894,16 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
}
|
||||
}
|
||||
|
||||
ast::PatQPath(_, _) => {
|
||||
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
||||
been rewritten")
|
||||
}
|
||||
|
||||
ast::PatStruct(_, ref pattern_fields, _) => {
|
||||
// Is this a struct or an enum variant?
|
||||
let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def();
|
||||
let class_id = match def {
|
||||
DefConst(..) =>
|
||||
DefConst(..) | DefAssociatedConst(..) =>
|
||||
cx.tcx.sess.span_bug(pat_span, "const pattern should've \
|
||||
been rewritten"),
|
||||
DefVariant(_, variant_id, _) => if *constructor == Variant(variant_id) {
|
||||
|
|
|
@ -12,10 +12,11 @@
|
|||
// recursively.
|
||||
|
||||
use session::Session;
|
||||
use middle::def::{DefStatic, DefConst, DefMap};
|
||||
use middle::def::{DefStatic, DefConst, DefAssociatedConst, DefMap};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::{ast_util, ast_map};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::visit::Visitor;
|
||||
use syntax::visit;
|
||||
|
||||
|
@ -26,8 +27,43 @@ struct CheckCrateVisitor<'a, 'ast: 'a> {
|
|||
}
|
||||
|
||||
impl<'v, 'a, 'ast> Visitor<'v> for CheckCrateVisitor<'a, 'ast> {
|
||||
fn visit_item(&mut self, i: &ast::Item) {
|
||||
check_item(self, i);
|
||||
fn visit_item(&mut self, it: &ast::Item) {
|
||||
match it.node {
|
||||
ast::ItemStatic(_, _, ref expr) |
|
||||
ast::ItemConst(_, ref expr) => {
|
||||
let mut recursion_visitor =
|
||||
CheckItemRecursionVisitor::new(self, &it.span);
|
||||
recursion_visitor.visit_item(it);
|
||||
visit::walk_expr(self, &*expr)
|
||||
},
|
||||
_ => visit::walk_item(self, it)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
|
||||
match ti.node {
|
||||
ast::ConstTraitItem(_, ref default) => {
|
||||
if let Some(ref expr) = *default {
|
||||
let mut recursion_visitor =
|
||||
CheckItemRecursionVisitor::new(self, &ti.span);
|
||||
recursion_visitor.visit_trait_item(ti);
|
||||
visit::walk_expr(self, &*expr)
|
||||
}
|
||||
}
|
||||
_ => visit::walk_trait_item(self, ti)
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
|
||||
match ii.node {
|
||||
ast::ConstImplItem(_, ref expr) => {
|
||||
let mut recursion_visitor =
|
||||
CheckItemRecursionVisitor::new(self, &ii.span);
|
||||
recursion_visitor.visit_impl_item(ii);
|
||||
visit::walk_expr(self, &*expr)
|
||||
}
|
||||
_ => visit::walk_impl_item(self, ii)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,51 +80,48 @@ pub fn check_crate<'ast>(sess: &Session,
|
|||
sess.abort_if_errors();
|
||||
}
|
||||
|
||||
fn check_item(v: &mut CheckCrateVisitor, it: &ast::Item) {
|
||||
match it.node {
|
||||
ast::ItemStatic(_, _, ref ex) |
|
||||
ast::ItemConst(_, ref ex) => {
|
||||
check_item_recursion(v.sess, v.ast_map, v.def_map, it);
|
||||
visit::walk_expr(v, &**ex)
|
||||
},
|
||||
_ => visit::walk_item(v, it)
|
||||
}
|
||||
}
|
||||
|
||||
struct CheckItemRecursionVisitor<'a, 'ast: 'a> {
|
||||
root_it: &'a ast::Item,
|
||||
root_span: &'a Span,
|
||||
sess: &'a Session,
|
||||
ast_map: &'a ast_map::Map<'ast>,
|
||||
def_map: &'a DefMap,
|
||||
idstack: Vec<ast::NodeId>
|
||||
}
|
||||
|
||||
// Make sure a const item doesn't recursively refer to itself
|
||||
// FIXME: Should use the dependency graph when it's available (#1356)
|
||||
pub fn check_item_recursion<'a>(sess: &'a Session,
|
||||
ast_map: &'a ast_map::Map,
|
||||
def_map: &'a DefMap,
|
||||
it: &'a ast::Item) {
|
||||
|
||||
let mut visitor = CheckItemRecursionVisitor {
|
||||
root_it: it,
|
||||
sess: sess,
|
||||
ast_map: ast_map,
|
||||
def_map: def_map,
|
||||
idstack: Vec::new()
|
||||
};
|
||||
visitor.visit_item(it);
|
||||
impl<'a, 'ast: 'a> CheckItemRecursionVisitor<'a, 'ast> {
|
||||
fn new(v: &CheckCrateVisitor<'a, 'ast>, span: &'a Span)
|
||||
-> CheckItemRecursionVisitor<'a, 'ast> {
|
||||
CheckItemRecursionVisitor {
|
||||
root_span: span,
|
||||
sess: v.sess,
|
||||
ast_map: v.ast_map,
|
||||
def_map: v.def_map,
|
||||
idstack: Vec::new()
|
||||
}
|
||||
}
|
||||
fn with_item_id_pushed<F>(&mut self, id: ast::NodeId, f: F)
|
||||
where F: Fn(&mut Self) {
|
||||
if self.idstack.iter().any(|x| x == &(id)) {
|
||||
span_err!(self.sess, *self.root_span, E0265, "recursive constant");
|
||||
return;
|
||||
}
|
||||
self.idstack.push(id);
|
||||
f(self);
|
||||
self.idstack.pop();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
|
||||
fn visit_item(&mut self, it: &ast::Item) {
|
||||
if self.idstack.iter().any(|x| x == &(it.id)) {
|
||||
span_err!(self.sess, self.root_it.span, E0265, "recursive constant");
|
||||
return;
|
||||
}
|
||||
self.idstack.push(it.id);
|
||||
visit::walk_item(self, it);
|
||||
self.idstack.pop();
|
||||
self.with_item_id_pushed(it.id, |v| visit::walk_item(v, it));
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
|
||||
self.with_item_id_pushed(ti.id, |v| visit::walk_trait_item(v, ti));
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
|
||||
self.with_item_id_pushed(ii.id, |v| visit::walk_impl_item(v, ii));
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, e: &ast::Expr) {
|
||||
|
@ -96,11 +129,16 @@ impl<'a, 'ast, 'v> Visitor<'v> for CheckItemRecursionVisitor<'a, 'ast> {
|
|||
ast::ExprPath(..) => {
|
||||
match self.def_map.borrow().get(&e.id).map(|d| d.base_def) {
|
||||
Some(DefStatic(def_id, _)) |
|
||||
Some(DefAssociatedConst(def_id, _)) |
|
||||
Some(DefConst(def_id)) if
|
||||
ast_util::is_local(def_id) => {
|
||||
match self.ast_map.get(def_id.node) {
|
||||
ast_map::NodeItem(item) =>
|
||||
self.visit_item(item),
|
||||
ast_map::NodeTraitItem(item) =>
|
||||
self.visit_trait_item(item),
|
||||
ast_map::NodeImplItem(item) =>
|
||||
self.visit_impl_item(item),
|
||||
ast_map::NodeForeignItem(_) => {},
|
||||
_ => {
|
||||
span_err!(self.sess, e.span, E0266,
|
||||
|
|
|
@ -16,11 +16,12 @@ pub use self::const_val::*;
|
|||
use self::ErrKind::*;
|
||||
|
||||
use metadata::csearch;
|
||||
use middle::{astencode, def};
|
||||
use middle::{astencode, def, infer, subst, traits};
|
||||
use middle::pat_util::def_to_path;
|
||||
use middle::ty::{self, Ty};
|
||||
use middle::astconv_util::ast_ty_to_prim_ty;
|
||||
use util::num::ToPrimitive;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::ast::{self, Expr};
|
||||
use syntax::codemap::Span;
|
||||
|
@ -39,8 +40,9 @@ use std::rc::Rc;
|
|||
fn lookup_const<'a>(tcx: &'a ty::ctxt, e: &Expr) -> Option<&'a Expr> {
|
||||
let opt_def = tcx.def_map.borrow().get(&e.id).map(|d| d.full_def());
|
||||
match opt_def {
|
||||
Some(def::DefConst(def_id)) => {
|
||||
lookup_const_by_id(tcx, def_id)
|
||||
Some(def::DefConst(def_id)) |
|
||||
Some(def::DefAssociatedConst(def_id, _)) => {
|
||||
lookup_const_by_id(tcx, def_id, Some(e.id))
|
||||
}
|
||||
Some(def::DefVariant(enum_def, variant_def, _)) => {
|
||||
lookup_variant_by_id(tcx, enum_def, variant_def)
|
||||
|
@ -101,14 +103,46 @@ fn lookup_variant_by_id<'a>(tcx: &'a ty::ctxt,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
|
||||
-> Option<&'a Expr> {
|
||||
pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
|
||||
def_id: ast::DefId,
|
||||
maybe_ref_id: Option<ast::NodeId>)
|
||||
-> Option<&'tcx Expr> {
|
||||
if ast_util::is_local(def_id) {
|
||||
match tcx.map.find(def_id.node) {
|
||||
None => None,
|
||||
Some(ast_map::NodeItem(it)) => match it.node {
|
||||
ast::ItemConst(_, ref const_expr) => {
|
||||
Some(&**const_expr)
|
||||
Some(&*const_expr)
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
|
||||
ast::ConstTraitItem(_, _) => {
|
||||
match maybe_ref_id {
|
||||
// If we have a trait item, and we know the expression
|
||||
// that's the source of the obligation to resolve it,
|
||||
// `resolve_trait_associated_const` will select an impl
|
||||
// or the default.
|
||||
Some(ref_id) => {
|
||||
let trait_id = ty::trait_of_item(tcx, def_id)
|
||||
.unwrap();
|
||||
resolve_trait_associated_const(tcx, ti, trait_id,
|
||||
ref_id)
|
||||
}
|
||||
// Technically, without knowing anything about the
|
||||
// expression that generates the obligation, we could
|
||||
// still return the default if there is one. However,
|
||||
// it's safer to return `None` than to return some value
|
||||
// that may differ from what you would get from
|
||||
// correctly selecting an impl.
|
||||
None => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
Some(ast_map::NodeImplItem(ii)) => match ii.node {
|
||||
ast::ConstImplItem(_, ref expr) => {
|
||||
Some(&*expr)
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
|
@ -122,16 +156,44 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId)
|
|||
}
|
||||
None => {}
|
||||
}
|
||||
let mut used_ref_id = false;
|
||||
let expr_id = match csearch::maybe_get_item_ast(tcx, def_id,
|
||||
Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) {
|
||||
csearch::FoundAst::Found(&ast::IIItem(ref item)) => match item.node {
|
||||
ast::ItemConst(_, ref const_expr) => Some(const_expr.id),
|
||||
_ => None
|
||||
},
|
||||
csearch::FoundAst::Found(&ast::IITraitItem(trait_id, ref ti)) => match ti.node {
|
||||
ast::ConstTraitItem(_, _) => {
|
||||
used_ref_id = true;
|
||||
match maybe_ref_id {
|
||||
// As mentioned in the comments above for in-crate
|
||||
// constants, we only try to find the expression for
|
||||
// a trait-associated const if the caller gives us
|
||||
// the expression that refers to it.
|
||||
Some(ref_id) => {
|
||||
resolve_trait_associated_const(tcx, ti, trait_id,
|
||||
ref_id).map(|e| e.id)
|
||||
}
|
||||
None => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
csearch::FoundAst::Found(&ast::IIImplItem(_, ref ii)) => match ii.node {
|
||||
ast::ConstImplItem(_, ref expr) => Some(expr.id),
|
||||
_ => None
|
||||
},
|
||||
_ => None
|
||||
};
|
||||
tcx.extern_const_statics.borrow_mut().insert(def_id,
|
||||
expr_id.unwrap_or(ast::DUMMY_NODE_ID));
|
||||
// If we used the reference expression, particularly to choose an impl
|
||||
// of a trait-associated const, don't cache that, because the next
|
||||
// lookup with the same def_id may yield a different result.
|
||||
if !used_ref_id {
|
||||
tcx.extern_const_statics
|
||||
.borrow_mut().insert(def_id,
|
||||
expr_id.unwrap_or(ast::DUMMY_NODE_ID));
|
||||
}
|
||||
expr_id.map(|id| tcx.map.expect_expr(id))
|
||||
}
|
||||
}
|
||||
|
@ -755,7 +817,35 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
_ => (None, None)
|
||||
}
|
||||
} else {
|
||||
(lookup_const_by_id(tcx, def_id), None)
|
||||
(lookup_const_by_id(tcx, def_id, Some(e.id)), None)
|
||||
}
|
||||
}
|
||||
Some(def::DefAssociatedConst(def_id, provenance)) => {
|
||||
if ast_util::is_local(def_id) {
|
||||
match provenance {
|
||||
def::FromTrait(trait_id) => match tcx.map.find(def_id.node) {
|
||||
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
|
||||
ast::ConstTraitItem(ref ty, _) => {
|
||||
(resolve_trait_associated_const(tcx, ti,
|
||||
trait_id, e.id),
|
||||
Some(&**ty))
|
||||
}
|
||||
_ => (None, None)
|
||||
},
|
||||
_ => (None, None)
|
||||
},
|
||||
def::FromImpl(_) => match tcx.map.find(def_id.node) {
|
||||
Some(ast_map::NodeImplItem(ii)) => match ii.node {
|
||||
ast::ConstImplItem(ref ty, ref expr) => {
|
||||
(Some(&**expr), Some(&**ty))
|
||||
}
|
||||
_ => (None, None)
|
||||
},
|
||||
_ => (None, None)
|
||||
},
|
||||
}
|
||||
} else {
|
||||
(lookup_const_by_id(tcx, def_id, Some(e.id)), None)
|
||||
}
|
||||
}
|
||||
Some(def::DefVariant(enum_def, variant_def, _)) => {
|
||||
|
@ -833,6 +923,71 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
Ok(result)
|
||||
}
|
||||
|
||||
fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>,
|
||||
ti: &'tcx ast::TraitItem,
|
||||
trait_id: ast::DefId,
|
||||
ref_id: ast::NodeId)
|
||||
-> Option<&'tcx Expr>
|
||||
{
|
||||
let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs;
|
||||
let subst::SeparateVecsPerParamSpace {
|
||||
types: rcvr_type,
|
||||
selfs: rcvr_self,
|
||||
fns: _,
|
||||
} = rcvr_substs.types.split();
|
||||
let trait_substs =
|
||||
subst::Substs::erased(subst::VecPerParamSpace::new(rcvr_type,
|
||||
rcvr_self,
|
||||
Vec::new()));
|
||||
let trait_substs = tcx.mk_substs(trait_substs);
|
||||
debug!("resolve_trait_associated_const: trait_substs={}",
|
||||
trait_substs.repr(tcx));
|
||||
let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id,
|
||||
substs: trait_substs }));
|
||||
|
||||
ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id());
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
|
||||
let param_env = ty::empty_parameter_environment(tcx);
|
||||
let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env);
|
||||
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
|
||||
trait_ref.to_poly_trait_predicate());
|
||||
let selection = match selcx.select(&obligation) {
|
||||
Ok(Some(vtable)) => vtable,
|
||||
// Still ambiguous, so give up and let the caller decide whether this
|
||||
// expression is really needed yet. Some associated constant values
|
||||
// can't be evaluated until monomorphization is done in trans.
|
||||
Ok(None) => {
|
||||
return None
|
||||
}
|
||||
Err(e) => {
|
||||
tcx.sess.span_bug(ti.span,
|
||||
&format!("Encountered error `{}` when trying \
|
||||
to select an implementation for \
|
||||
constant trait item reference.",
|
||||
e.repr(tcx)))
|
||||
}
|
||||
};
|
||||
|
||||
match selection {
|
||||
traits::VtableImpl(ref impl_data) => {
|
||||
match ty::associated_consts(tcx, impl_data.impl_def_id)
|
||||
.iter().find(|ic| ic.name == ti.ident.name) {
|
||||
Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
|
||||
None => match ti.node {
|
||||
ast::ConstTraitItem(_, Some(ref expr)) => Some(&*expr),
|
||||
_ => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_bug(
|
||||
ti.span,
|
||||
&format!("resolve_trait_associated_const: unexpected vtable type"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult {
|
||||
macro_rules! convert_val {
|
||||
($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => {
|
||||
|
|
|
@ -72,7 +72,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) {
|
||||
self.tcx.def_map.borrow().get(id).map(|def| {
|
||||
match def.full_def() {
|
||||
def::DefConst(_) => {
|
||||
def::DefConst(_) | def::DefAssociatedConst(..) => {
|
||||
self.check_def_id(def.def_id())
|
||||
}
|
||||
_ if self.ignore_non_const_paths => (),
|
||||
|
@ -114,14 +114,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
|
|||
let trait_item = ty::trait_item(self.tcx,
|
||||
trait_ref.def_id,
|
||||
index);
|
||||
match trait_item {
|
||||
ty::MethodTraitItem(method) => {
|
||||
self.check_def_id(method.def_id);
|
||||
}
|
||||
ty::TypeTraitItem(typedef) => {
|
||||
self.check_def_id(typedef.def_id);
|
||||
}
|
||||
}
|
||||
self.check_def_id(trait_item.def_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -353,6 +346,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
|
|||
ast::ItemTrait(_, _, _, ref trait_items) => {
|
||||
for trait_item in trait_items {
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(_, Some(_)) |
|
||||
ast::MethodTraitItem(_, Some(_)) => {
|
||||
if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
|
||||
self.worklist.push(trait_item.id);
|
||||
|
@ -365,6 +359,7 @@ impl<'v> Visitor<'v> for LifeSeeder {
|
|||
ast::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => {
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(..) |
|
||||
ast::MethodImplItem(..) => {
|
||||
if opt_trait.is_some() ||
|
||||
has_allow_dead_code_or_lang_attr(&impl_item.attrs) {
|
||||
|
@ -406,7 +401,7 @@ fn create_and_seed_worklist(tcx: &ty::ctxt,
|
|||
None => ()
|
||||
}
|
||||
|
||||
// Seed implemented trait methods
|
||||
// Seed implemented trait items
|
||||
let mut life_seeder = LifeSeeder {
|
||||
worklist: worklist
|
||||
};
|
||||
|
@ -487,7 +482,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> {
|
|||
|ctor| self.live_symbols.contains(&ctor)) {
|
||||
return true;
|
||||
}
|
||||
// If it's a type whose methods are live, then it's live, too.
|
||||
// If it's a type whose items are live, then it's live, too.
|
||||
// This is done to handle the case where, for example, the static
|
||||
// method of a private type is used, but the type itself is never
|
||||
// called directly.
|
||||
|
@ -557,21 +552,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
|
|||
visit::walk_foreign_item(self, fi);
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self, fk: visit::FnKind<'v>,
|
||||
_: &'v ast::FnDecl, block: &'v ast::Block,
|
||||
span: codemap::Span, id: ast::NodeId) {
|
||||
// Have to warn method here because methods are not ast::Item
|
||||
match fk {
|
||||
visit::FkMethod(name, _, _) => {
|
||||
if !self.symbol_is_live(id, None) {
|
||||
self.warn_dead_code(id, span, name.name, "method");
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
visit::walk_block(self, block);
|
||||
}
|
||||
|
||||
fn visit_struct_field(&mut self, field: &ast::StructField) {
|
||||
if self.should_warn_about_field(&field.node) {
|
||||
self.warn_dead_code(field.node.id, field.span,
|
||||
|
@ -581,12 +561,37 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> {
|
|||
visit::walk_struct_field(self, field);
|
||||
}
|
||||
|
||||
// Overwrite so that we don't warn the trait method itself.
|
||||
fn visit_trait_item(&mut self, trait_method: &ast::TraitItem) {
|
||||
match trait_method.node {
|
||||
fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(_, ref expr) => {
|
||||
if !self.symbol_is_live(impl_item.id, None) {
|
||||
self.warn_dead_code(impl_item.id, impl_item.span,
|
||||
impl_item.ident.name, "associated const");
|
||||
}
|
||||
visit::walk_expr(self, expr)
|
||||
}
|
||||
ast::MethodImplItem(_, ref body) => {
|
||||
if !self.symbol_is_live(impl_item.id, None) {
|
||||
self.warn_dead_code(impl_item.id, impl_item.span,
|
||||
impl_item.ident.name, "method");
|
||||
}
|
||||
visit::walk_block(self, body)
|
||||
}
|
||||
ast::TypeImplItem(..) |
|
||||
ast::MacImplItem(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Overwrite so that we don't warn the trait item itself.
|
||||
fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(_, Some(ref expr)) => {
|
||||
visit::walk_expr(self, expr)
|
||||
}
|
||||
ast::MethodTraitItem(_, Some(ref body)) => {
|
||||
visit::walk_block(self, body)
|
||||
}
|
||||
ast::ConstTraitItem(_, None) |
|
||||
ast::MethodTraitItem(_, None) |
|
||||
ast::TypeTraitItem(..) => {}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ pub enum Def {
|
|||
DefForeignMod(ast::DefId),
|
||||
DefStatic(ast::DefId, bool /* is_mutbl */),
|
||||
DefConst(ast::DefId),
|
||||
DefAssociatedConst(ast::DefId /* const */, MethodProvenance),
|
||||
DefLocal(ast::NodeId),
|
||||
DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */),
|
||||
DefTy(ast::DefId, bool /* is_enum */),
|
||||
|
@ -140,7 +141,8 @@ impl Def {
|
|||
DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) |
|
||||
DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) |
|
||||
DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) |
|
||||
DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> {
|
||||
DefMethod(id, _) | DefConst(id) | DefAssociatedConst(id, _) |
|
||||
DefSelfTy(Some(id), None)=> {
|
||||
id
|
||||
}
|
||||
DefLocal(id) |
|
||||
|
|
|
@ -234,7 +234,7 @@ impl OverloadedCallType {
|
|||
ty::MethodTraitItem(ref method_descriptor) => {
|
||||
(*method_descriptor).clone()
|
||||
}
|
||||
ty::TypeTraitItem(_) => {
|
||||
_ => {
|
||||
tcx.sess.bug("overloaded call method wasn't in method map")
|
||||
}
|
||||
};
|
||||
|
@ -1147,7 +1147,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
let tcx = typer.tcx();
|
||||
|
||||
match pat.node {
|
||||
ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
|
||||
ast::PatEnum(_, _) | ast::PatQPath(..) |
|
||||
ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
|
||||
match def_map.get(&pat.id).map(|d| d.full_def()) {
|
||||
None => {
|
||||
// no definition found: pat is not a
|
||||
|
@ -1183,6 +1184,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||
}
|
||||
|
||||
Some(def::DefConst(..)) |
|
||||
Some(def::DefAssociatedConst(..)) |
|
||||
Some(def::DefLocal(..)) => {
|
||||
// This is a leaf (i.e. identifier binding
|
||||
// or constant value to match); thus no
|
||||
|
|
|
@ -843,8 +843,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
|
|||
Some(&sig.explicit_self.node),
|
||||
item.span))
|
||||
}
|
||||
ast::TypeImplItem(_) => None,
|
||||
ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro")
|
||||
ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"),
|
||||
_ => None,
|
||||
}
|
||||
},
|
||||
ast_map::NodeTraitItem(item) => {
|
||||
|
@ -1723,8 +1723,8 @@ fn lifetimes_in_scope(tcx: &ty::ctxt,
|
|||
taken.push_all(&sig.generics.lifetimes);
|
||||
Some(ii.id)
|
||||
}
|
||||
ast::TypeImplItem(_) => None,
|
||||
ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro")
|
||||
ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
|
|
|
@ -589,7 +589,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
|
||||
match def {
|
||||
def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
|
||||
def::DefFn(..) | def::DefMethod(..) => {
|
||||
def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => {
|
||||
Ok(self.cat_rvalue_node(id, span, expr_ty))
|
||||
}
|
||||
def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
|
||||
|
@ -1286,7 +1286,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
try!(self.cat_pattern_(cmt_field, &**subpat, op));
|
||||
}
|
||||
}
|
||||
Some(def::DefConst(..)) => {
|
||||
Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => {
|
||||
for subpat in subpats {
|
||||
try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
|
||||
}
|
||||
|
@ -1299,6 +1299,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
|
|||
}
|
||||
}
|
||||
|
||||
ast::PatQPath(..) => {
|
||||
// Lone constant: ignore
|
||||
}
|
||||
|
||||
ast::PatIdent(_, _, Some(ref subpat)) => {
|
||||
try!(self.cat_pattern_(cmt, &**subpat, op));
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap {
|
|||
|
||||
pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||
match pat.node {
|
||||
ast::PatLit(_) | ast::PatRange(_, _) => true,
|
||||
ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true,
|
||||
ast::PatEnum(_, _) |
|
||||
ast::PatIdent(_, _, None) |
|
||||
ast::PatStruct(..) => {
|
||||
|
@ -60,9 +60,25 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool {
|
|||
|
||||
pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||
match pat.node {
|
||||
ast::PatIdent(_, _, None) | ast::PatEnum(..) => {
|
||||
ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
|
||||
match dm.borrow().get(&pat.id).map(|d| d.full_def()) {
|
||||
Some(DefConst(..)) => true,
|
||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
// Same as above, except that partially-resolved defs cause `false` to be
|
||||
// returned instead of a panic.
|
||||
pub fn pat_is_resolved_const(dm: &DefMap, pat: &ast::Pat) -> bool {
|
||||
match pat.node {
|
||||
ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => {
|
||||
match dm.borrow().get(&pat.id)
|
||||
.and_then(|d| if d.depth == 0 { Some(d.base_def) }
|
||||
else { None } ) {
|
||||
Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> {
|
|||
// If this path leads to a constant, then we need to
|
||||
// recurse into the constant to continue finding
|
||||
// items that are reachable.
|
||||
def::DefConst(..) => {
|
||||
def::DefConst(..) | def::DefAssociatedConst(..) => {
|
||||
self.worklist.push(def_id.node);
|
||||
}
|
||||
|
||||
|
@ -183,12 +183,14 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
}
|
||||
Some(ast_map::NodeTraitItem(trait_method)) => {
|
||||
match trait_method.node {
|
||||
ast::ConstTraitItem(_, ref default) => default.is_some(),
|
||||
ast::MethodTraitItem(_, ref body) => body.is_some(),
|
||||
ast::TypeTraitItem(..) => false,
|
||||
}
|
||||
}
|
||||
Some(ast_map::NodeImplItem(impl_item)) => {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(..) => true,
|
||||
ast::MethodImplItem(ref sig, _) => {
|
||||
if generics_require_inlining(&sig.generics) ||
|
||||
attr::requests_inline(&impl_item.attrs) {
|
||||
|
@ -303,9 +305,13 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
}
|
||||
ast_map::NodeTraitItem(trait_method) => {
|
||||
match trait_method.node {
|
||||
ast::ConstTraitItem(_, None) |
|
||||
ast::MethodTraitItem(_, None) => {
|
||||
// Keep going, nothing to get exported
|
||||
}
|
||||
ast::ConstTraitItem(_, Some(ref expr)) => {
|
||||
self.visit_expr(&*expr);
|
||||
}
|
||||
ast::MethodTraitItem(_, Some(ref body)) => {
|
||||
visit::walk_block(self, body);
|
||||
}
|
||||
|
@ -314,6 +320,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
|
|||
}
|
||||
ast_map::NodeImplItem(impl_item) => {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(_, ref expr) => {
|
||||
self.visit_expr(&*expr);
|
||||
}
|
||||
ast::MethodImplItem(ref sig, ref body) => {
|
||||
let did = self.tcx.map.get_parent_did(search_item);
|
||||
if method_might_be_inlined(self.tcx, sig, impl_item, did) {
|
||||
|
|
|
@ -100,9 +100,7 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
.map(|code| ObjectSafetyViolation::Method(m.clone(), code))
|
||||
.into_iter()
|
||||
}
|
||||
ty::TypeTraitItem(_) => {
|
||||
None.into_iter()
|
||||
}
|
||||
_ => None.into_iter(),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
|
|
@ -863,7 +863,7 @@ fn confirm_impl_candidate<'cx,'tcx>(
|
|||
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::MethodTraitItem(..) => { continue; }
|
||||
ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; }
|
||||
};
|
||||
|
||||
if assoc_type.name != obligation.predicate.item_name {
|
||||
|
|
|
@ -434,7 +434,7 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
for trait_item in &**trait_items {
|
||||
match *trait_item {
|
||||
ty::MethodTraitItem(_) => method_count += 1,
|
||||
ty::TypeTraitItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -445,14 +445,14 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
for trait_item in trait_items.iter().take(method_offset_in_trait) {
|
||||
match *trait_item {
|
||||
ty::MethodTraitItem(_) => method_count += 1,
|
||||
ty::TypeTraitItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// the item at the offset we were given really ought to be a method
|
||||
assert!(match trait_items[method_offset_in_trait] {
|
||||
ty::MethodTraitItem(_) => true,
|
||||
ty::TypeTraitItem(_) => false
|
||||
_ => false
|
||||
});
|
||||
|
||||
method_count
|
||||
|
|
|
@ -80,7 +80,7 @@ use std::vec::IntoIter;
|
|||
use collections::enum_set::{EnumSet, CLike};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use syntax::abi;
|
||||
use syntax::ast::{CrateNum, DefId, ItemTrait, LOCAL_CRATE};
|
||||
use syntax::ast::{CrateNum, DefId, ItemImpl, ItemTrait, LOCAL_CRATE};
|
||||
use syntax::ast::{MutImmutable, MutMutable, Name, NamedField, NodeId};
|
||||
use syntax::ast::{StmtExpr, StmtSemi, StructField, UnnamedField, Visibility};
|
||||
use syntax::ast_util::{self, is_local, lit_is_str, local_def};
|
||||
|
@ -133,6 +133,7 @@ impl ImplOrTraitItemContainer {
|
|||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ImplOrTraitItem<'tcx> {
|
||||
ConstTraitItem(Rc<AssociatedConst<'tcx>>),
|
||||
MethodTraitItem(Rc<Method<'tcx>>),
|
||||
TypeTraitItem(Rc<AssociatedType>),
|
||||
}
|
||||
|
@ -140,6 +141,9 @@ pub enum ImplOrTraitItem<'tcx> {
|
|||
impl<'tcx> ImplOrTraitItem<'tcx> {
|
||||
fn id(&self) -> ImplOrTraitItemId {
|
||||
match *self {
|
||||
ConstTraitItem(ref associated_const) => {
|
||||
ConstTraitItemId(associated_const.def_id)
|
||||
}
|
||||
MethodTraitItem(ref method) => MethodTraitItemId(method.def_id),
|
||||
TypeTraitItem(ref associated_type) => {
|
||||
TypeTraitItemId(associated_type.def_id)
|
||||
|
@ -149,6 +153,7 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
|
|||
|
||||
pub fn def_id(&self) -> ast::DefId {
|
||||
match *self {
|
||||
ConstTraitItem(ref associated_const) => associated_const.def_id,
|
||||
MethodTraitItem(ref method) => method.def_id,
|
||||
TypeTraitItem(ref associated_type) => associated_type.def_id,
|
||||
}
|
||||
|
@ -156,13 +161,23 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
|
|||
|
||||
pub fn name(&self) -> ast::Name {
|
||||
match *self {
|
||||
ConstTraitItem(ref associated_const) => associated_const.name,
|
||||
MethodTraitItem(ref method) => method.name,
|
||||
TypeTraitItem(ref associated_type) => associated_type.name,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn vis(&self) -> ast::Visibility {
|
||||
match *self {
|
||||
ConstTraitItem(ref associated_const) => associated_const.vis,
|
||||
MethodTraitItem(ref method) => method.vis,
|
||||
TypeTraitItem(ref associated_type) => associated_type.vis,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn container(&self) -> ImplOrTraitItemContainer {
|
||||
match *self {
|
||||
ConstTraitItem(ref associated_const) => associated_const.container,
|
||||
MethodTraitItem(ref method) => method.container,
|
||||
TypeTraitItem(ref associated_type) => associated_type.container,
|
||||
}
|
||||
|
@ -171,13 +186,14 @@ impl<'tcx> ImplOrTraitItem<'tcx> {
|
|||
pub fn as_opt_method(&self) -> Option<Rc<Method<'tcx>>> {
|
||||
match *self {
|
||||
MethodTraitItem(ref m) => Some((*m).clone()),
|
||||
TypeTraitItem(_) => None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ImplOrTraitItemId {
|
||||
ConstTraitItemId(ast::DefId),
|
||||
MethodTraitItemId(ast::DefId),
|
||||
TypeTraitItemId(ast::DefId),
|
||||
}
|
||||
|
@ -185,6 +201,7 @@ pub enum ImplOrTraitItemId {
|
|||
impl ImplOrTraitItemId {
|
||||
pub fn def_id(&self) -> ast::DefId {
|
||||
match *self {
|
||||
ConstTraitItemId(def_id) => def_id,
|
||||
MethodTraitItemId(def_id) => def_id,
|
||||
TypeTraitItemId(def_id) => def_id,
|
||||
}
|
||||
|
@ -238,6 +255,16 @@ impl<'tcx> Method<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct AssociatedConst<'tcx> {
|
||||
pub name: ast::Name,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub vis: ast::Visibility,
|
||||
pub def_id: ast::DefId,
|
||||
pub container: ImplOrTraitItemContainer,
|
||||
pub default: Option<ast::DefId>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct AssociatedType {
|
||||
pub name: ast::Name,
|
||||
|
@ -2291,6 +2318,16 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
|
|||
match cx.map.find(id) {
|
||||
Some(ast_map::NodeImplItem(ref impl_item)) => {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(_, _) => {
|
||||
let def_id = ast_util::local_def(id);
|
||||
let scheme = lookup_item_type(cx, def_id);
|
||||
let predicates = lookup_predicates(cx, def_id);
|
||||
construct_parameter_environment(cx,
|
||||
impl_item.span,
|
||||
&scheme.generics,
|
||||
&predicates,
|
||||
id)
|
||||
}
|
||||
ast::MethodImplItem(_, ref body) => {
|
||||
let method_def_id = ast_util::local_def(id);
|
||||
match ty::impl_or_trait_item(cx, method_def_id) {
|
||||
|
@ -2304,11 +2341,10 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
|
|||
method_bounds,
|
||||
body.id)
|
||||
}
|
||||
TypeTraitItem(_) => {
|
||||
_ => {
|
||||
cx.sess
|
||||
.bug("ParameterEnvironment::for_item(): \
|
||||
can't create a parameter environment \
|
||||
for type trait items")
|
||||
got non-method item from impl method?!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2322,6 +2358,25 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
|
|||
}
|
||||
Some(ast_map::NodeTraitItem(trait_item)) => {
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(_, ref default) => {
|
||||
match *default {
|
||||
Some(_) => {
|
||||
let def_id = ast_util::local_def(id);
|
||||
let scheme = lookup_item_type(cx, def_id);
|
||||
let predicates = lookup_predicates(cx, def_id);
|
||||
construct_parameter_environment(cx,
|
||||
trait_item.span,
|
||||
&scheme.generics,
|
||||
&predicates,
|
||||
id)
|
||||
}
|
||||
None => {
|
||||
cx.sess.bug("ParameterEnvironment::from_item(): \
|
||||
can't create a parameter environment \
|
||||
for const trait items without defaults")
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::MethodTraitItem(_, None) => {
|
||||
cx.sess.span_bug(trait_item.span,
|
||||
"ParameterEnvironment::for_item():
|
||||
|
@ -2342,11 +2397,11 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
|
|||
method_bounds,
|
||||
body.id)
|
||||
}
|
||||
TypeTraitItem(_) => {
|
||||
_ => {
|
||||
cx.sess
|
||||
.bug("ParameterEnvironment::for_item(): \
|
||||
can't create a parameter environment \
|
||||
for type trait items")
|
||||
got non-method item from provided \
|
||||
method?!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4719,7 +4774,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
|||
def::DefUpvar(..) |
|
||||
def::DefLocal(..) => LvalueExpr,
|
||||
|
||||
def::DefConst(..) => RvalueDatumExpr,
|
||||
def::DefConst(..) |
|
||||
def::DefAssociatedConst(..) => RvalueDatumExpr,
|
||||
|
||||
def => {
|
||||
tcx.sess.span_bug(
|
||||
|
@ -5070,10 +5126,10 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
|||
if let ast::MethodTraitItem(_, Some(_)) = ti.node {
|
||||
match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
|
||||
MethodTraitItem(m) => Some(m),
|
||||
TypeTraitItem(_) => {
|
||||
_ => {
|
||||
cx.sess.bug("provided_trait_methods(): \
|
||||
associated type found from \
|
||||
looking up ProvidedMethod?!")
|
||||
non-method item found from \
|
||||
looking up provided method?!")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -5088,6 +5144,52 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
|||
}
|
||||
}
|
||||
|
||||
pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId)
|
||||
-> Vec<Rc<AssociatedConst<'tcx>>> {
|
||||
if is_local(id) {
|
||||
match cx.map.expect_item(id.node).node {
|
||||
ItemTrait(_, _, _, ref tis) => {
|
||||
tis.iter().filter_map(|ti| {
|
||||
if let ast::ConstTraitItem(_, _) = ti.node {
|
||||
match impl_or_trait_item(cx, ast_util::local_def(ti.id)) {
|
||||
ConstTraitItem(ac) => Some(ac),
|
||||
_ => {
|
||||
cx.sess.bug("associated_consts(): \
|
||||
non-const item found from \
|
||||
looking up a constant?!")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
ItemImpl(_, _, _, _, _, ref iis) => {
|
||||
iis.iter().filter_map(|ii| {
|
||||
if let ast::ConstImplItem(_, _) = ii.node {
|
||||
match impl_or_trait_item(cx, ast_util::local_def(ii.id)) {
|
||||
ConstTraitItem(ac) => Some(ac),
|
||||
_ => {
|
||||
cx.sess.bug("associated_consts(): \
|
||||
non-const item found from \
|
||||
looking up a constant?!")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
_ => {
|
||||
cx.sess.bug(&format!("associated_consts: `{:?}` is not a trait \
|
||||
or impl", id))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
csearch::get_associated_consts(cx, id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper for looking things up in the various maps that are populated during
|
||||
/// typeck::collect (e.g., `cx.impl_or_trait_items`, `cx.tcache`, etc). All of
|
||||
/// these share the pattern that if the id is local, it should have been loaded
|
||||
|
@ -5174,7 +5276,7 @@ pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool {
|
|||
Some(ref item) => {
|
||||
match **item {
|
||||
TypeTraitItem(_) => true,
|
||||
MethodTraitItem(_) => false,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
None => false,
|
||||
|
@ -6188,7 +6290,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt,
|
|||
.insert(method_def_id, source);
|
||||
}
|
||||
}
|
||||
TypeTraitItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6240,7 +6342,7 @@ pub fn populate_implementations_for_trait_if_necessary(
|
|||
.insert(method_def_id, source);
|
||||
}
|
||||
}
|
||||
TypeTraitItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -830,6 +830,7 @@ impl<'tcx> Repr<'tcx> for ty::TraitDef<'tcx> {
|
|||
impl<'tcx> Repr<'tcx> for ast::TraitItem {
|
||||
fn repr(&self, _tcx: &ctxt) -> String {
|
||||
let kind = match self.node {
|
||||
ast::ConstTraitItem(..) => "ConstTraitItem",
|
||||
ast::MethodTraitItem(..) => "MethodTraitItem",
|
||||
ast::TypeTraitItem(..) => "TypeTraitItem",
|
||||
};
|
||||
|
@ -1054,9 +1055,39 @@ impl<'tcx> Repr<'tcx> for ty::Variance {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::ImplOrTraitItem<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("ImplOrTraitItem({})",
|
||||
match *self {
|
||||
ty::ImplOrTraitItem::MethodTraitItem(ref i) => i.repr(tcx),
|
||||
ty::ImplOrTraitItem::ConstTraitItem(ref i) => i.repr(tcx),
|
||||
ty::ImplOrTraitItem::TypeTraitItem(ref i) => i.repr(tcx),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("AssociatedConst(name: {}, ty: {}, vis: {}, def_id: {})",
|
||||
self.name.repr(tcx),
|
||||
self.ty.repr(tcx),
|
||||
self.vis.repr(tcx),
|
||||
self.def_id.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::AssociatedType {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("AssociatedType(name: {}, vis: {}, def_id: {})",
|
||||
self.name.repr(tcx),
|
||||
self.vis.repr(tcx),
|
||||
self.def_id.repr(tcx))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Repr<'tcx> for ty::Method<'tcx> {
|
||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||
format!("method(name: {}, generics: {}, predicates: {}, fty: {}, \
|
||||
format!("Method(name: {}, generics: {}, predicates: {}, fty: {}, \
|
||||
explicit_self: {}, vis: {}, def_id: {})",
|
||||
self.name.repr(tcx),
|
||||
self.generics.repr(tcx),
|
||||
|
|
|
@ -77,6 +77,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for BorrowckCtxt<'a, 'tcx> {
|
|||
fn visit_item(&mut self, item: &ast::Item) {
|
||||
borrowck_item(self, item);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
|
||||
if let ast::ConstTraitItem(_, Some(ref expr)) = ti.node {
|
||||
gather_loans::gather_loans_in_static_initializer(self, &*expr);
|
||||
}
|
||||
visit::walk_trait_item(self, ti);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
|
||||
if let ast::ConstImplItem(_, ref expr) = ii.node {
|
||||
gather_loans::gather_loans_in_static_initializer(self, &*expr);
|
||||
}
|
||||
visit::walk_impl_item(self, ii);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_crate(tcx: &ty::ctxt) {
|
||||
|
|
|
@ -35,6 +35,7 @@ use syntax::codemap;
|
|||
use syntax::fold::{self, Folder};
|
||||
use syntax::print::{pp, pprust};
|
||||
use syntax::ptr::P;
|
||||
use syntax::util::small_vector::SmallVector;
|
||||
|
||||
use graphviz as dot;
|
||||
|
||||
|
@ -475,6 +476,29 @@ impl fold::Folder for ReplaceBodyWithLoop {
|
|||
}
|
||||
}
|
||||
|
||||
fn fold_trait_item(&mut self, i: P<ast::TraitItem>) -> SmallVector<P<ast::TraitItem>> {
|
||||
match i.node {
|
||||
ast::ConstTraitItem(..) => {
|
||||
self.within_static_or_const = true;
|
||||
let ret = fold::noop_fold_trait_item(i, self);
|
||||
self.within_static_or_const = false;
|
||||
return ret;
|
||||
}
|
||||
_ => fold::noop_fold_trait_item(i, self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_impl_item(&mut self, i: P<ast::ImplItem>) -> SmallVector<P<ast::ImplItem>> {
|
||||
match i.node {
|
||||
ast::ConstImplItem(..) => {
|
||||
self.within_static_or_const = true;
|
||||
let ret = fold::noop_fold_impl_item(i, self);
|
||||
self.within_static_or_const = false;
|
||||
return ret;
|
||||
}
|
||||
_ => fold::noop_fold_impl_item(i, self),
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
|
||||
fn expr_to_block(rules: ast::BlockCheckMode,
|
||||
|
|
|
@ -1068,6 +1068,26 @@ impl LintPass for NonUpperCaseGlobals {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_trait_item(&mut self, cx: &Context, ti: &ast::TraitItem) {
|
||||
match ti.node {
|
||||
ast::ConstTraitItem(..) => {
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
|
||||
ti.ident, ti.span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_impl_item(&mut self, cx: &Context, ii: &ast::ImplItem) {
|
||||
match ii.node {
|
||||
ast::ConstImplItem(..) => {
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
|
||||
ii.ident, ii.span);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_pat(&mut self, cx: &Context, p: &ast::Pat) {
|
||||
// Lint for constants that look like binding identifiers (#7526)
|
||||
match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
|
||||
|
@ -1584,8 +1604,9 @@ impl LintPass for MissingDoc {
|
|||
if self.private_traits.contains(&trait_item.id) { return }
|
||||
|
||||
let desc = match trait_item.node {
|
||||
ast::ConstTraitItem(..) => "an associated constant",
|
||||
ast::MethodTraitItem(..) => "a trait method",
|
||||
ast::TypeTraitItem(..) => "an associated type"
|
||||
ast::TypeTraitItem(..) => "an associated type",
|
||||
};
|
||||
|
||||
self.check_missing_docs_attrs(cx, Some(trait_item.id),
|
||||
|
@ -1600,9 +1621,10 @@ impl LintPass for MissingDoc {
|
|||
}
|
||||
|
||||
let desc = match impl_item.node {
|
||||
ast::ConstImplItem(..) => "an associated constant",
|
||||
ast::MethodImplItem(..) => "a method",
|
||||
ast::TypeImplItem(_) => "an associated type",
|
||||
ast::MacImplItem(_) => "an impl item macro"
|
||||
ast::MacImplItem(_) => "an impl item macro",
|
||||
};
|
||||
self.check_missing_docs_attrs(cx, Some(impl_item.id),
|
||||
&impl_item.attrs,
|
||||
|
|
|
@ -119,6 +119,15 @@ impl<'v> Visitor<'v> for ParentVisitor {
|
|||
visit::walk_fn(self, a, b, c, d);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
|
||||
// visit_fn handles methods, but associated consts have to be handled
|
||||
// here.
|
||||
if !self.parents.contains_key(&ii.id) {
|
||||
self.parents.insert(ii.id, self.curparent);
|
||||
}
|
||||
visit::walk_impl_item(self, ii);
|
||||
}
|
||||
|
||||
fn visit_struct_def(&mut self, s: &ast::StructDef, _: ast::Ident,
|
||||
_: &'v ast::Generics, n: ast::NodeId) {
|
||||
// Struct constructors are parented to their struct definitions because
|
||||
|
@ -272,6 +281,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
|
|||
if public_ty || public_trait {
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(..) => {
|
||||
if (public_ty && impl_item.vis == ast::Public)
|
||||
|| tr.is_some() {
|
||||
self.exported_items.insert(impl_item.id);
|
||||
}
|
||||
}
|
||||
ast::MethodImplItem(ref sig, _) => {
|
||||
let meth_public = match sig.explicit_self.node {
|
||||
ast::SelfStatic => public_ty,
|
||||
|
@ -399,6 +414,33 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
|||
debug!("privacy - is {:?} a public method", did);
|
||||
|
||||
return match self.tcx.impl_or_trait_items.borrow().get(&did) {
|
||||
Some(&ty::ConstTraitItem(ref ac)) => {
|
||||
debug!("privacy - it's a const: {:?}", *ac);
|
||||
match ac.container {
|
||||
ty::TraitContainer(id) => {
|
||||
debug!("privacy - recursing on trait {:?}", id);
|
||||
self.def_privacy(id)
|
||||
}
|
||||
ty::ImplContainer(id) => {
|
||||
match ty::impl_trait_ref(self.tcx, id) {
|
||||
Some(t) => {
|
||||
debug!("privacy - impl of trait {:?}", id);
|
||||
self.def_privacy(t.def_id)
|
||||
}
|
||||
None => {
|
||||
debug!("privacy - found inherent \
|
||||
associated constant {:?}",
|
||||
ac.vis);
|
||||
if ac.vis == ast::Public {
|
||||
Allowable
|
||||
} else {
|
||||
ExternallyDenied
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(&ty::MethodTraitItem(ref meth)) => {
|
||||
debug!("privacy - well at least it's a method: {:?}",
|
||||
*meth);
|
||||
|
@ -490,6 +532,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
|||
// where the method was defined?
|
||||
Some(ast_map::NodeImplItem(ii)) => {
|
||||
match ii.node {
|
||||
ast::ConstImplItem(..) |
|
||||
ast::MethodImplItem(..) => {
|
||||
let imp = self.tcx.map
|
||||
.get_parent_did(closest_private_id);
|
||||
|
@ -693,7 +736,11 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
|||
ty::MethodTraitItem(method_type) => {
|
||||
method_type.provided_source.unwrap_or(method_id)
|
||||
}
|
||||
ty::TypeTraitItem(_) => method_id,
|
||||
_ => {
|
||||
self.tcx.sess
|
||||
.span_bug(span,
|
||||
"got non-method item in check_static_method")
|
||||
}
|
||||
};
|
||||
|
||||
let string = token::get_name(name);
|
||||
|
@ -787,6 +834,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
|
|||
def::DefFn(..) => ck("function"),
|
||||
def::DefStatic(..) => ck("static"),
|
||||
def::DefConst(..) => ck("const"),
|
||||
def::DefAssociatedConst(..) => ck("associated const"),
|
||||
def::DefVariant(..) => ck("variant"),
|
||||
def::DefTy(_, false) => ck("type"),
|
||||
def::DefTy(_, true) => ck("enum"),
|
||||
|
@ -1128,8 +1176,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
|
|||
ast::MethodImplItem(..) => {
|
||||
check_inherited(tcx, impl_item.span, impl_item.vis);
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1307,6 +1354,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||
impl_items.iter()
|
||||
.any(|impl_item| {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(..) |
|
||||
ast::MethodImplItem(..) => {
|
||||
self.exported_items.contains(&impl_item.id)
|
||||
}
|
||||
|
@ -1330,6 +1378,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||
// don't erroneously report errors for private
|
||||
// types in private items.
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(..) |
|
||||
ast::MethodImplItem(..)
|
||||
if self.item_is_public(&impl_item.id, impl_item.vis) =>
|
||||
{
|
||||
|
@ -1360,12 +1409,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||
|
||||
// Those in 3. are warned with this call.
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::TypeImplItem(ref ty) => {
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
ast::MethodImplItem(..) |
|
||||
ast::MacImplItem(_) => {},
|
||||
if let ast::TypeImplItem(ref ty) = impl_item.node {
|
||||
self.visit_ty(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1376,15 +1421,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> {
|
|||
let mut found_pub_static = false;
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::MethodImplItem(ref sig, _) => {
|
||||
if sig.explicit_self.node == ast::SelfStatic &&
|
||||
self.item_is_public(&impl_item.id, impl_item.vis) {
|
||||
ast::ConstImplItem(..) => {
|
||||
if self.item_is_public(&impl_item.id, impl_item.vis) {
|
||||
found_pub_static = true;
|
||||
visit::walk_impl_item(self, impl_item);
|
||||
}
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => {}
|
||||
ast::MethodImplItem(ref sig, _) => {
|
||||
if sig.explicit_self.node == ast::SelfStatic &&
|
||||
self.item_is_public(&impl_item.id, impl_item.vis) {
|
||||
found_pub_static = true;
|
||||
visit::walk_impl_item(self, impl_item);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if found_pub_static {
|
||||
|
|
|
@ -530,6 +530,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||
trait_item.span);
|
||||
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(..) => {
|
||||
let def = DefAssociatedConst(local_def(trait_item.id),
|
||||
FromTrait(local_def(item.id)));
|
||||
// NB: not IMPORTABLE
|
||||
name_bindings.define_value(def, trait_item.span, PUBLIC);
|
||||
}
|
||||
ast::MethodTraitItem(..) => {
|
||||
let def = DefMethod(local_def(trait_item.id),
|
||||
FromTrait(local_def(item.id)));
|
||||
|
@ -703,7 +709,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> {
|
|||
csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id)
|
||||
.map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers);
|
||||
}
|
||||
DefFn(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => {
|
||||
DefFn(..) | DefStatic(..) | DefConst(..) | DefAssociatedConst(..) |
|
||||
DefMethod(..) => {
|
||||
debug!("(building reduced graph for external \
|
||||
crate) building value (fn/static) {}", final_ident);
|
||||
// impl methods have already been defined with the correct importability modifier
|
||||
|
|
|
@ -41,6 +41,7 @@ use self::TypeParameters::*;
|
|||
use self::RibKind::*;
|
||||
use self::UseLexicalScopeFlag::*;
|
||||
use self::ModulePrefixResult::*;
|
||||
use self::AssocItemResolveResult::*;
|
||||
use self::NameSearchType::*;
|
||||
use self::BareIdentifierPatternResolution::*;
|
||||
use self::ParentLink::*;
|
||||
|
@ -60,7 +61,8 @@ use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap};
|
|||
use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap};
|
||||
use rustc::util::lev_distance::lev_distance;
|
||||
|
||||
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum};
|
||||
use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block};
|
||||
use syntax::ast::{ConstImplItem, Crate, CrateNum};
|
||||
use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField};
|
||||
use syntax::ast::{ExprLoop, ExprWhile, ExprMethodCall};
|
||||
use syntax::ast::{ExprPath, ExprStruct, FnDecl};
|
||||
|
@ -69,7 +71,7 @@ use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate};
|
|||
use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl};
|
||||
use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse};
|
||||
use syntax::ast::{Local, MethodImplItem, Name, NodeId};
|
||||
use syntax::ast::{Pat, PatEnum, PatIdent, PatLit};
|
||||
use syntax::ast::{Pat, PatEnum, PatIdent, PatLit, PatQPath};
|
||||
use syntax::ast::{PatRange, PatStruct, Path, PrimTy};
|
||||
use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32};
|
||||
use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt};
|
||||
|
@ -330,6 +332,15 @@ enum ModulePrefixResult {
|
|||
PrefixFound(Rc<Module>, usize)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum AssocItemResolveResult {
|
||||
/// Syntax such as `<T>::item`, which can't be resolved until type
|
||||
/// checking.
|
||||
TypecheckRequired,
|
||||
/// We should have been able to resolve the associated item.
|
||||
ResolveAttempt(Option<PathResolution>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
enum NameSearchType {
|
||||
/// We're doing a name search in order to resolve a `use` directive.
|
||||
|
@ -1830,21 +1841,36 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
//
|
||||
// FIXME #4951: Do we need a node ID here?
|
||||
|
||||
let type_parameters = match trait_item.node {
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(_, ref default) => {
|
||||
// Only impose the restrictions of
|
||||
// ConstRibKind if there's an actual constant
|
||||
// expression in a provided default.
|
||||
if default.is_some() {
|
||||
this.with_constant_rib(|this| {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
});
|
||||
} else {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
}
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, _) => {
|
||||
HasTypeParameters(&sig.generics,
|
||||
FnSpace,
|
||||
MethodRibKind)
|
||||
let type_parameters =
|
||||
HasTypeParameters(&sig.generics,
|
||||
FnSpace,
|
||||
MethodRibKind);
|
||||
this.with_type_parameter_rib(type_parameters, |this| {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
});
|
||||
}
|
||||
ast::TypeTraitItem(..) => {
|
||||
this.check_if_primitive_type_name(trait_item.ident.name,
|
||||
trait_item.span);
|
||||
NoTypeParameters
|
||||
this.with_type_parameter_rib(NoTypeParameters, |this| {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
});
|
||||
}
|
||||
};
|
||||
this.with_type_parameter_rib(type_parameters, |this| {
|
||||
visit::walk_trait_item(this, trait_item)
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -2094,6 +2120,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
this.with_current_self_type(self_type, |this| {
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ConstImplItem(..) => {
|
||||
// If this is a trait impl, ensure the method
|
||||
// exists in trait
|
||||
this.check_trait_item(impl_item.ident.name,
|
||||
impl_item.span);
|
||||
this.with_constant_rib(|this| {
|
||||
visit::walk_impl_item(this, impl_item);
|
||||
});
|
||||
}
|
||||
MethodImplItem(ref sig, _) => {
|
||||
// If this is a trait impl, ensure the method
|
||||
// exists in trait
|
||||
|
@ -2280,31 +2315,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
|
||||
fn resolve_type(&mut self, ty: &Ty) {
|
||||
match ty.node {
|
||||
// `<T>::a::b::c` is resolved by typeck alone.
|
||||
TyPath(Some(ast::QSelf { position: 0, .. }), _) => {}
|
||||
|
||||
TyPath(ref maybe_qself, ref path) => {
|
||||
let max_assoc_types = if let Some(ref qself) = *maybe_qself {
|
||||
// Make sure the trait is valid.
|
||||
let _ = self.resolve_trait_reference(ty.id, path, 1);
|
||||
path.segments.len() - qself.position
|
||||
} else {
|
||||
path.segments.len()
|
||||
};
|
||||
|
||||
let mut resolution = None;
|
||||
for depth in 0..max_assoc_types {
|
||||
self.with_no_errors(|this| {
|
||||
resolution = this.resolve_path(ty.id, path, depth, TypeNS, true);
|
||||
});
|
||||
if resolution.is_some() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
|
||||
// A module is not a valid type.
|
||||
resolution = None;
|
||||
}
|
||||
let resolution =
|
||||
match self.resolve_possibly_assoc_item(ty.id,
|
||||
maybe_qself.as_ref(),
|
||||
path,
|
||||
TypeNS,
|
||||
true) {
|
||||
// `<T>::a::b::c` is resolved by typeck alone.
|
||||
TypecheckRequired => {
|
||||
// Resolve embedded types.
|
||||
visit::walk_ty(self, ty);
|
||||
return;
|
||||
}
|
||||
ResolveAttempt(resolution) => resolution,
|
||||
};
|
||||
|
||||
// This is a path in the type namespace. Walk through scopes
|
||||
// looking for it.
|
||||
|
@ -2464,7 +2489,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
|
||||
PatEnum(ref path, _) => {
|
||||
// This must be an enum variant, struct or const.
|
||||
if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) {
|
||||
let resolution =
|
||||
match self.resolve_possibly_assoc_item(pat_id, None,
|
||||
path, ValueNS,
|
||||
false) {
|
||||
// The below shouldn't happen because all
|
||||
// qualified paths should be in PatQPath.
|
||||
TypecheckRequired =>
|
||||
self.session.span_bug(
|
||||
path.span,
|
||||
"resolve_possibly_assoc_item claimed
|
||||
that a path in PatEnum requires typecheck
|
||||
to resolve, but qualified paths should be
|
||||
PatQPath"),
|
||||
ResolveAttempt(resolution) => resolution,
|
||||
};
|
||||
if let Some(path_res) = resolution {
|
||||
match path_res.base_def {
|
||||
DefVariant(..) | DefStruct(..) | DefConst(..) => {
|
||||
self.record_def(pattern.id, path_res);
|
||||
|
@ -2476,10 +2516,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
use a `const` instead");
|
||||
}
|
||||
_ => {
|
||||
self.resolve_error(path.span,
|
||||
&format!("`{}` is not an enum variant, struct or const",
|
||||
token::get_ident(
|
||||
path.segments.last().unwrap().identifier)));
|
||||
// If anything ends up here entirely resolved,
|
||||
// it's an error. If anything ends up here
|
||||
// partially resolved, that's OK, because it may
|
||||
// be a `T::CONST` that typeck will resolve to
|
||||
// an inherent impl.
|
||||
if path_res.depth == 0 {
|
||||
self.resolve_error(
|
||||
path.span,
|
||||
&format!("`{}` is not an enum variant, struct or const",
|
||||
token::get_ident(
|
||||
path.segments.last().unwrap().identifier)));
|
||||
} else {
|
||||
self.record_def(pattern.id, path_res);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2490,6 +2540,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
visit::walk_path(self, path);
|
||||
}
|
||||
|
||||
PatQPath(ref qself, ref path) => {
|
||||
// Associated constants only.
|
||||
let resolution =
|
||||
match self.resolve_possibly_assoc_item(pat_id, Some(qself),
|
||||
path, ValueNS,
|
||||
false) {
|
||||
TypecheckRequired => {
|
||||
// All `<T>::CONST` should end up here, and will
|
||||
// require use of the trait map to resolve
|
||||
// during typechecking.
|
||||
let const_name = path.segments.last().unwrap()
|
||||
.identifier.name;
|
||||
let traits = self.get_traits_containing_item(const_name);
|
||||
self.trait_map.insert(pattern.id, traits);
|
||||
visit::walk_pat(self, pattern);
|
||||
return true;
|
||||
}
|
||||
ResolveAttempt(resolution) => resolution,
|
||||
};
|
||||
if let Some(path_res) = resolution {
|
||||
match path_res.base_def {
|
||||
// All `<T as Trait>::CONST` should end up here, and
|
||||
// have the trait already selected.
|
||||
DefAssociatedConst(..) => {
|
||||
self.record_def(pattern.id, path_res);
|
||||
}
|
||||
_ => {
|
||||
self.resolve_error(path.span,
|
||||
&format!("`{}` is not an associated const",
|
||||
token::get_ident(
|
||||
path.segments.last().unwrap().identifier)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.resolve_error(path.span,
|
||||
&format!("unresolved associated const `{}`",
|
||||
token::get_ident(path.segments.last().unwrap().identifier)));
|
||||
}
|
||||
visit::walk_pat(self, pattern);
|
||||
}
|
||||
|
||||
PatStruct(ref path, _, _) => {
|
||||
match self.resolve_path(pat_id, path, 0, TypeNS, false) {
|
||||
Some(definition) => {
|
||||
|
@ -2542,7 +2633,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
def @ DefVariant(..) | def @ DefStruct(..) => {
|
||||
return FoundStructOrEnumVariant(def, LastMod(AllPublic));
|
||||
}
|
||||
def @ DefConst(..) => {
|
||||
def @ DefConst(..) | def @ DefAssociatedConst(..) => {
|
||||
return FoundConst(def, LastMod(AllPublic));
|
||||
}
|
||||
DefStatic(..) => {
|
||||
|
@ -2579,6 +2670,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Handles paths that may refer to associated items
|
||||
fn resolve_possibly_assoc_item(&mut self,
|
||||
id: NodeId,
|
||||
maybe_qself: Option<&ast::QSelf>,
|
||||
path: &Path,
|
||||
namespace: Namespace,
|
||||
check_ribs: bool)
|
||||
-> AssocItemResolveResult
|
||||
{
|
||||
match maybe_qself {
|
||||
Some(&ast::QSelf { position: 0, .. }) =>
|
||||
return TypecheckRequired,
|
||||
_ => {}
|
||||
}
|
||||
let max_assoc_types = if let Some(qself) = maybe_qself {
|
||||
// Make sure the trait is valid.
|
||||
let _ = self.resolve_trait_reference(id, path, 1);
|
||||
path.segments.len() - qself.position
|
||||
} else {
|
||||
path.segments.len()
|
||||
};
|
||||
|
||||
let mut resolution = self.with_no_errors(|this| {
|
||||
this.resolve_path(id, path, 0, namespace, check_ribs)
|
||||
});
|
||||
for depth in 1..max_assoc_types {
|
||||
if resolution.is_some() {
|
||||
break;
|
||||
}
|
||||
self.with_no_errors(|this| {
|
||||
resolution = this.resolve_path(id, path, depth,
|
||||
TypeNS, true);
|
||||
});
|
||||
}
|
||||
if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
|
||||
// A module is not a valid type or value.
|
||||
resolution = None;
|
||||
}
|
||||
ResolveAttempt(resolution)
|
||||
}
|
||||
|
||||
/// If `check_ribs` is true, checks the local definitions first; i.e.
|
||||
/// doesn't skip straight to the containing module.
|
||||
/// Skips `path_depth` trailing segments, which is also reflected in the
|
||||
|
@ -3093,38 +3225,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
|
||||
// Next, resolve the node.
|
||||
match expr.node {
|
||||
// `<T>::a::b::c` is resolved by typeck alone.
|
||||
ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => {
|
||||
let method_name = path.segments.last().unwrap().identifier.name;
|
||||
let traits = self.search_for_traits_containing_method(method_name);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
visit::walk_expr(self, expr);
|
||||
}
|
||||
|
||||
ExprPath(ref maybe_qself, ref path) => {
|
||||
let max_assoc_types = if let Some(ref qself) = *maybe_qself {
|
||||
// Make sure the trait is valid.
|
||||
let _ = self.resolve_trait_reference(expr.id, path, 1);
|
||||
path.segments.len() - qself.position
|
||||
} else {
|
||||
path.segments.len()
|
||||
};
|
||||
|
||||
let mut resolution = self.with_no_errors(|this| {
|
||||
this.resolve_path(expr.id, path, 0, ValueNS, true)
|
||||
});
|
||||
for depth in 1..max_assoc_types {
|
||||
if resolution.is_some() {
|
||||
break;
|
||||
}
|
||||
self.with_no_errors(|this| {
|
||||
resolution = this.resolve_path(expr.id, path, depth, TypeNS, true);
|
||||
});
|
||||
}
|
||||
if let Some(DefMod(_)) = resolution.map(|r| r.base_def) {
|
||||
// A module is not a valid type or value.
|
||||
resolution = None;
|
||||
}
|
||||
let resolution =
|
||||
match self.resolve_possibly_assoc_item(expr.id,
|
||||
maybe_qself.as_ref(),
|
||||
path,
|
||||
ValueNS,
|
||||
true) {
|
||||
// `<T>::a::b::c` is resolved by typeck alone.
|
||||
TypecheckRequired => {
|
||||
let method_name = path.segments.last().unwrap().identifier.name;
|
||||
let traits = self.get_traits_containing_item(method_name);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
visit::walk_expr(self, expr);
|
||||
return;
|
||||
}
|
||||
ResolveAttempt(resolution) => resolution,
|
||||
};
|
||||
|
||||
// This is a local path in the value namespace. Walk through
|
||||
// scopes looking for it.
|
||||
|
@ -3155,7 +3272,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
// so they can be completed during typeck.
|
||||
if path_res.depth != 0 {
|
||||
let method_name = path.segments.last().unwrap().identifier.name;
|
||||
let traits = self.search_for_traits_containing_method(method_name);
|
||||
let traits = self.get_traits_containing_item(method_name);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
|
||||
|
@ -3313,14 +3430,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
// field, we need to add any trait methods we find that match
|
||||
// the field name so that we can do some nice error reporting
|
||||
// later on in typeck.
|
||||
let traits = self.search_for_traits_containing_method(ident.node.name);
|
||||
let traits = self.get_traits_containing_item(ident.node.name);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
ExprMethodCall(ident, _, _) => {
|
||||
debug!("(recording candidate traits for expr) recording \
|
||||
traits for {}",
|
||||
expr.id);
|
||||
let traits = self.search_for_traits_containing_method(ident.node.name);
|
||||
let traits = self.get_traits_containing_item(ident.node.name);
|
||||
self.trait_map.insert(expr.id, traits);
|
||||
}
|
||||
_ => {
|
||||
|
@ -3329,8 +3446,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn search_for_traits_containing_method(&mut self, name: Name) -> Vec<DefId> {
|
||||
debug!("(searching for traits containing method) looking for '{}'",
|
||||
fn get_traits_containing_item(&mut self, name: Name) -> Vec<DefId> {
|
||||
debug!("(getting traits containing item) looking for '{}'",
|
||||
token::get_name(name));
|
||||
|
||||
fn add_trait_info(found_traits: &mut Vec<DefId>,
|
||||
|
|
|
@ -242,6 +242,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
def::DefTrait(_) => Some(recorder::TypeRef),
|
||||
def::DefStatic(_, _) |
|
||||
def::DefConst(_) |
|
||||
def::DefAssociatedConst(..) |
|
||||
def::DefLocal(_) |
|
||||
def::DefVariant(_, _, _) |
|
||||
def::DefUpvar(..) => Some(recorder::VarRef),
|
||||
|
@ -359,14 +360,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
// record the decl for this def (if it has one)
|
||||
let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx,
|
||||
ast_util::local_def(id))
|
||||
.and_then(|def_id| {
|
||||
if match def_id {
|
||||
ty::MethodTraitItemId(def_id) => {
|
||||
def_id.node != 0 && def_id != ast_util::local_def(id)
|
||||
}
|
||||
ty::TypeTraitItemId(_) => false,
|
||||
} {
|
||||
Some(def_id.def_id())
|
||||
.and_then(|new_id| {
|
||||
let def_id = new_id.def_id();
|
||||
if def_id.node != 0 && def_id != ast_util::local_def(id) {
|
||||
Some(def_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -542,25 +539,27 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
}
|
||||
|
||||
fn process_const(&mut self,
|
||||
item: &ast::Item,
|
||||
typ: &ast::Ty,
|
||||
expr: &ast::Expr)
|
||||
id: ast::NodeId,
|
||||
ident: &ast::Ident,
|
||||
span: Span,
|
||||
typ: &ast::Ty,
|
||||
expr: &ast::Expr)
|
||||
{
|
||||
let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(item.id));
|
||||
let qualname = format!("::{}", self.analysis.ty_cx.map.path_to_string(id));
|
||||
|
||||
let sub_span = self.span.sub_span_after_keyword(item.span,
|
||||
let sub_span = self.span.sub_span_after_keyword(span,
|
||||
keywords::Const);
|
||||
self.fmt.static_str(item.span,
|
||||
self.fmt.static_str(span,
|
||||
sub_span,
|
||||
item.id,
|
||||
&get_ident(item.ident),
|
||||
id,
|
||||
&get_ident((*ident).clone()),
|
||||
&qualname[..],
|
||||
"",
|
||||
&ty_to_string(&*typ),
|
||||
self.cur_scope);
|
||||
|
||||
// walk type and init value
|
||||
self.visit_ty(&*typ);
|
||||
self.visit_ty(typ);
|
||||
self.visit_expr(expr);
|
||||
}
|
||||
|
||||
|
@ -800,6 +799,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
def::DefLocal(..) |
|
||||
def::DefStatic(..) |
|
||||
def::DefConst(..) |
|
||||
def::DefAssociatedConst(..) |
|
||||
def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef),
|
||||
span,
|
||||
sub_span,
|
||||
|
@ -883,6 +883,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
def::DefLocal(_) |
|
||||
def::DefStatic(_,_) |
|
||||
def::DefConst(..) |
|
||||
def::DefAssociatedConst(..) |
|
||||
def::DefStruct(_) |
|
||||
def::DefVariant(..) |
|
||||
def::DefFn(..) => self.write_sub_paths_truncated(path, false),
|
||||
|
@ -966,7 +967,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
ty::MethodTraitItem(method) => {
|
||||
method.provided_source.unwrap_or(def_id)
|
||||
}
|
||||
ty::TypeTraitItem(_) => def_id,
|
||||
_ => self.sess
|
||||
.span_bug(ex.span,
|
||||
"save::process_method_call: non-method \
|
||||
DefId in MethodStatic or MethodStaticClosure"),
|
||||
};
|
||||
(Some(def_id), decl_id)
|
||||
}
|
||||
|
@ -1008,7 +1012,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
|
||||
let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def();
|
||||
let struct_def = match def {
|
||||
def::DefConst(..) => None,
|
||||
def::DefConst(..) | def::DefAssociatedConst(..) => None,
|
||||
def::DefVariant(_, variant_id, _) => Some(variant_id),
|
||||
_ => {
|
||||
match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) {
|
||||
|
@ -1040,7 +1044,8 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ast::PatEnum(ref path, _) => {
|
||||
ast::PatEnum(ref path, _) |
|
||||
ast::PatQPath(_, ref path) => {
|
||||
self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef));
|
||||
visit::walk_pat(self, p);
|
||||
}
|
||||
|
@ -1186,7 +1191,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
|||
ast::ItemStatic(ref typ, mt, ref expr) =>
|
||||
self.process_static(item, &**typ, mt, &**expr),
|
||||
ast::ItemConst(ref typ, ref expr) =>
|
||||
self.process_const(item, &**typ, &**expr),
|
||||
self.process_const(item.id, &item.ident, item.span, &*typ, &*expr),
|
||||
ast::ItemStruct(ref def, ref ty_params) => self.process_struct(item, &**def, ty_params),
|
||||
ast::ItemEnum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
|
||||
ast::ItemImpl(_, _,
|
||||
|
@ -1236,16 +1241,25 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
|||
|
||||
fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(ref ty, Some(ref expr)) => {
|
||||
self.process_const(trait_item.id, &trait_item.ident,
|
||||
trait_item.span, &*ty, &*expr);
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, ref body) => {
|
||||
self.process_method(sig, body.as_ref().map(|x| &**x),
|
||||
trait_item.id, trait_item.ident.name, trait_item.span);
|
||||
}
|
||||
ast::ConstTraitItem(_, None) |
|
||||
ast::TypeTraitItem(..) => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(ref ty, ref expr) => {
|
||||
self.process_const(impl_item.id, &impl_item.ident,
|
||||
impl_item.span, &*ty, &*expr);
|
||||
}
|
||||
ast::MethodImplItem(ref sig, ref body) => {
|
||||
self.process_method(sig, Some(body), impl_item.id,
|
||||
impl_item.ident.name, impl_item.span);
|
||||
|
@ -1432,8 +1446,9 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> {
|
|||
paths_to_process.push((id, p.clone(), Some(ref_kind)))
|
||||
}
|
||||
// FIXME(nrc) what are these doing here?
|
||||
def::DefStatic(_, _) => {}
|
||||
def::DefConst(..) => {}
|
||||
def::DefStatic(_, _) |
|
||||
def::DefConst(..) |
|
||||
def::DefAssociatedConst(..) => {}
|
||||
_ => error!("unexpected definition kind when processing collected paths: {:?}",
|
||||
def)
|
||||
}
|
||||
|
|
|
@ -1809,7 +1809,8 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
ast::PatMac(..) => {
|
||||
bcx.sess().span_bug(pat.span, "unexpanded macro");
|
||||
}
|
||||
ast::PatWild(_) | ast::PatLit(_) | ast::PatRange(_, _) => ()
|
||||
ast::PatQPath(..) | ast::PatWild(_) | ast::PatLit(_) |
|
||||
ast::PatRange(_, _) => ()
|
||||
}
|
||||
return bcx;
|
||||
}
|
||||
|
|
|
@ -1078,25 +1078,17 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
|
|||
Some(ast_map::NodeTraitItem(trait_item)) => {
|
||||
match trait_item.node {
|
||||
ast::MethodTraitItem(_, Some(ref body)) => body,
|
||||
ast::MethodTraitItem(_, None) => {
|
||||
tcx.sess.bug("unexpected variant: required trait method \
|
||||
in has_nested_returns")
|
||||
}
|
||||
ast::TypeTraitItem(..) => {
|
||||
tcx.sess.bug("unexpected variant: associated type trait item in \
|
||||
has_nested_returns")
|
||||
_ => {
|
||||
tcx.sess.bug("unexpected variant: trait item other than a \
|
||||
provided method in has_nested_returns")
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(ast_map::NodeImplItem(impl_item)) => {
|
||||
match impl_item.node {
|
||||
ast::MethodImplItem(_, ref body) => body,
|
||||
ast::TypeImplItem(_) => {
|
||||
tcx.sess.bug("unexpected variant: associated type impl item in \
|
||||
has_nested_returns")
|
||||
}
|
||||
ast::MacImplItem(_) => {
|
||||
tcx.sess.bug("unexpected variant: unexpanded macro impl item in \
|
||||
_ => {
|
||||
tcx.sess.bug("unexpected variant: non-method impl item in \
|
||||
has_nested_returns")
|
||||
}
|
||||
}
|
||||
|
@ -2363,13 +2355,14 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
|||
ast_map::NodeTraitItem(trait_item) => {
|
||||
debug!("get_item_val(): processing a NodeTraitItem");
|
||||
match trait_item.node {
|
||||
ast::MethodTraitItem(_, None) | ast::TypeTraitItem(..) => {
|
||||
ccx.sess().span_bug(trait_item.span,
|
||||
"unexpected variant: required trait method in get_item_val()");
|
||||
}
|
||||
ast::MethodTraitItem(_, Some(_)) => {
|
||||
register_method(ccx, id, &trait_item.attrs, trait_item.span)
|
||||
}
|
||||
_ => {
|
||||
ccx.sess().span_bug(trait_item.span,
|
||||
"unexpected variant: trait item other than a provided \
|
||||
method in get_item_val()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2378,13 +2371,10 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
|||
ast::MethodImplItem(..) => {
|
||||
register_method(ccx, id, &impl_item.attrs, impl_item.span)
|
||||
}
|
||||
ast::TypeImplItem(_) => {
|
||||
_ => {
|
||||
ccx.sess().span_bug(impl_item.span,
|
||||
"unexpected variant: associated type in get_item_val()")
|
||||
}
|
||||
ast::MacImplItem(_) => {
|
||||
ccx.sess().span_bug(impl_item.span,
|
||||
"unexpected variant: unexpanded macro in get_item_val()")
|
||||
"unexpected variant: non-method impl item in \
|
||||
get_item_val()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -202,6 +202,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr)
|
|||
}
|
||||
def::DefStatic(..) |
|
||||
def::DefConst(..) |
|
||||
def::DefAssociatedConst(..) |
|
||||
def::DefLocal(..) |
|
||||
def::DefUpvar(..) => {
|
||||
datum_callee(bcx, ref_expr)
|
||||
|
@ -465,9 +466,9 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>(
|
|||
|
||||
(true, source_id, new_substs)
|
||||
}
|
||||
ty::TypeTraitItem(_) => {
|
||||
_ => {
|
||||
tcx.sess.bug("trans_fn_ref_with_vtables() tried \
|
||||
to translate an associated type?!")
|
||||
to translate a non-method?!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,13 +173,11 @@ pub fn get_const_expr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
"cross crate constant could not be inlined");
|
||||
}
|
||||
|
||||
let item = ccx.tcx().map.expect_item(def_id.node);
|
||||
if let ast::ItemConst(_, ref expr) = item.node {
|
||||
&**expr
|
||||
} else {
|
||||
ccx.sess().span_bug(ref_expr.span,
|
||||
&format!("get_const_expr given non-constant item {}",
|
||||
item.repr(ccx.tcx())));
|
||||
match const_eval::lookup_const_by_id(ccx.tcx(), def_id, Some(ref_expr.id)) {
|
||||
Some(ref expr) => expr,
|
||||
None => {
|
||||
ccx.sess().span_bug(ref_expr.span, "constant item not found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,7 +199,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
ast::ExprPath(..) => {
|
||||
let def = ccx.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
|
||||
match def {
|
||||
def::DefConst(def_id) => {
|
||||
def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
|
||||
if !ccx.tcx().adjustments.borrow().contains_key(&expr.id) {
|
||||
return get_const_val(ccx, def_id, expr);
|
||||
}
|
||||
|
@ -774,7 +772,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
def::DefFn(..) | def::DefMethod(..) => {
|
||||
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
|
||||
}
|
||||
def::DefConst(def_id) => {
|
||||
def::DefConst(def_id) | def::DefAssociatedConst(def_id, _) => {
|
||||
const_deref_ptr(cx, get_const_val(cx, def_id, e))
|
||||
}
|
||||
def::DefVariant(enum_did, variant_did, _) => {
|
||||
|
|
|
@ -1314,15 +1314,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
impl_item.span,
|
||||
true)
|
||||
}
|
||||
ast::TypeImplItem(_) => {
|
||||
_ => {
|
||||
cx.sess().span_bug(impl_item.span,
|
||||
"create_function_debug_context() \
|
||||
called on associated type?!")
|
||||
}
|
||||
ast::MacImplItem(_) => {
|
||||
cx.sess().span_bug(impl_item.span,
|
||||
"create_function_debug_context() \
|
||||
called on unexpanded macro?!")
|
||||
called on non-method impl item?!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3442,6 +3437,10 @@ fn create_scope_map(cx: &CrateContext,
|
|||
}
|
||||
}
|
||||
|
||||
ast::PatQPath(..) => {
|
||||
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||
}
|
||||
|
||||
ast::PatStruct(_, ref field_pats, _) => {
|
||||
scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata);
|
||||
|
||||
|
|
|
@ -134,6 +134,14 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId)
|
|||
|
||||
ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
|
||||
|
||||
// Associated consts already have to be evaluated in `typeck`, so
|
||||
// the logic to do that already exists in `middle`. In order to
|
||||
// reuse that code, it needs to be able to look up the traits for
|
||||
// inlined items.
|
||||
let ty_trait_item = ty::impl_or_trait_item(ccx.tcx(), fn_id).clone();
|
||||
ccx.tcx().impl_or_trait_items.borrow_mut()
|
||||
.insert(local_def(trait_item.id), ty_trait_item);
|
||||
|
||||
// If this is a default method, we can't look up the
|
||||
// impl type. But we aren't going to translate anyways, so
|
||||
// don't.
|
||||
|
|
|
@ -74,8 +74,7 @@ pub fn trans_impl(ccx: &CrateContext,
|
|||
ast::MethodImplItem(..) => {
|
||||
visit::walk_impl_item(&mut v, impl_item);
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -98,8 +97,7 @@ pub fn trans_impl(ccx: &CrateContext,
|
|||
}
|
||||
visit::walk_impl_item(&mut v, impl_item);
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -336,9 +334,9 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let impl_did = vtable_impl.impl_def_id;
|
||||
let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) {
|
||||
ty::MethodTraitItem(method) => method.name,
|
||||
ty::TypeTraitItem(_) => {
|
||||
bcx.tcx().sess.bug("can't monomorphize an associated \
|
||||
type")
|
||||
_ => {
|
||||
bcx.tcx().sess.bug("can't monomorphize a non-method trait \
|
||||
item")
|
||||
}
|
||||
};
|
||||
let mth_id = method_with_name(bcx.ccx(), impl_did, mname);
|
||||
|
@ -579,8 +577,8 @@ pub fn trans_object_shim<'a, 'tcx>(
|
|||
// Lookup the type of this method as declared in the trait and apply substitutions.
|
||||
let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) {
|
||||
ty::MethodTraitItem(method) => method,
|
||||
ty::TypeTraitItem(_) => {
|
||||
tcx.sess.bug("can't create a method shim for an associated type")
|
||||
_ => {
|
||||
tcx.sess.bug("can't create a method shim for a non-method item")
|
||||
}
|
||||
};
|
||||
let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
|
||||
|
@ -789,11 +787,11 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
trait_item_def_ids
|
||||
.iter()
|
||||
|
||||
// Filter out the associated types.
|
||||
// Filter out non-method items.
|
||||
.filter_map(|item_def_id| {
|
||||
match *item_def_id {
|
||||
ty::MethodTraitItemId(def_id) => Some(def_id),
|
||||
ty::TypeTraitItemId(_) => None,
|
||||
_ => None,
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -806,7 +804,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) {
|
||||
ty::MethodTraitItem(m) => m,
|
||||
ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
|
||||
_ => ccx.sess().bug("should be a method, not other assoc item"),
|
||||
};
|
||||
let name = trait_method_type.name;
|
||||
|
||||
|
@ -824,7 +822,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
let impl_method_def_id = method_with_name(ccx, impl_id, name);
|
||||
let impl_method_type = match ty::impl_or_trait_item(tcx, impl_method_def_id) {
|
||||
ty::MethodTraitItem(m) => m,
|
||||
ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type")
|
||||
_ => ccx.sess().bug("should be a method, not other assoc item"),
|
||||
};
|
||||
|
||||
debug!("emit_vtable_methods: impl_method_type={}",
|
||||
|
|
|
@ -236,11 +236,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
d
|
||||
}
|
||||
ast::TypeImplItem(_) => {
|
||||
ccx.sess().bug("can't monomorphize an associated type")
|
||||
}
|
||||
ast::MacImplItem(_) => {
|
||||
ccx.sess().bug("can't monomorphize an unexpanded macro")
|
||||
_ => {
|
||||
ccx.sess().bug(&format!("can't monomorphize a {:?}",
|
||||
map_node))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
use middle::const_eval;
|
||||
use middle::def;
|
||||
use middle::infer;
|
||||
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const};
|
||||
use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding};
|
||||
use middle::pat_util::pat_is_resolved_const;
|
||||
use middle::privacy::{AllPublic, LastMod};
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{self, Ty};
|
||||
use check::{check_expr, check_expr_has_type, check_expr_with_expectation};
|
||||
use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation};
|
||||
use check::{instantiate_path, structurally_resolved_type};
|
||||
use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type};
|
||||
use require_same_types;
|
||||
use util::nodemap::FnvHashMap;
|
||||
use util::ppaux::Repr;
|
||||
|
@ -118,7 +120,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
// subtyping doesn't matter here, as the value is some kind of scalar
|
||||
demand::eqtype(fcx, pat.span, expected, lhs_ty);
|
||||
}
|
||||
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => {
|
||||
ast::PatEnum(..) | ast::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => {
|
||||
let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id();
|
||||
let const_scheme = ty::lookup_item_type(tcx, const_did);
|
||||
assert!(const_scheme.generics.is_empty());
|
||||
|
@ -181,6 +183,37 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
let subpats = subpats.as_ref().map(|v| &v[..]);
|
||||
check_pat_enum(pcx, pat, path, subpats, expected);
|
||||
}
|
||||
ast::PatQPath(ref qself, ref path) => {
|
||||
let self_ty = fcx.to_ty(&qself.ty);
|
||||
let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) {
|
||||
d
|
||||
} else if qself.position == 0 {
|
||||
def::PathResolution {
|
||||
// This is just a sentinel for finish_resolving_def_to_ty.
|
||||
base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)),
|
||||
last_private: LastMod(AllPublic),
|
||||
depth: path.segments.len()
|
||||
}
|
||||
} else {
|
||||
tcx.sess.span_bug(pat.span,
|
||||
&format!("unbound path {}", pat.repr(tcx)))
|
||||
};
|
||||
if let Some((opt_ty, segments, def)) =
|
||||
resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty),
|
||||
path, pat.span, pat.id) {
|
||||
if check_assoc_item_is_const(pcx, def, pat.span) {
|
||||
let scheme = ty::lookup_item_type(tcx, def.def_id());
|
||||
let predicates = ty::lookup_predicates(tcx, def.def_id());
|
||||
instantiate_path(fcx, segments,
|
||||
scheme, &predicates,
|
||||
opt_ty, def, pat.span, pat.id);
|
||||
let const_ty = fcx.node_ty(pat.id);
|
||||
demand::suptype(fcx, pat.span, expected, const_ty);
|
||||
} else {
|
||||
fcx.write_error(pat.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::PatStruct(ref path, ref fields, etc) => {
|
||||
check_pat_struct(pcx, pat, path, fields, etc, expected);
|
||||
}
|
||||
|
@ -331,6 +364,21 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
// subtyping.
|
||||
}
|
||||
|
||||
fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool {
|
||||
match def {
|
||||
def::DefAssociatedConst(..) => true,
|
||||
def::DefMethod(..) => {
|
||||
span_err!(pcx.fcx.ccx.tcx.sess, span, E0327,
|
||||
"associated items in match patterns must be constants");
|
||||
false
|
||||
}
|
||||
_ => {
|
||||
pcx.fcx.ccx.tcx.sess.span_bug(span, "non-associated item in
|
||||
check_assoc_item_is_const");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
||||
span: Span, expected: Ty<'tcx>,
|
||||
inner: &ast::Pat) -> bool {
|
||||
|
@ -532,7 +580,24 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
let fcx = pcx.fcx;
|
||||
let tcx = pcx.fcx.ccx.tcx;
|
||||
|
||||
let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
|
||||
let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap();
|
||||
|
||||
let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res,
|
||||
None, path,
|
||||
pat.span, pat.id) {
|
||||
Some(resolution) => resolution,
|
||||
// Error handling done inside resolve_ty_and_def_ufcs, so if
|
||||
// resolution fails just return.
|
||||
None => {return;}
|
||||
};
|
||||
|
||||
// Items that were partially resolved before should have been resolved to
|
||||
// associated constants (i.e. not methods).
|
||||
if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) {
|
||||
fcx.write_error(pat.id);
|
||||
return;
|
||||
}
|
||||
|
||||
let enum_def = def.variant_def_ids()
|
||||
.map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
|
||||
|
||||
|
@ -547,13 +612,23 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
|
|||
} else {
|
||||
ctor_scheme
|
||||
};
|
||||
instantiate_path(pcx.fcx, &path.segments,
|
||||
instantiate_path(pcx.fcx, segments,
|
||||
path_scheme, &ctor_predicates,
|
||||
None, def, pat.span, pat.id);
|
||||
opt_ty, def, pat.span, pat.id);
|
||||
|
||||
// If we didn't have a fully resolved path to start with, we had an
|
||||
// associated const, and we should quit now, since the rest of this
|
||||
// function uses checks specific to structs and enums.
|
||||
if path_res.depth != 0 {
|
||||
let pat_ty = fcx.node_ty(pat.id);
|
||||
demand::suptype(fcx, pat.span, expected, pat_ty);
|
||||
return;
|
||||
}
|
||||
|
||||
let pat_ty = fcx.node_ty(pat.id);
|
||||
demand::eqtype(fcx, pat.span, expected, pat_ty);
|
||||
|
||||
|
||||
let real_path_ty = fcx.node_ty(pat.id);
|
||||
let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty {
|
||||
ty::ty_enum(enum_def_id, expected_substs)
|
||||
|
|
|
@ -412,3 +412,85 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_c: &ty::AssociatedConst<'tcx>,
|
||||
impl_c_span: Span,
|
||||
trait_c: &ty::AssociatedConst<'tcx>,
|
||||
impl_trait_ref: &ty::TraitRef<'tcx>) {
|
||||
debug!("compare_const_impl(impl_trait_ref={})",
|
||||
impl_trait_ref.repr(tcx));
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
let mut fulfillment_cx = traits::FulfillmentContext::new();
|
||||
|
||||
// The below is for the most part highly similar to the procedure
|
||||
// for methods above. It is simpler in many respects, especially
|
||||
// because we shouldn't really have to deal with lifetimes or
|
||||
// predicates. In fact some of this should probably be put into
|
||||
// shared functions because of DRY violations...
|
||||
let trait_to_impl_substs = &impl_trait_ref.substs;
|
||||
|
||||
// Create a parameter environment that represents the implementation's
|
||||
// method.
|
||||
let impl_param_env =
|
||||
ty::ParameterEnvironment::for_item(tcx, impl_c.def_id.node);
|
||||
|
||||
// Create mapping from impl to skolemized.
|
||||
let impl_to_skol_substs = &impl_param_env.free_substs;
|
||||
|
||||
// Create mapping from trait to skolemized.
|
||||
let trait_to_skol_substs =
|
||||
trait_to_impl_substs
|
||||
.subst(tcx, impl_to_skol_substs)
|
||||
.with_method(impl_to_skol_substs.types.get_slice(subst::FnSpace).to_vec(),
|
||||
impl_to_skol_substs.regions().get_slice(subst::FnSpace).to_vec());
|
||||
debug!("compare_const_impl: trait_to_skol_substs={}",
|
||||
trait_to_skol_substs.repr(tcx));
|
||||
|
||||
// Compute skolemized form of impl and trait const tys.
|
||||
let impl_ty = impl_c.ty.subst(tcx, impl_to_skol_substs);
|
||||
let trait_ty = trait_c.ty.subst(tcx, &trait_to_skol_substs);
|
||||
|
||||
let err = infcx.commit_if_ok(|_| {
|
||||
let origin = infer::Misc(impl_c_span);
|
||||
|
||||
// There is no "body" here, so just pass dummy id.
|
||||
let impl_ty =
|
||||
assoc::normalize_associated_types_in(&infcx,
|
||||
&impl_param_env,
|
||||
&mut fulfillment_cx,
|
||||
impl_c_span,
|
||||
0,
|
||||
&impl_ty);
|
||||
debug!("compare_const_impl: impl_ty={}",
|
||||
impl_ty.repr(tcx));
|
||||
|
||||
let trait_ty =
|
||||
assoc::normalize_associated_types_in(&infcx,
|
||||
&impl_param_env,
|
||||
&mut fulfillment_cx,
|
||||
impl_c_span,
|
||||
0,
|
||||
&trait_ty);
|
||||
debug!("compare_const_impl: trait_ty={}",
|
||||
trait_ty.repr(tcx));
|
||||
|
||||
infer::mk_subty(&infcx, false, origin, impl_ty, trait_ty)
|
||||
});
|
||||
|
||||
match err {
|
||||
Ok(()) => { }
|
||||
Err(terr) => {
|
||||
debug!("checking associated const for compatibility: impl ty {}, trait ty {}",
|
||||
impl_ty.repr(tcx),
|
||||
trait_ty.repr(tcx));
|
||||
span_err!(tcx.sess, impl_c_span, E0326,
|
||||
"implemented const `{}` has an incompatible type for \
|
||||
trait: {}",
|
||||
token::get_name(trait_c.name),
|
||||
ty::type_err_to_str(tcx, &terr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,10 +109,11 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
self.add_obligations(&pick, &all_substs, &method_predicates);
|
||||
|
||||
// Create the final `MethodCallee`.
|
||||
let method_ty = pick.item.as_opt_method().unwrap();
|
||||
let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
|
||||
sig: ty::Binder(method_sig),
|
||||
unsafety: pick.method_ty.fty.unsafety,
|
||||
abi: pick.method_ty.fty.abi.clone(),
|
||||
unsafety: method_ty.fty.unsafety,
|
||||
abi: method_ty.fty.abi.clone(),
|
||||
}));
|
||||
let callee = MethodCallee {
|
||||
origin: method_origin,
|
||||
|
@ -204,7 +205,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
"impl {:?} is not an inherent impl", impl_def_id);
|
||||
let impl_polytype = check::impl_self_ty(self.fcx, self.span, impl_def_id);
|
||||
|
||||
(impl_polytype.substs, MethodStatic(pick.method_ty.def_id))
|
||||
(impl_polytype.substs, MethodStatic(pick.item.def_id()))
|
||||
}
|
||||
|
||||
probe::ObjectPick(trait_def_id, method_num, vtable_index) => {
|
||||
|
@ -336,7 +337,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// If they were not explicitly supplied, just construct fresh
|
||||
// variables.
|
||||
let num_supplied_types = supplied_method_types.len();
|
||||
let num_method_types = pick.method_ty.generics.types.len(subst::FnSpace);
|
||||
let num_method_types = pick.item.as_opt_method().unwrap()
|
||||
.generics.types.len(subst::FnSpace);
|
||||
let method_types = {
|
||||
if num_supplied_types == 0 {
|
||||
self.fcx.infcx().next_ty_vars(num_method_types)
|
||||
|
@ -360,7 +362,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
let method_regions =
|
||||
self.fcx.infcx().region_vars_for_defs(
|
||||
self.span,
|
||||
pick.method_ty.generics.regions.get_slice(subst::FnSpace));
|
||||
pick.item.as_opt_method().unwrap()
|
||||
.generics.regions.get_slice(subst::FnSpace));
|
||||
|
||||
(method_types, method_regions)
|
||||
}
|
||||
|
@ -397,7 +400,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// Instantiate the bounds on the method with the
|
||||
// type/early-bound-regions substitutions performed. There can
|
||||
// be no late-bound regions appearing here.
|
||||
let method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
|
||||
let method_predicates = pick.item.as_opt_method().unwrap()
|
||||
.predicates.instantiate(self.tcx(), &all_substs);
|
||||
let method_predicates = self.fcx.normalize_associated_types_in(self.span,
|
||||
&method_predicates);
|
||||
|
||||
|
@ -410,7 +414,8 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// NB: Instantiate late-bound regions first so that
|
||||
// `instantiate_type_scheme` can normalize associated types that
|
||||
// may reference those regions.
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(&pick.method_ty.fty.sig);
|
||||
let method_sig = self.replace_late_bound_regions_with_fresh_var(
|
||||
&pick.item.as_opt_method().unwrap().fty.sig);
|
||||
debug!("late-bound lifetimes from method instantiated, method_sig={}",
|
||||
method_sig.repr(self.tcx()));
|
||||
|
||||
|
@ -616,7 +621,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
|
||||
fn enforce_illegal_method_limitations(&self, pick: &probe::Pick) {
|
||||
// Disallow calls to the method `drop` defined in the `Drop` trait.
|
||||
match pick.method_ty.container {
|
||||
match pick.item.container() {
|
||||
ty::TraitContainer(trait_def_id) => {
|
||||
callee::check_legal_trait_for_method_call(self.fcx.ccx, self.span, trait_def_id)
|
||||
}
|
||||
|
@ -625,7 +630,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||
// potential calls to it will wind up in the other
|
||||
// arm. But just to be sure, check that the method id
|
||||
// does not appear in the list of destructors.
|
||||
assert!(!self.tcx().destructors.borrow().contains(&pick.method_ty.def_id));
|
||||
assert!(!self.tcx().destructors.borrow().contains(&pick.item.def_id()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ pub enum CandidateSource {
|
|||
TraitSource(/* trait id */ ast::DefId),
|
||||
}
|
||||
|
||||
type MethodIndex = usize; // just for doc purposes
|
||||
type ItemIndex = usize; // just for doc purposes
|
||||
|
||||
/// Determines whether the type `self_ty` supports a method name `method_name` or not.
|
||||
pub fn exists<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
|
@ -312,18 +312,25 @@ pub fn resolve_ufcs<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
{
|
||||
let mode = probe::Mode::Path;
|
||||
let pick = try!(probe::probe(fcx, span, mode, method_name, self_ty, expr_id));
|
||||
let def_id = pick.method_ty.def_id;
|
||||
let def_id = pick.item.def_id();
|
||||
let mut lp = LastMod(AllPublic);
|
||||
let provenance = match pick.kind {
|
||||
probe::InherentImplPick(impl_def_id) => {
|
||||
if pick.method_ty.vis != ast::Public {
|
||||
if pick.item.vis() != ast::Public {
|
||||
lp = LastMod(DependsOn(def_id));
|
||||
}
|
||||
def::FromImpl(impl_def_id)
|
||||
}
|
||||
_ => def::FromTrait(pick.method_ty.container.id())
|
||||
_ => def::FromTrait(pick.item.container().id())
|
||||
};
|
||||
Ok((def::DefMethod(def_id, provenance), lp))
|
||||
let def_result = match pick.item {
|
||||
ImplOrTraitItem::MethodTraitItem(..) => def::DefMethod(def_id, provenance),
|
||||
ImplOrTraitItem::ConstTraitItem(..) => def::DefAssociatedConst(def_id, provenance),
|
||||
ImplOrTraitItem::TypeTraitItem(..) => {
|
||||
fcx.tcx().sess.span_bug(span, "resolve_ufcs: probe picked associated type");
|
||||
}
|
||||
};
|
||||
Ok((def_result, lp))
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
use super::MethodError;
|
||||
use super::MethodIndex;
|
||||
use super::ItemIndex;
|
||||
use super::{CandidateSource,ImplSource,TraitSource};
|
||||
use super::suggest;
|
||||
|
||||
|
@ -37,7 +37,7 @@ struct ProbeContext<'a, 'tcx:'a> {
|
|||
fcx: &'a FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
method_name: ast::Name,
|
||||
item_name: ast::Name,
|
||||
steps: Rc<Vec<CandidateStep<'tcx>>>,
|
||||
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>,
|
||||
inherent_candidates: Vec<Candidate<'tcx>>,
|
||||
|
@ -54,7 +54,7 @@ struct CandidateStep<'tcx> {
|
|||
|
||||
struct Candidate<'tcx> {
|
||||
xform_self_ty: Ty<'tcx>,
|
||||
method_ty: Rc<ty::Method<'tcx>>,
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
kind: CandidateKind<'tcx>,
|
||||
}
|
||||
|
||||
|
@ -62,14 +62,14 @@ enum CandidateKind<'tcx> {
|
|||
InherentImplCandidate(/* Impl */ ast::DefId, subst::Substs<'tcx>),
|
||||
ObjectCandidate(/* Trait */ ast::DefId, /* method_num */ usize, /* vtable index */ usize),
|
||||
ExtensionImplCandidate(/* Impl */ ast::DefId, Rc<ty::TraitRef<'tcx>>,
|
||||
subst::Substs<'tcx>, MethodIndex),
|
||||
ClosureCandidate(/* Trait */ ast::DefId, MethodIndex),
|
||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, MethodIndex),
|
||||
ProjectionCandidate(ast::DefId, MethodIndex),
|
||||
subst::Substs<'tcx>, ItemIndex),
|
||||
ClosureCandidate(/* Trait */ ast::DefId, ItemIndex),
|
||||
WhereClauseCandidate(ty::PolyTraitRef<'tcx>, ItemIndex),
|
||||
ProjectionCandidate(ast::DefId, ItemIndex),
|
||||
}
|
||||
|
||||
pub struct Pick<'tcx> {
|
||||
pub method_ty: Rc<ty::Method<'tcx>>,
|
||||
pub item: ty::ImplOrTraitItem<'tcx>,
|
||||
pub kind: PickKind<'tcx>,
|
||||
|
||||
// Indicates that the source expression should be autoderef'd N times
|
||||
|
@ -94,20 +94,20 @@ pub struct Pick<'tcx> {
|
|||
pub enum PickKind<'tcx> {
|
||||
InherentImplPick(/* Impl */ ast::DefId),
|
||||
ObjectPick(/* Trait */ ast::DefId, /* method_num */ usize, /* real_index */ usize),
|
||||
ExtensionImplPick(/* Impl */ ast::DefId, MethodIndex),
|
||||
TraitPick(/* Trait */ ast::DefId, MethodIndex),
|
||||
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, MethodIndex),
|
||||
ExtensionImplPick(/* Impl */ ast::DefId, ItemIndex),
|
||||
TraitPick(/* Trait */ ast::DefId, ItemIndex),
|
||||
WhereClausePick(/* Trait */ ty::PolyTraitRef<'tcx>, ItemIndex),
|
||||
}
|
||||
|
||||
pub type PickResult<'tcx> = Result<Pick<'tcx>, MethodError>;
|
||||
|
||||
#[derive(PartialEq, Eq, Copy, Clone)]
|
||||
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub enum Mode {
|
||||
// An expression of the form `receiver.method_name(...)`.
|
||||
// Autoderefs are performed on `receiver`, lookup is done based on the
|
||||
// `self` argument of the method, and static methods aren't considered.
|
||||
MethodCall,
|
||||
// An expression of the form `Type::method` or `<T>::method`.
|
||||
// An expression of the form `Type::item` or `<T>::item`.
|
||||
// No autoderefs are performed, lookup is done based on the type each
|
||||
// implementation is for, and static methods are included.
|
||||
Path
|
||||
|
@ -116,14 +116,14 @@ pub enum Mode {
|
|||
pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
method_name: ast::Name,
|
||||
item_name: ast::Name,
|
||||
self_ty: Ty<'tcx>,
|
||||
scope_expr_id: ast::NodeId)
|
||||
-> PickResult<'tcx>
|
||||
{
|
||||
debug!("probe(self_ty={}, method_name={}, scope_expr_id={})",
|
||||
debug!("probe(self_ty={}, item_name={}, scope_expr_id={})",
|
||||
self_ty.repr(fcx.tcx()),
|
||||
method_name,
|
||||
item_name,
|
||||
scope_expr_id);
|
||||
|
||||
// FIXME(#18741) -- right now, creating the steps involves evaluating the
|
||||
|
@ -171,7 +171,7 @@ pub fn probe<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
let mut probe_cx = ProbeContext::new(fcx,
|
||||
span,
|
||||
mode,
|
||||
method_name,
|
||||
item_name,
|
||||
steps,
|
||||
opt_simplified_steps);
|
||||
probe_cx.assemble_inherent_candidates();
|
||||
|
@ -221,7 +221,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
fn new(fcx: &'a FnCtxt<'a,'tcx>,
|
||||
span: Span,
|
||||
mode: Mode,
|
||||
method_name: ast::Name,
|
||||
item_name: ast::Name,
|
||||
steps: Vec<CandidateStep<'tcx>>,
|
||||
opt_simplified_steps: Option<Vec<fast_reject::SimplifiedType>>)
|
||||
-> ProbeContext<'a,'tcx>
|
||||
|
@ -230,7 +230,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
fcx: fcx,
|
||||
span: span,
|
||||
mode: mode,
|
||||
method_name: method_name,
|
||||
item_name: item_name,
|
||||
inherent_candidates: Vec::new(),
|
||||
extension_candidates: Vec::new(),
|
||||
impl_dups: HashSet::new(),
|
||||
|
@ -387,12 +387,12 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
debug!("assemble_inherent_impl_probe {:?}", impl_def_id);
|
||||
|
||||
let method = match impl_method(self.tcx(), impl_def_id, self.method_name) {
|
||||
let item = match impl_item(self.tcx(), impl_def_id, self.item_name) {
|
||||
Some(m) => m,
|
||||
None => { return; } // No method with correct name on this impl
|
||||
};
|
||||
|
||||
if !self.has_applicable_self(&*method) {
|
||||
if !self.has_applicable_self(&item) {
|
||||
// No receiver declared. Not a candidate.
|
||||
return self.record_static_candidate(ImplSource(impl_def_id));
|
||||
}
|
||||
|
@ -402,11 +402,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
// Determine the receiver type that the method itself expects.
|
||||
let xform_self_ty =
|
||||
self.xform_self_ty(&method, impl_ty, &impl_substs);
|
||||
self.xform_self_ty(&item, impl_ty, &impl_substs);
|
||||
|
||||
self.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: method,
|
||||
item: item,
|
||||
kind: InherentImplCandidate(impl_def_id, impl_substs)
|
||||
});
|
||||
}
|
||||
|
@ -427,23 +427,23 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
// itself. Hence, a `&self` method will wind up with an
|
||||
// argument type like `&Trait`.
|
||||
let trait_ref = data.principal_trait_ref_with_self_ty(self.tcx(), self_ty);
|
||||
self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, m, method_num| {
|
||||
self.elaborate_bounds(&[trait_ref.clone()], |this, new_trait_ref, item, item_num| {
|
||||
let new_trait_ref = this.erase_late_bound_regions(&new_trait_ref);
|
||||
|
||||
let vtable_index =
|
||||
traits::get_vtable_index_of_object_method(tcx,
|
||||
trait_ref.clone(),
|
||||
new_trait_ref.def_id,
|
||||
method_num);
|
||||
item_num);
|
||||
|
||||
let xform_self_ty = this.xform_self_ty(&m,
|
||||
let xform_self_ty = this.xform_self_ty(&item,
|
||||
new_trait_ref.self_ty(),
|
||||
new_trait_ref.substs);
|
||||
|
||||
this.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: m,
|
||||
kind: ObjectCandidate(new_trait_ref.def_id, method_num, vtable_index)
|
||||
item: item,
|
||||
kind: ObjectCandidate(new_trait_ref.def_id, item_num, vtable_index)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -476,27 +476,29 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
})
|
||||
.collect();
|
||||
|
||||
self.elaborate_bounds(&bounds, |this, poly_trait_ref, m, method_num| {
|
||||
self.elaborate_bounds(&bounds, |this, poly_trait_ref, item, item_num| {
|
||||
let trait_ref =
|
||||
this.erase_late_bound_regions(&poly_trait_ref);
|
||||
|
||||
let xform_self_ty =
|
||||
this.xform_self_ty(&m,
|
||||
this.xform_self_ty(&item,
|
||||
trait_ref.self_ty(),
|
||||
trait_ref.substs);
|
||||
|
||||
debug!("found match: trait_ref={} substs={} m={}",
|
||||
trait_ref.repr(this.tcx()),
|
||||
trait_ref.substs.repr(this.tcx()),
|
||||
m.repr(this.tcx()));
|
||||
assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs.types.get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs.types.get_slice(subst::SelfSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
|
||||
if let Some(ref m) = item.as_opt_method() {
|
||||
debug!("found match: trait_ref={} substs={} m={}",
|
||||
trait_ref.repr(this.tcx()),
|
||||
trait_ref.substs.repr(this.tcx()),
|
||||
m.repr(this.tcx()));
|
||||
assert_eq!(m.generics.types.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs.types.get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::TypeSpace).len(),
|
||||
trait_ref.substs.regions().get_slice(subst::TypeSpace).len());
|
||||
assert_eq!(m.generics.types.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs.types.get_slice(subst::SelfSpace).len());
|
||||
assert_eq!(m.generics.regions.get_slice(subst::SelfSpace).len(),
|
||||
trait_ref.substs.regions().get_slice(subst::SelfSpace).len());
|
||||
}
|
||||
|
||||
// Because this trait derives from a where-clause, it
|
||||
// should not contain any inference variables or other
|
||||
|
@ -507,8 +509,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
this.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: m,
|
||||
kind: WhereClauseCandidate(poly_trait_ref, method_num)
|
||||
item: item,
|
||||
kind: WhereClauseCandidate(poly_trait_ref, item_num)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -523,7 +525,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
F: for<'b> FnMut(
|
||||
&mut ProbeContext<'b, 'tcx>,
|
||||
ty::PolyTraitRef<'tcx>,
|
||||
Rc<ty::Method<'tcx>>,
|
||||
ty::ImplOrTraitItem<'tcx>,
|
||||
usize,
|
||||
),
|
||||
{
|
||||
|
@ -531,17 +533,17 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
let tcx = self.tcx();
|
||||
for bound_trait_ref in traits::transitive_bounds(tcx, bounds) {
|
||||
let (pos, method) = match trait_method(tcx,
|
||||
bound_trait_ref.def_id(),
|
||||
self.method_name) {
|
||||
let (pos, item) = match trait_item(tcx,
|
||||
bound_trait_ref.def_id(),
|
||||
self.item_name) {
|
||||
Some(v) => v,
|
||||
None => { continue; }
|
||||
};
|
||||
|
||||
if !self.has_applicable_self(&*method) {
|
||||
if !self.has_applicable_self(&item) {
|
||||
self.record_static_candidate(TraitSource(bound_trait_ref.def_id()));
|
||||
} else {
|
||||
mk_cand(self, bound_trait_ref, method, pos);
|
||||
mk_cand(self, bound_trait_ref, item, pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -584,37 +586,34 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
ty::trait_items(self.tcx(), trait_def_id);
|
||||
let matching_index =
|
||||
trait_items.iter()
|
||||
.position(|item| item.name() == self.method_name);
|
||||
.position(|item| item.name() == self.item_name);
|
||||
let matching_index = match matching_index {
|
||||
Some(i) => i,
|
||||
None => { return Ok(()); }
|
||||
};
|
||||
let method = match (&*trait_items)[matching_index].as_opt_method() {
|
||||
Some(m) => m,
|
||||
None => { return Ok(()); }
|
||||
};
|
||||
let ref item = (&*trait_items)[matching_index];
|
||||
|
||||
// Check whether `trait_def_id` defines a method with suitable name:
|
||||
if !self.has_applicable_self(&*method) {
|
||||
if !self.has_applicable_self(item) {
|
||||
debug!("method has inapplicable self");
|
||||
self.record_static_candidate(TraitSource(trait_def_id));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.assemble_extension_candidates_for_trait_impls(trait_def_id,
|
||||
method.clone(),
|
||||
item.clone(),
|
||||
matching_index);
|
||||
|
||||
try!(self.assemble_closure_candidates(trait_def_id,
|
||||
method.clone(),
|
||||
item.clone(),
|
||||
matching_index));
|
||||
|
||||
self.assemble_projection_candidates(trait_def_id,
|
||||
method.clone(),
|
||||
item.clone(),
|
||||
matching_index);
|
||||
|
||||
self.assemble_where_clause_candidates(trait_def_id,
|
||||
method,
|
||||
item.clone(),
|
||||
matching_index);
|
||||
|
||||
Ok(())
|
||||
|
@ -622,8 +621,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
fn assemble_extension_candidates_for_trait_impls(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
method: Rc<ty::Method<'tcx>>,
|
||||
method_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
{
|
||||
ty::populate_implementations_for_trait_if_necessary(self.tcx(),
|
||||
trait_def_id);
|
||||
|
@ -657,7 +656,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
// Determine the receiver type that the method itself expects.
|
||||
let xform_self_ty =
|
||||
self.xform_self_ty(&method,
|
||||
self.xform_self_ty(&item,
|
||||
impl_trait_ref.self_ty(),
|
||||
impl_trait_ref.substs);
|
||||
|
||||
|
@ -665,8 +664,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: method.clone(),
|
||||
kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, method_index)
|
||||
item: item.clone(),
|
||||
kind: ExtensionImplCandidate(impl_def_id, impl_trait_ref, impl_substs, item_index)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -689,8 +688,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
fn assemble_closure_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
method_ty: Rc<ty::Method<'tcx>>,
|
||||
method_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
-> Result<(),MethodError>
|
||||
{
|
||||
// Check if this is one of the Fn,FnMut,FnOnce traits.
|
||||
|
@ -736,13 +735,13 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
&trait_def.generics,
|
||||
step.self_ty);
|
||||
|
||||
let xform_self_ty = self.xform_self_ty(&method_ty,
|
||||
let xform_self_ty = self.xform_self_ty(&item,
|
||||
step.self_ty,
|
||||
&substs);
|
||||
self.inherent_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: method_ty.clone(),
|
||||
kind: ClosureCandidate(trait_def_id, method_index)
|
||||
item: item.clone(),
|
||||
kind: ClosureCandidate(trait_def_id, item_index)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -751,16 +750,16 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
fn assemble_projection_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
method: Rc<ty::Method<'tcx>>,
|
||||
method_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
{
|
||||
debug!("assemble_projection_candidates(\
|
||||
trait_def_id={}, \
|
||||
method={}, \
|
||||
method_index={})",
|
||||
item={}, \
|
||||
item_index={})",
|
||||
trait_def_id.repr(self.tcx()),
|
||||
method.repr(self.tcx()),
|
||||
method_index);
|
||||
item.repr(self.tcx()),
|
||||
item_index);
|
||||
|
||||
for step in &*self.steps {
|
||||
debug!("assemble_projection_candidates: step={}",
|
||||
|
@ -792,7 +791,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
bound.repr(self.tcx()));
|
||||
|
||||
if self.infcx().can_equate(&step.self_ty, &bound.self_ty()).is_ok() {
|
||||
let xform_self_ty = self.xform_self_ty(&method,
|
||||
let xform_self_ty = self.xform_self_ty(&item,
|
||||
bound.self_ty(),
|
||||
bound.substs);
|
||||
|
||||
|
@ -802,8 +801,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: method.clone(),
|
||||
kind: ProjectionCandidate(trait_def_id, method_index)
|
||||
item: item.clone(),
|
||||
kind: ProjectionCandidate(trait_def_id, item_index)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -812,8 +811,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
fn assemble_where_clause_candidates(&mut self,
|
||||
trait_def_id: ast::DefId,
|
||||
method_ty: Rc<ty::Method<'tcx>>,
|
||||
method_index: usize)
|
||||
item: ty::ImplOrTraitItem<'tcx>,
|
||||
item_index: usize)
|
||||
{
|
||||
debug!("assemble_where_clause_candidates(trait_def_id={})",
|
||||
trait_def_id.repr(self.tcx()));
|
||||
|
@ -824,7 +823,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
.filter(|b| b.def_id() == trait_def_id)
|
||||
{
|
||||
let bound = self.erase_late_bound_regions(&poly_bound);
|
||||
let xform_self_ty = self.xform_self_ty(&method_ty,
|
||||
let xform_self_ty = self.xform_self_ty(&item,
|
||||
bound.self_ty(),
|
||||
bound.substs);
|
||||
|
||||
|
@ -834,8 +833,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
|
||||
self.extension_candidates.push(Candidate {
|
||||
xform_self_ty: xform_self_ty,
|
||||
method_ty: method_ty.clone(),
|
||||
kind: WhereClauseCandidate(poly_bound, method_index)
|
||||
item: item.clone(),
|
||||
kind: WhereClauseCandidate(poly_bound, item_index)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -860,7 +859,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
try!(self.assemble_extension_candidates_for_all_traits());
|
||||
|
||||
let out_of_scope_traits = match self.pick_core() {
|
||||
Some(Ok(p)) => vec![p.method_ty.container.id()],
|
||||
Some(Ok(p)) => vec![p.item.container().id()],
|
||||
Some(Err(MethodError::Ambiguity(v))) => v.into_iter().map(|source| {
|
||||
match source {
|
||||
TraitSource(id) => id,
|
||||
|
@ -1099,11 +1098,11 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
}
|
||||
|
||||
// If so, just use this trait and call it a day.
|
||||
let (trait_def_id, method_num) = trait_data;
|
||||
let method_ty = probes[0].method_ty.clone();
|
||||
let (trait_def_id, item_num) = trait_data;
|
||||
let item = probes[0].item.clone();
|
||||
Some(Pick {
|
||||
method_ty: method_ty,
|
||||
kind: TraitPick(trait_def_id, method_num),
|
||||
item: item,
|
||||
kind: TraitPick(trait_def_id, item_num),
|
||||
autoderefs: 0,
|
||||
autoref: None,
|
||||
unsize: None
|
||||
|
@ -1117,28 +1116,25 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup)
|
||||
}
|
||||
|
||||
fn has_applicable_self(&self, method: &ty::Method) -> bool {
|
||||
fn has_applicable_self(&self, item: &ty::ImplOrTraitItem) -> bool {
|
||||
// "fast track" -- check for usage of sugar
|
||||
match method.explicit_self {
|
||||
ty::StaticExplicitSelfCategory => {
|
||||
if self.mode == Mode::Path {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
ty::ByValueExplicitSelfCategory |
|
||||
ty::ByReferenceExplicitSelfCategory(..) |
|
||||
ty::ByBoxExplicitSelfCategory => {
|
||||
return true;
|
||||
}
|
||||
match *item {
|
||||
ty::ImplOrTraitItem::MethodTraitItem(ref method) =>
|
||||
match method.explicit_self {
|
||||
ty::StaticExplicitSelfCategory => self.mode == Mode::Path,
|
||||
ty::ByValueExplicitSelfCategory |
|
||||
ty::ByReferenceExplicitSelfCategory(..) |
|
||||
ty::ByBoxExplicitSelfCategory => true,
|
||||
},
|
||||
ty::ImplOrTraitItem::ConstTraitItem(..) => self.mode == Mode::Path,
|
||||
_ => false,
|
||||
}
|
||||
|
||||
// FIXME -- check for types that deref to `Self`,
|
||||
// like `Rc<Self>` and so on.
|
||||
//
|
||||
// Note also that the current code will break if this type
|
||||
// includes any of the type parameters defined on the method
|
||||
// -- but this could be overcome.
|
||||
return false;
|
||||
}
|
||||
|
||||
fn record_static_candidate(&mut self, source: CandidateSource) {
|
||||
|
@ -1146,10 +1142,23 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
}
|
||||
|
||||
fn xform_self_ty(&self,
|
||||
method: &Rc<ty::Method<'tcx>>,
|
||||
item: &ty::ImplOrTraitItem<'tcx>,
|
||||
impl_ty: Ty<'tcx>,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
match item.as_opt_method() {
|
||||
Some(ref method) => self.xform_method_self_ty(method, impl_ty,
|
||||
substs),
|
||||
None => impl_ty,
|
||||
}
|
||||
}
|
||||
|
||||
fn xform_method_self_ty(&self,
|
||||
method: &Rc<ty::Method<'tcx>>,
|
||||
impl_ty: Ty<'tcx>,
|
||||
substs: &subst::Substs<'tcx>)
|
||||
-> Ty<'tcx>
|
||||
{
|
||||
debug!("xform_self_ty(impl_ty={}, self_ty={}, substs={})",
|
||||
impl_ty.repr(self.tcx()),
|
||||
|
@ -1245,46 +1254,45 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_def_id: ast::DefId,
|
||||
method_name: ast::Name)
|
||||
-> Option<Rc<ty::Method<'tcx>>>
|
||||
fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
impl_def_id: ast::DefId,
|
||||
item_name: ast::Name)
|
||||
-> Option<ty::ImplOrTraitItem<'tcx>>
|
||||
{
|
||||
let impl_items = tcx.impl_items.borrow();
|
||||
let impl_items = impl_items.get(&impl_def_id).unwrap();
|
||||
impl_items
|
||||
.iter()
|
||||
.map(|&did| ty::impl_or_trait_item(tcx, did.def_id()))
|
||||
.find(|m| m.name() == method_name)
|
||||
.and_then(|item| item.as_opt_method())
|
||||
.find(|item| item.name() == item_name)
|
||||
}
|
||||
|
||||
/// Find method with name `method_name` defined in `trait_def_id` and return it, along with its
|
||||
/// index (or `None`, if no such method).
|
||||
fn trait_method<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_def_id: ast::DefId,
|
||||
method_name: ast::Name)
|
||||
-> Option<(usize, Rc<ty::Method<'tcx>>)>
|
||||
/// Find item with name `item_name` defined in `trait_def_id` and return it,
|
||||
/// along with its index (or `None`, if no such item).
|
||||
fn trait_item<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
trait_def_id: ast::DefId,
|
||||
item_name: ast::Name)
|
||||
-> Option<(usize, ty::ImplOrTraitItem<'tcx>)>
|
||||
{
|
||||
let trait_items = ty::trait_items(tcx, trait_def_id);
|
||||
debug!("trait_method; items: {:?}", trait_items);
|
||||
trait_items
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|&(_, ref item)| item.name() == method_name)
|
||||
.and_then(|(idx, item)| item.as_opt_method().map(|m| (idx, m)))
|
||||
.find(|&(_, ref item)| item.name() == item_name)
|
||||
.map(|(num, ref item)| (num, (*item).clone()))
|
||||
}
|
||||
|
||||
impl<'tcx> Candidate<'tcx> {
|
||||
fn to_unadjusted_pick(&self) -> Pick<'tcx> {
|
||||
Pick {
|
||||
method_ty: self.method_ty.clone(),
|
||||
item: self.item.clone(),
|
||||
kind: match self.kind {
|
||||
InherentImplCandidate(def_id, _) => {
|
||||
InherentImplPick(def_id)
|
||||
}
|
||||
ObjectCandidate(def_id, method_num, real_index) => {
|
||||
ObjectPick(def_id, method_num, real_index)
|
||||
ObjectCandidate(def_id, item_num, real_index) => {
|
||||
ObjectPick(def_id, item_num, real_index)
|
||||
}
|
||||
ExtensionImplCandidate(def_id, _, _, index) => {
|
||||
ExtensionImplPick(def_id, index)
|
||||
|
@ -1323,25 +1331,25 @@ impl<'tcx> Candidate<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn to_trait_data(&self) -> Option<(ast::DefId,MethodIndex)> {
|
||||
fn to_trait_data(&self) -> Option<(ast::DefId, ItemIndex)> {
|
||||
match self.kind {
|
||||
InherentImplCandidate(..) => {
|
||||
None
|
||||
}
|
||||
ObjectCandidate(trait_def_id, method_num, _) => {
|
||||
Some((trait_def_id, method_num))
|
||||
ObjectCandidate(trait_def_id, item_num, _) => {
|
||||
Some((trait_def_id, item_num))
|
||||
}
|
||||
ClosureCandidate(trait_def_id, method_num) => {
|
||||
Some((trait_def_id, method_num))
|
||||
ClosureCandidate(trait_def_id, item_num) => {
|
||||
Some((trait_def_id, item_num))
|
||||
}
|
||||
ExtensionImplCandidate(_, ref trait_ref, _, method_num) => {
|
||||
Some((trait_ref.def_id, method_num))
|
||||
ExtensionImplCandidate(_, ref trait_ref, _, item_num) => {
|
||||
Some((trait_ref.def_id, item_num))
|
||||
}
|
||||
WhereClauseCandidate(ref trait_ref, method_num) => {
|
||||
Some((trait_ref.def_id(), method_num))
|
||||
WhereClauseCandidate(ref trait_ref, item_num) => {
|
||||
Some((trait_ref.def_id(), item_num))
|
||||
}
|
||||
ProjectionCandidate(trait_def_id, method_num) => {
|
||||
Some((trait_def_id, method_num))
|
||||
ProjectionCandidate(trait_def_id, item_num) => {
|
||||
Some((trait_def_id, item_num))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1392,9 +1400,9 @@ impl<'tcx> Repr<'tcx> for PickKind<'tcx> {
|
|||
|
||||
impl<'tcx> Repr<'tcx> for Pick<'tcx> {
|
||||
fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String {
|
||||
format!("Pick(method_ty={}, autoderefs={},
|
||||
format!("Pick(item={}, autoderefs={},
|
||||
autoref={}, unsize={}, kind={:?})",
|
||||
self.method_ty.repr(tcx),
|
||||
self.item.repr(tcx),
|
||||
self.autoderefs,
|
||||
self.autoref.repr(tcx),
|
||||
self.unsize.repr(tcx),
|
||||
|
|
|
@ -78,7 +78,7 @@ type parameter).
|
|||
|
||||
pub use self::LvaluePreference::*;
|
||||
pub use self::Expectation::*;
|
||||
pub use self::compare_method::compare_impl_method;
|
||||
pub use self::compare_method::{compare_impl_method, compare_const_impl};
|
||||
use self::TupleArgumentsFlag::*;
|
||||
|
||||
use astconv::{self, ast_region_to_region, ast_ty_to_ty, AstConv, PathParamMode};
|
||||
|
@ -807,6 +807,9 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
|
|||
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(_, ref expr) => {
|
||||
check_const(ccx, impl_item.span, &*expr, impl_item.id)
|
||||
}
|
||||
ast::MethodImplItem(ref sig, ref body) => {
|
||||
check_method_body(ccx, &impl_pty.generics, sig, body,
|
||||
impl_item.id, impl_item.span);
|
||||
|
@ -822,14 +825,15 @@ pub fn check_item_body<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx ast::Item) {
|
|||
let trait_def = ty::lookup_trait_def(ccx.tcx, local_def(it.id));
|
||||
for trait_item in trait_items {
|
||||
match trait_item.node {
|
||||
ast::MethodTraitItem(_, None) => {
|
||||
// Nothing to do, since required methods don't have
|
||||
// bodies to check.
|
||||
ast::ConstTraitItem(_, Some(ref expr)) => {
|
||||
check_const(ccx, trait_item.span, &*expr, trait_item.id)
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, Some(ref body)) => {
|
||||
check_method_body(ccx, &trait_def.generics, sig, body,
|
||||
trait_item.id, trait_item.span);
|
||||
}
|
||||
ast::ConstTraitItem(_, None) |
|
||||
ast::MethodTraitItem(_, None) |
|
||||
ast::TypeTraitItem(..) => {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
@ -919,6 +923,48 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
// and compatible with trait signature
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(..) => {
|
||||
let impl_const_def_id = local_def(impl_item.id);
|
||||
let impl_const_ty = ty::impl_or_trait_item(ccx.tcx,
|
||||
impl_const_def_id);
|
||||
|
||||
// Find associated const definition.
|
||||
let opt_associated_const =
|
||||
trait_items.iter()
|
||||
.find(|ac| ac.name() == impl_const_ty.name());
|
||||
match opt_associated_const {
|
||||
Some(associated_const) => {
|
||||
match (associated_const, &impl_const_ty) {
|
||||
(&ty::ConstTraitItem(ref const_trait),
|
||||
&ty::ConstTraitItem(ref const_impl)) => {
|
||||
compare_const_impl(ccx.tcx,
|
||||
&const_impl,
|
||||
impl_item.span,
|
||||
&const_trait,
|
||||
&*impl_trait_ref);
|
||||
}
|
||||
_ => {
|
||||
span_err!(tcx.sess, impl_item.span, E0323,
|
||||
"item `{}` is an associated const, \
|
||||
which doesn't match its trait `{}`",
|
||||
token::get_name(impl_const_ty.name()),
|
||||
impl_trait_ref.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// This is `span_bug` as it should have already been
|
||||
// caught in resolve.
|
||||
tcx.sess.span_bug(
|
||||
impl_item.span,
|
||||
&format!(
|
||||
"associated const `{}` is not a member of \
|
||||
trait `{}`",
|
||||
token::get_name(impl_const_ty.name()),
|
||||
impl_trait_ref.repr(tcx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::MethodImplItem(_, ref body) => {
|
||||
let impl_method_def_id = local_def(impl_item.id);
|
||||
let impl_item_ty = ty::impl_or_trait_item(ccx.tcx,
|
||||
|
@ -942,13 +988,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
&*impl_trait_ref);
|
||||
}
|
||||
_ => {
|
||||
// This is span_bug as it should have already been
|
||||
// caught in resolve.
|
||||
tcx.sess.span_bug(
|
||||
impl_item.span,
|
||||
&format!("item `{}` is of a different kind from its trait `{}`",
|
||||
token::get_name(impl_item_ty.name()),
|
||||
impl_trait_ref.repr(tcx)));
|
||||
span_err!(tcx.sess, impl_item.span, E0324,
|
||||
"item `{}` is an associated method, \
|
||||
which doesn't match its trait `{}`",
|
||||
token::get_name(impl_item_ty.name()),
|
||||
impl_trait_ref.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -978,13 +1022,11 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
match (associated_type, &typedef_ty) {
|
||||
(&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {}
|
||||
_ => {
|
||||
// This is `span_bug` as it should have
|
||||
// already been caught in resolve.
|
||||
tcx.sess.span_bug(
|
||||
impl_item.span,
|
||||
&format!("item `{}` is of a different kind from its trait `{}`",
|
||||
token::get_name(typedef_ty.name()),
|
||||
impl_trait_ref.repr(tcx)));
|
||||
span_err!(tcx.sess, impl_item.span, E0325,
|
||||
"item `{}` is an associated type, \
|
||||
which doesn't match its trait `{}`",
|
||||
token::get_name(typedef_ty.name()),
|
||||
impl_trait_ref.repr(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1008,9 +1050,27 @@ 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();
|
||||
for trait_item in &*trait_items {
|
||||
match *trait_item {
|
||||
ty::ConstTraitItem(ref associated_const) => {
|
||||
let is_implemented = impl_items.iter().any(|ii| {
|
||||
match ii.node {
|
||||
ast::ConstImplItem(..) => {
|
||||
ii.ident.name == associated_const.name
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
let is_provided =
|
||||
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)));
|
||||
}
|
||||
}
|
||||
ty::MethodTraitItem(ref trait_method) => {
|
||||
let is_implemented =
|
||||
impl_items.iter().any(|ii| {
|
||||
|
@ -1018,8 +1078,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
ast::MethodImplItem(..) => {
|
||||
ii.ident.name == trait_method.name
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => false,
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
let is_provided =
|
||||
|
@ -1034,8 +1093,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
ast::TypeImplItem(_) => {
|
||||
ii.ident.name == associated_type.name
|
||||
}
|
||||
ast::MethodImplItem(..) |
|
||||
ast::MacImplItem(_) => false,
|
||||
_ => false,
|
||||
}
|
||||
});
|
||||
if !is_implemented {
|
||||
|
@ -3171,53 +3229,20 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
&format!("unbound path {}", expr.repr(tcx)))
|
||||
};
|
||||
|
||||
let def = path_res.base_def;
|
||||
if path_res.depth == 0 {
|
||||
if let Some((opt_ty, segments, def)) =
|
||||
resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path,
|
||||
expr.span, expr.id) {
|
||||
let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx,
|
||||
expr.span,
|
||||
def);
|
||||
instantiate_path(fcx,
|
||||
&path.segments,
|
||||
segments,
|
||||
scheme,
|
||||
&predicates,
|
||||
opt_self_ty,
|
||||
opt_ty,
|
||||
def,
|
||||
expr.span,
|
||||
id);
|
||||
} else {
|
||||
let ty_segments = path.segments.init();
|
||||
let base_ty_end = path.segments.len() - path_res.depth;
|
||||
let ty = astconv::finish_resolving_def_to_ty(fcx,
|
||||
fcx,
|
||||
expr.span,
|
||||
PathParamMode::Optional,
|
||||
&def,
|
||||
opt_self_ty,
|
||||
&ty_segments[..base_ty_end],
|
||||
&ty_segments[base_ty_end..]);
|
||||
let method_segment = path.segments.last().unwrap();
|
||||
let method_name = method_segment.identifier.name;
|
||||
match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) {
|
||||
Ok((def, lp)) => {
|
||||
// Write back the new resolution.
|
||||
tcx.def_map.borrow_mut().insert(id, def::PathResolution {
|
||||
base_def: def,
|
||||
last_private: path_res.last_private.or(lp),
|
||||
depth: 0
|
||||
});
|
||||
|
||||
let (scheme, predicates) =
|
||||
type_scheme_and_predicates_for_def(fcx, expr.span, def);
|
||||
instantiate_path(fcx, slice::ref_slice(method_segment),
|
||||
scheme, &predicates,
|
||||
Some(ty), def, expr.span, id);
|
||||
}
|
||||
Err(error) => {
|
||||
method::report_error(fcx, expr.span, ty,
|
||||
method_name, None, error);
|
||||
fcx.write_error(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We always require that the type provided as the value for
|
||||
|
@ -3679,6 +3704,52 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
unifier();
|
||||
}
|
||||
|
||||
pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>,
|
||||
path_res: def::PathResolution,
|
||||
opt_self_ty: Option<Ty<'tcx>>,
|
||||
path: &'a ast::Path,
|
||||
span: Span,
|
||||
node_id: ast::NodeId)
|
||||
-> Option<(Option<Ty<'tcx>>,
|
||||
&'a [ast::PathSegment],
|
||||
def::Def)>
|
||||
{
|
||||
// If fully resolved already, we don't have to do anything.
|
||||
if path_res.depth == 0 {
|
||||
Some((opt_self_ty, &path.segments, path_res.base_def))
|
||||
} else {
|
||||
let mut def = path_res.base_def;
|
||||
let ty_segments = path.segments.init();
|
||||
let base_ty_end = path.segments.len() - path_res.depth;
|
||||
let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span,
|
||||
PathParamMode::Optional,
|
||||
&mut def,
|
||||
opt_self_ty,
|
||||
&ty_segments[..base_ty_end],
|
||||
&ty_segments[base_ty_end..]);
|
||||
let item_segment = path.segments.last().unwrap();
|
||||
let item_name = item_segment.identifier.name;
|
||||
match method::resolve_ufcs(fcx, span, item_name, ty, node_id) {
|
||||
Ok((def, lp)) => {
|
||||
// Write back the new resolution.
|
||||
fcx.ccx.tcx.def_map.borrow_mut()
|
||||
.insert(node_id, def::PathResolution {
|
||||
base_def: def,
|
||||
last_private: path_res.last_private.or(lp),
|
||||
depth: 0
|
||||
});
|
||||
Some((Some(ty), slice::ref_slice(item_segment), def))
|
||||
}
|
||||
Err(error) => {
|
||||
method::report_error(fcx, span, ty,
|
||||
item_name, None, error);
|
||||
fcx.write_error(node_id);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_path_type_parameters(fcx: &FnCtxt,
|
||||
expr: &ast::Expr)
|
||||
{
|
||||
|
@ -4207,7 +4278,7 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
def::DefFn(id, _) | def::DefMethod(id, _) |
|
||||
def::DefStatic(id, _) | def::DefVariant(_, id, _) |
|
||||
def::DefStruct(id) | def::DefConst(id) => {
|
||||
def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id, _) => {
|
||||
(ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id))
|
||||
}
|
||||
def::DefTrait(_) |
|
||||
|
@ -4249,7 +4320,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
// Luckily, we can (at least for now) deduce the intermediate steps
|
||||
// just from the end-point.
|
||||
//
|
||||
// There are basically three cases to consider:
|
||||
// There are basically four cases to consider:
|
||||
//
|
||||
// 1. Reference to a *type*, such as a struct or enum:
|
||||
//
|
||||
|
@ -4299,6 +4370,16 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
// `SomeStruct::<A>`, contains parameters in TypeSpace, and the
|
||||
// final segment, `foo::<B>` contains parameters in fn space.
|
||||
//
|
||||
// 4. Reference to an *associated const*:
|
||||
//
|
||||
// impl<A> AnotherStruct<A> {
|
||||
// const FOO: B = BAR;
|
||||
// }
|
||||
//
|
||||
// The path in this case will look like
|
||||
// `a::b::AnotherStruct::<A>::FOO`, so the penultimate segment
|
||||
// only will have parameters in TypeSpace.
|
||||
//
|
||||
// The first step then is to categorize the segments appropriately.
|
||||
|
||||
assert!(!segments.is_empty());
|
||||
|
@ -4350,6 +4431,23 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
def::DefAssociatedConst(_, provenance) => {
|
||||
match provenance {
|
||||
def::FromTrait(trait_did) => {
|
||||
callee::check_legal_trait_for_method_call(fcx.ccx, span, trait_did)
|
||||
}
|
||||
def::FromImpl(_) => {}
|
||||
}
|
||||
|
||||
if segments.len() >= 2 {
|
||||
segment_spaces = repeat(None).take(segments.len() - 2).collect();
|
||||
segment_spaces.push(Some(subst::TypeSpace));
|
||||
segment_spaces.push(None);
|
||||
} else {
|
||||
segment_spaces = vec![None];
|
||||
}
|
||||
}
|
||||
|
||||
// Other cases. Various nonsense that really shouldn't show up
|
||||
// here. If they do, an error will have been reported
|
||||
// elsewhere. (I hope)
|
||||
|
|
|
@ -20,8 +20,9 @@ use metadata::csearch::{each_impl, get_impl_trait};
|
|||
use metadata::csearch;
|
||||
use middle::subst::{self, Subst};
|
||||
use middle::ty::RegionEscape;
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
|
||||
use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type};
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId};
|
||||
use middle::ty::{MethodTraitItemId, TypeTraitItemId};
|
||||
use middle::ty::{ParameterEnvironment, lookup_item_type};
|
||||
use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err};
|
||||
use middle::ty::{ty_param, TypeScheme, ty_ptr};
|
||||
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
|
||||
|
@ -278,6 +279,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
let mut items: Vec<ImplOrTraitItemId> =
|
||||
impl_items.iter().map(|impl_item| {
|
||||
match impl_item.node {
|
||||
ast::ConstImplItem(..) => {
|
||||
ConstTraitItemId(local_def(impl_item.id))
|
||||
}
|
||||
ast::MethodImplItem(..) => {
|
||||
MethodTraitItemId(local_def(impl_item.id))
|
||||
}
|
||||
|
@ -348,7 +352,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
|
|||
.insert(item_def_id.def_id(), source);
|
||||
}
|
||||
}
|
||||
ty::TypeTraitItem(_) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> {
|
|||
let def_id = local_def(method_id);
|
||||
match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() {
|
||||
ty::MethodTraitItem(ref mty) => mty.clone(),
|
||||
ty::TypeTraitItem(..) => {
|
||||
_ => {
|
||||
self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id));
|
||||
}
|
||||
}
|
||||
|
@ -692,11 +692,37 @@ fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
container: ImplOrTraitItemContainer,
|
||||
ident: ast::Ident,
|
||||
id: ast::NodeId,
|
||||
vis: ast::Visibility,
|
||||
ty: ty::Ty<'tcx>,
|
||||
default: Option<&ast::Expr>)
|
||||
{
|
||||
ccx.tcx.predicates.borrow_mut().insert(local_def(id),
|
||||
ty::GenericPredicates::empty());
|
||||
|
||||
write_ty_to_tcx(ccx.tcx, id, ty);
|
||||
let default_id = default.map(|expr| local_def(expr.id));
|
||||
|
||||
let associated_const = Rc::new(ty::AssociatedConst {
|
||||
name: ident.name,
|
||||
vis: vis,
|
||||
def_id: local_def(id),
|
||||
container: container,
|
||||
ty: ty,
|
||||
default: default_id,
|
||||
});
|
||||
ccx.tcx.impl_or_trait_items.borrow_mut()
|
||||
.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)
|
||||
container: ImplOrTraitItemContainer,
|
||||
ident: ast::Ident,
|
||||
id: ast::NodeId,
|
||||
vis: ast::Visibility)
|
||||
{
|
||||
let associated_type = Rc::new(ty::AssociatedType {
|
||||
name: ident.name,
|
||||
|
@ -829,45 +855,56 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
it.vis
|
||||
};
|
||||
|
||||
// Convert all the associated consts.
|
||||
for impl_item in impl_items {
|
||||
if let ast::ConstImplItem(ref ty, ref expr) = impl_item.node {
|
||||
let ty = ccx.icx(&ty_predicates)
|
||||
.to_ty(&ExplicitRscope, &*ty);
|
||||
tcx.tcache.borrow_mut().insert(local_def(impl_item.id),
|
||||
TypeScheme {
|
||||
generics: ty_generics.clone(),
|
||||
ty: ty,
|
||||
});
|
||||
convert_associated_const(ccx, ImplContainer(local_def(it.id)),
|
||||
impl_item.ident, impl_item.id,
|
||||
impl_item.vis.inherit_from(parent_visibility),
|
||||
ty, Some(&*expr));
|
||||
}
|
||||
}
|
||||
|
||||
// Convert all the associated types.
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::TypeImplItem(ref ty) => {
|
||||
if opt_trait_ref.is_none() {
|
||||
span_err!(tcx.sess, impl_item.span, E0202,
|
||||
"associated items 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);
|
||||
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");
|
||||
}
|
||||
ast::MethodImplItem(..) |
|
||||
ast::MacImplItem(_) => {}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
let methods = impl_items.iter().filter_map(|ii| {
|
||||
match ii.node {
|
||||
ast::MethodImplItem(ref sig, _) => {
|
||||
// if the method specifies a visibility, use that, otherwise
|
||||
// inherit the visibility from the impl (so `foo` in `pub impl
|
||||
// { fn foo(); }` is public, but private in `priv impl { fn
|
||||
// foo(); }`).
|
||||
let method_vis = ii.vis.inherit_from(parent_visibility);
|
||||
Some((sig, ii.id, ii.ident, method_vis, ii.span))
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => None
|
||||
if let ast::MethodImplItem(ref sig, _) = ii.node {
|
||||
// if the method specifies a visibility, use that, otherwise
|
||||
// inherit the visibility from the impl (so `foo` in `pub impl
|
||||
// { fn foo(); }` is public, but private in `priv impl { fn
|
||||
// foo(); }`).
|
||||
let method_vis = ii.vis.inherit_from(parent_visibility);
|
||||
Some((sig, ii.id, ii.ident, method_vis, ii.span))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
convert_methods(ccx,
|
||||
|
@ -878,18 +915,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
&ty_predicates);
|
||||
|
||||
for impl_item in impl_items {
|
||||
match impl_item.node {
|
||||
ast::MethodImplItem(ref sig, ref body) => {
|
||||
let body_id = body.id;
|
||||
check_method_self_type(ccx,
|
||||
&BindingRscope::new(),
|
||||
ccx.method_ty(impl_item.id),
|
||||
selfty,
|
||||
&sig.explicit_self,
|
||||
body_id);
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => {}
|
||||
if let ast::MethodImplItem(ref sig, ref body) = impl_item.node {
|
||||
let body_id = body.id;
|
||||
check_method_self_type(ccx,
|
||||
&BindingRscope::new(),
|
||||
ccx.method_ty(impl_item.id),
|
||||
selfty,
|
||||
&sig.explicit_self,
|
||||
body_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -920,18 +953,37 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
// Convert all the associated types.
|
||||
for trait_item in trait_items {
|
||||
match trait_item.node {
|
||||
ast::MethodTraitItem(..) => {}
|
||||
ast::ConstTraitItem(ref ty, ref default) => {
|
||||
let ty = ccx.icx(&trait_predicates)
|
||||
.to_ty(&ExplicitRscope, ty);
|
||||
tcx.tcache.borrow_mut().insert(local_def(trait_item.id),
|
||||
TypeScheme {
|
||||
generics: trait_def.generics.clone(),
|
||||
ty: ty,
|
||||
});
|
||||
convert_associated_const(ccx, TraitContainer(local_def(it.id)),
|
||||
trait_item.ident, trait_item.id,
|
||||
ast::Public, ty, default.as_ref().map(|d| &**d));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
// 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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
|
||||
let methods = trait_items.iter().filter_map(|ti| {
|
||||
let sig = match ti.node {
|
||||
ast::MethodTraitItem(ref sig, _) => sig,
|
||||
ast::TypeTraitItem(..) => return None,
|
||||
_ => return None,
|
||||
};
|
||||
Some((sig, ti.id, ti.ident, ast::Inherited, ti.span))
|
||||
});
|
||||
|
@ -948,6 +1000,9 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| {
|
||||
let def_id = local_def(trait_item.id);
|
||||
match trait_item.node {
|
||||
ast::ConstTraitItem(..) => {
|
||||
ty::ConstTraitItemId(def_id)
|
||||
}
|
||||
ast::MethodTraitItem(..) => {
|
||||
ty::MethodTraitItemId(def_id)
|
||||
}
|
||||
|
@ -963,7 +1018,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
for trait_item in trait_items {
|
||||
let sig = match trait_item.node {
|
||||
ast::MethodTraitItem(ref sig, _) => sig,
|
||||
ast::TypeTraitItem(..) => continue
|
||||
_ => continue
|
||||
};
|
||||
check_method_self_type(ccx,
|
||||
&BindingRscope::new(),
|
||||
|
@ -1186,8 +1241,8 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
|
||||
let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| {
|
||||
match trait_item.node {
|
||||
ast::MethodTraitItem(..) => None,
|
||||
ast::TypeTraitItem(..) => Some(trait_item.ident.name),
|
||||
_ => None,
|
||||
}
|
||||
}).collect();
|
||||
|
||||
|
@ -1261,7 +1316,7 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt,
|
|||
trait_items.iter().any(|trait_item| {
|
||||
match trait_item.node {
|
||||
ast::TypeTraitItem(..) => trait_item.ident.name == assoc_name,
|
||||
ast::MethodTraitItem(..) => false,
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1321,7 +1376,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item)
|
|||
trait_items.iter().flat_map(|trait_item| {
|
||||
let bounds = match trait_item.node {
|
||||
ast::TypeTraitItem(ref bounds, _) => bounds,
|
||||
ast::MethodTraitItem(..) => {
|
||||
_ => {
|
||||
return vec!().into_iter();
|
||||
}
|
||||
};
|
||||
|
@ -2237,7 +2292,8 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
|
|||
impl_items.iter()
|
||||
.filter_map(|item| match item.node {
|
||||
ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)),
|
||||
ast::MethodImplItem(..) | ast::MacImplItem(..) => None,
|
||||
ast::ConstImplItem(..) | ast::MethodImplItem(..) |
|
||||
ast::MacImplItem(..) => None,
|
||||
})
|
||||
.flat_map(|ty| ctp::parameters_for_type(ty).into_iter())
|
||||
.filter_map(|p| match p {
|
||||
|
|
|
@ -176,6 +176,11 @@ register_diagnostics! {
|
|||
E0320, // recursive overflow during dropck
|
||||
E0321, // extended coherence rules for defaulted traits violated
|
||||
E0322, // cannot implement Sized explicitly
|
||||
E0323, // implemented an associated const when another trait item expected
|
||||
E0324, // implemented a method when another trait item expected
|
||||
E0325, // implemented an associated type when another trait item expected
|
||||
E0326, // associated const implemented with different type from trait
|
||||
E0327, // referred to method instead of constant in match pattern
|
||||
E0366, // dropck forbid specialization to concrete type or region
|
||||
E0367, // dropck forbid specialization to predicate not in struct/enum
|
||||
E0368, // binary operation `<op>=` cannot be applied to types
|
||||
|
|
|
@ -22,12 +22,13 @@ use rustc::middle::def;
|
|||
use rustc::middle::ty;
|
||||
use rustc::middle::subst;
|
||||
use rustc::middle::stability;
|
||||
use rustc::middle::const_eval;
|
||||
|
||||
use core::DocContext;
|
||||
use doctree;
|
||||
use clean;
|
||||
|
||||
use super::Clean;
|
||||
use super::{Clean, ToSource};
|
||||
|
||||
/// Attempt to inline the definition of a local node id into this AST.
|
||||
///
|
||||
|
@ -106,7 +107,7 @@ fn try_inline_def(cx: &DocContext, tcx: &ty::ctxt,
|
|||
record_extern_fqn(cx, did, clean::TypeStatic);
|
||||
clean::StaticItem(build_static(cx, tcx, did, mtbl))
|
||||
}
|
||||
def::DefConst(did) => {
|
||||
def::DefConst(did) | def::DefAssociatedConst(did, _) => {
|
||||
record_extern_fqn(cx, did, clean::TypeConst);
|
||||
clean::ConstantItem(build_const(cx, tcx, did))
|
||||
}
|
||||
|
@ -312,6 +313,27 @@ pub fn build_impl(cx: &DocContext,
|
|||
let did = did.def_id();
|
||||
let impl_item = ty::impl_or_trait_item(tcx, did);
|
||||
match impl_item {
|
||||
ty::ConstTraitItem(ref assoc_const) => {
|
||||
let did = assoc_const.def_id;
|
||||
let type_scheme = ty::lookup_item_type(tcx, did);
|
||||
let default = match assoc_const.default {
|
||||
Some(_) => Some(const_eval::lookup_const_by_id(tcx, did, None)
|
||||
.unwrap().span.to_src(cx)),
|
||||
None => None,
|
||||
};
|
||||
Some(clean::Item {
|
||||
name: Some(assoc_const.name.clean(cx)),
|
||||
inner: clean::AssociatedConstItem(
|
||||
type_scheme.ty.clean(cx),
|
||||
default,
|
||||
),
|
||||
source: clean::Span::empty(),
|
||||
attrs: vec![],
|
||||
visibility: None,
|
||||
stability: stability::lookup(tcx, did).clean(cx),
|
||||
def_id: did
|
||||
})
|
||||
}
|
||||
ty::MethodTraitItem(method) => {
|
||||
if method.vis != ast::Public && associated_trait.is_none() {
|
||||
return None
|
||||
|
@ -443,7 +465,7 @@ fn build_const(cx: &DocContext, tcx: &ty::ctxt,
|
|||
use rustc::middle::const_eval;
|
||||
use syntax::print::pprust;
|
||||
|
||||
let expr = const_eval::lookup_const_by_id(tcx, did).unwrap_or_else(|| {
|
||||
let expr = const_eval::lookup_const_by_id(tcx, did, None).unwrap_or_else(|| {
|
||||
panic!("expected lookup_const_by_id to succeed for {:?}", did);
|
||||
});
|
||||
debug!("converting constant expr {:?} to snippet", expr);
|
||||
|
|
|
@ -361,6 +361,7 @@ pub enum ItemEnum {
|
|||
ForeignStaticItem(Static),
|
||||
MacroItem(Macro),
|
||||
PrimitiveItem(PrimitiveType),
|
||||
AssociatedConstItem(Type, Option<String>),
|
||||
AssociatedTypeItem(Vec<TyParamBound>, Option<Type>),
|
||||
DefaultImplItem(DefaultImpl),
|
||||
}
|
||||
|
@ -1235,6 +1236,11 @@ impl Clean<PolyTrait> for ast::PolyTraitRef {
|
|||
impl Clean<Item> for ast::TraitItem {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
let inner = match self.node {
|
||||
ast::ConstTraitItem(ref ty, ref default) => {
|
||||
AssociatedConstItem(ty.clean(cx),
|
||||
default.as_ref().map(|expr|
|
||||
expr.span.to_src(cx)))
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, Some(_)) => {
|
||||
MethodItem(sig.clean(cx))
|
||||
}
|
||||
|
@ -1260,6 +1266,12 @@ impl Clean<Item> for ast::TraitItem {
|
|||
impl Clean<Item> for ast::ImplItem {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
let inner = match self.node {
|
||||
ast::ConstImplItem(ref ty, ref expr) => {
|
||||
ConstantItem(Constant{
|
||||
type_: ty.clean(cx),
|
||||
expr: expr.span.to_src(cx),
|
||||
})
|
||||
}
|
||||
ast::MethodImplItem(ref sig, _) => {
|
||||
MethodItem(sig.clean(cx))
|
||||
}
|
||||
|
@ -1363,6 +1375,7 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
|
|||
impl<'tcx> Clean<Item> for ty::ImplOrTraitItem<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
match *self {
|
||||
ty::ConstTraitItem(ref cti) => cti.clean(cx),
|
||||
ty::MethodTraitItem(ref mti) => mti.clean(cx),
|
||||
ty::TypeTraitItem(ref tti) => tti.clean(cx),
|
||||
}
|
||||
|
@ -2509,6 +2522,8 @@ fn name_from_pat(p: &ast::Pat) -> String {
|
|||
PatWild(PatWildMulti) => "..".to_string(),
|
||||
PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(),
|
||||
PatEnum(ref p, _) => path_to_string(p),
|
||||
PatQPath(..) => panic!("tried to get argument name from PatQPath, \
|
||||
which is not allowed in function arguments"),
|
||||
PatStruct(ref name, ref fields, etc) => {
|
||||
format!("{} {{ {}{} }}", path_to_string(name),
|
||||
fields.iter().map(|&Spanned { node: ref fp, .. }|
|
||||
|
@ -2672,6 +2687,20 @@ impl Clean<Stability> for attr::Stability {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Clean<Item> for ty::AssociatedConst<'tcx> {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
Item {
|
||||
source: DUMMY_SP.clean(cx),
|
||||
name: Some(self.name.clean(cx)),
|
||||
attrs: Vec::new(),
|
||||
inner: AssociatedConstItem(self.ty.clean(cx), None),
|
||||
visibility: None,
|
||||
def_id: self.def_id,
|
||||
stability: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clean<Item> for ty::AssociatedType {
|
||||
fn clean(&self, cx: &DocContext) -> Item {
|
||||
// When loading a cross-crate associated type, the bounds for this type
|
||||
|
|
|
@ -39,6 +39,7 @@ pub enum ItemType {
|
|||
Primitive = 15,
|
||||
AssociatedType = 16,
|
||||
Constant = 17,
|
||||
AssociatedConst = 18,
|
||||
}
|
||||
|
||||
impl ItemType {
|
||||
|
@ -63,6 +64,7 @@ impl ItemType {
|
|||
clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic
|
||||
clean::MacroItem(..) => ItemType::Macro,
|
||||
clean::PrimitiveItem(..) => ItemType::Primitive,
|
||||
clean::AssociatedConstItem(..) => ItemType::AssociatedConst,
|
||||
clean::AssociatedTypeItem(..) => ItemType::AssociatedType,
|
||||
clean::DefaultImplItem(..) => ItemType::Impl,
|
||||
}
|
||||
|
@ -102,6 +104,7 @@ impl ItemType {
|
|||
ItemType::Primitive => "primitive",
|
||||
ItemType::AssociatedType => "associatedtype",
|
||||
ItemType::Constant => "constant",
|
||||
ItemType::AssociatedConst => "associatedconstant",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1629,6 +1629,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
|
|||
ItemType::Macro => ("macros", "Macros"),
|
||||
ItemType::Primitive => ("primitives", "Primitive Types"),
|
||||
ItemType::AssociatedType => ("associated-types", "Associated Types"),
|
||||
ItemType::AssociatedConst => ("associated-consts", "Associated Constants"),
|
||||
};
|
||||
try!(write!(w,
|
||||
"<h2 id='{id}' class='section-header'>\
|
||||
|
@ -1799,7 +1800,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
try!(write!(w, "{{\n"));
|
||||
for t in &types {
|
||||
try!(write!(w, " "));
|
||||
try!(render_method(w, t, MethodLink::Anchor));
|
||||
try!(render_assoc_item(w, t, AssocItemLink::Anchor));
|
||||
try!(write!(w, ";\n"));
|
||||
}
|
||||
if !types.is_empty() && !required.is_empty() {
|
||||
|
@ -1807,7 +1808,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
}
|
||||
for m in &required {
|
||||
try!(write!(w, " "));
|
||||
try!(render_method(w, m, MethodLink::Anchor));
|
||||
try!(render_assoc_item(w, m, AssocItemLink::Anchor));
|
||||
try!(write!(w, ";\n"));
|
||||
}
|
||||
if !required.is_empty() && !provided.is_empty() {
|
||||
|
@ -1815,7 +1816,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
}
|
||||
for m in &provided {
|
||||
try!(write!(w, " "));
|
||||
try!(render_method(w, m, MethodLink::Anchor));
|
||||
try!(render_assoc_item(w, m, AssocItemLink::Anchor));
|
||||
try!(write!(w, " {{ ... }}\n"));
|
||||
}
|
||||
try!(write!(w, "}}"));
|
||||
|
@ -1831,7 +1832,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
ty = shortty(m),
|
||||
name = *m.name.as_ref().unwrap(),
|
||||
stab = m.stability_class()));
|
||||
try!(render_method(w, m, MethodLink::Anchor));
|
||||
try!(render_assoc_item(w, m, AssocItemLink::Anchor));
|
||||
try!(write!(w, "</code></h3>"));
|
||||
try!(document(w, m));
|
||||
Ok(())
|
||||
|
@ -1871,7 +1872,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
}
|
||||
|
||||
// If there are methods directly on this trait object, render them here.
|
||||
try!(render_methods(w, it.def_id, MethodRender::All));
|
||||
try!(render_assoc_items(w, it.def_id, AssocItemRender::All));
|
||||
|
||||
let cache = cache();
|
||||
try!(write!(w, "
|
||||
|
@ -1903,6 +1904,17 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item,
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn assoc_const(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
ty: &clean::Type, default: &Option<String>)
|
||||
-> fmt::Result {
|
||||
try!(write!(w, "const {}", it.name.as_ref().unwrap()));
|
||||
try!(write!(w, ": {}", ty));
|
||||
if let Some(ref default) = *default {
|
||||
try!(write!(w, " = {}", default));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
bounds: &Vec<clean::TyParamBound>,
|
||||
default: &Option<clean::Type>)
|
||||
|
@ -1917,19 +1929,19 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item,
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn render_method(w: &mut fmt::Formatter, meth: &clean::Item,
|
||||
link: MethodLink) -> fmt::Result {
|
||||
fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
|
||||
link: AssocItemLink) -> fmt::Result {
|
||||
fn method(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
unsafety: ast::Unsafety, abi: abi::Abi,
|
||||
g: &clean::Generics, selfty: &clean::SelfTy,
|
||||
d: &clean::FnDecl, link: MethodLink) -> fmt::Result {
|
||||
d: &clean::FnDecl, link: AssocItemLink) -> fmt::Result {
|
||||
use syntax::abi::Abi;
|
||||
|
||||
let name = it.name.as_ref().unwrap();
|
||||
let anchor = format!("#{}.{}", shortty(it), name);
|
||||
let href = match link {
|
||||
MethodLink::Anchor => anchor,
|
||||
MethodLink::GotoSource(did) => {
|
||||
AssocItemLink::Anchor => anchor,
|
||||
AssocItemLink::GotoSource(did) => {
|
||||
href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor)
|
||||
}
|
||||
};
|
||||
|
@ -1958,10 +1970,13 @@ fn render_method(w: &mut fmt::Formatter, meth: &clean::Item,
|
|||
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
|
||||
link)
|
||||
}
|
||||
clean::AssociatedConstItem(ref ty, ref default) => {
|
||||
assoc_const(w, meth, ty, default)
|
||||
}
|
||||
clean::AssociatedTypeItem(ref bounds, ref default) => {
|
||||
assoc_type(w, meth, bounds, default)
|
||||
}
|
||||
_ => panic!("render_method called on non-method")
|
||||
_ => panic!("render_assoc_item called on non-associated-item")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2001,7 +2016,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item,
|
|||
try!(write!(w, "</table>"));
|
||||
}
|
||||
}
|
||||
render_methods(w, it.def_id, MethodRender::All)
|
||||
render_assoc_items(w, it.def_id, AssocItemRender::All)
|
||||
}
|
||||
|
||||
fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
|
||||
|
@ -2100,7 +2115,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item,
|
|||
try!(write!(w, "</table>"));
|
||||
|
||||
}
|
||||
try!(render_methods(w, it.def_id, MethodRender::All));
|
||||
try!(render_assoc_items(w, it.def_id, AssocItemRender::All));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -2184,19 +2199,19 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
|
|||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum MethodLink {
|
||||
enum AssocItemLink {
|
||||
Anchor,
|
||||
GotoSource(ast::DefId),
|
||||
}
|
||||
|
||||
enum MethodRender<'a> {
|
||||
enum AssocItemRender<'a> {
|
||||
All,
|
||||
DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type },
|
||||
}
|
||||
|
||||
fn render_methods(w: &mut fmt::Formatter,
|
||||
it: ast::DefId,
|
||||
what: MethodRender) -> fmt::Result {
|
||||
fn render_assoc_items(w: &mut fmt::Formatter,
|
||||
it: ast::DefId,
|
||||
what: AssocItemRender) -> fmt::Result {
|
||||
let c = cache();
|
||||
let v = match c.impls.get(&it) {
|
||||
Some(v) => v,
|
||||
|
@ -2207,21 +2222,21 @@ fn render_methods(w: &mut fmt::Formatter,
|
|||
});
|
||||
if !non_trait.is_empty() {
|
||||
let render_header = match what {
|
||||
MethodRender::All => {
|
||||
AssocItemRender::All => {
|
||||
try!(write!(w, "<h2 id='methods'>Methods</h2>"));
|
||||
true
|
||||
}
|
||||
MethodRender::DerefFor { trait_, type_ } => {
|
||||
AssocItemRender::DerefFor { trait_, type_ } => {
|
||||
try!(write!(w, "<h2 id='deref-methods'>Methods from \
|
||||
{}<Target={}></h2>", trait_, type_));
|
||||
false
|
||||
}
|
||||
};
|
||||
for i in &non_trait {
|
||||
try!(render_impl(w, i, MethodLink::Anchor, render_header));
|
||||
try!(render_impl(w, i, AssocItemLink::Anchor, render_header));
|
||||
}
|
||||
}
|
||||
if let MethodRender::DerefFor { .. } = what {
|
||||
if let AssocItemRender::DerefFor { .. } = what {
|
||||
return Ok(())
|
||||
}
|
||||
if !traits.is_empty() {
|
||||
|
@ -2243,7 +2258,7 @@ fn render_methods(w: &mut fmt::Formatter,
|
|||
});
|
||||
for i in &manual {
|
||||
let did = i.trait_did().unwrap();
|
||||
try!(render_impl(w, i, MethodLink::GotoSource(did), true));
|
||||
try!(render_impl(w, i, AssocItemLink::GotoSource(did), true));
|
||||
}
|
||||
if !derived.is_empty() {
|
||||
try!(write!(w, "<h3 id='derived_implementations'>\
|
||||
|
@ -2251,7 +2266,7 @@ fn render_methods(w: &mut fmt::Formatter,
|
|||
</h3>"));
|
||||
for i in &derived {
|
||||
let did = i.trait_did().unwrap();
|
||||
try!(render_impl(w, i, MethodLink::GotoSource(did), true));
|
||||
try!(render_impl(w, i, AssocItemLink::GotoSource(did), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2266,14 +2281,14 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
|
|||
_ => None,
|
||||
}
|
||||
}).next().unwrap();
|
||||
let what = MethodRender::DerefFor { trait_: deref_type, type_: target };
|
||||
let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target };
|
||||
match *target {
|
||||
clean::ResolvedPath { did, .. } => render_methods(w, did, what),
|
||||
clean::ResolvedPath { did, .. } => render_assoc_items(w, did, what),
|
||||
_ => {
|
||||
if let Some(prim) = target.primitive_type() {
|
||||
if let Some(c) = cache().primitive_locations.get(&prim) {
|
||||
let did = ast::DefId { krate: *c, node: prim.to_node_id() };
|
||||
try!(render_methods(w, did, what));
|
||||
try!(render_assoc_items(w, did, what));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
@ -2281,7 +2296,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result {
|
|||
}
|
||||
}
|
||||
|
||||
fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
||||
fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
|
||||
render_header: bool) -> fmt::Result {
|
||||
if render_header {
|
||||
try!(write!(w, "<h3 class='impl'><code>impl{} ",
|
||||
|
@ -2300,13 +2315,13 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
|||
}
|
||||
|
||||
fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item,
|
||||
link: MethodLink) -> fmt::Result {
|
||||
link: AssocItemLink) -> fmt::Result {
|
||||
match item.inner {
|
||||
clean::MethodItem(..) | clean::TyMethodItem(..) => {
|
||||
try!(write!(w, "<h4 id='method.{}' class='{}'><code>",
|
||||
*item.name.as_ref().unwrap(),
|
||||
shortty(item)));
|
||||
try!(render_method(w, item, link));
|
||||
try!(render_assoc_item(w, item, link));
|
||||
try!(write!(w, "</code></h4>\n"));
|
||||
}
|
||||
clean::TypedefItem(ref tydef) => {
|
||||
|
@ -2317,6 +2332,14 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
|||
try!(write!(w, "type {} = {}", name, tydef.type_));
|
||||
try!(write!(w, "</code></h4>\n"));
|
||||
}
|
||||
clean::AssociatedConstItem(ref ty, ref default) => {
|
||||
let name = item.name.as_ref().unwrap();
|
||||
try!(write!(w, "<h4 id='assoc_const.{}' class='{}'><code>",
|
||||
*name,
|
||||
shortty(item)));
|
||||
try!(assoc_const(w, item, ty, default));
|
||||
try!(write!(w, "</code></h4>\n"));
|
||||
}
|
||||
clean::AssociatedTypeItem(ref bounds, ref default) => {
|
||||
let name = item.name.as_ref().unwrap();
|
||||
try!(write!(w, "<h4 id='assoc_type.{}' class='{}'><code>",
|
||||
|
@ -2327,7 +2350,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
|||
}
|
||||
_ => panic!("can't make docs for trait item with name {:?}", item.name)
|
||||
}
|
||||
if let MethodLink::Anchor = link {
|
||||
if let AssocItemLink::Anchor = link {
|
||||
document(w, item)
|
||||
} else {
|
||||
Ok(())
|
||||
|
@ -2339,10 +2362,10 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
|||
try!(doctraititem(w, trait_item, link));
|
||||
}
|
||||
|
||||
fn render_default_methods(w: &mut fmt::Formatter,
|
||||
did: ast::DefId,
|
||||
t: &clean::Trait,
|
||||
i: &clean::Impl) -> fmt::Result {
|
||||
fn render_default_items(w: &mut fmt::Formatter,
|
||||
did: ast::DefId,
|
||||
t: &clean::Trait,
|
||||
i: &clean::Impl) -> fmt::Result {
|
||||
for trait_item in &t.items {
|
||||
let n = trait_item.name.clone();
|
||||
match i.items.iter().find(|m| { m.name == n }) {
|
||||
|
@ -2350,7 +2373,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
|||
None => {}
|
||||
}
|
||||
|
||||
try!(doctraititem(w, trait_item, MethodLink::GotoSource(did)));
|
||||
try!(doctraititem(w, trait_item, AssocItemLink::GotoSource(did)));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -2361,7 +2384,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink,
|
|||
// for them work.
|
||||
if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ {
|
||||
if let Some(t) = cache().traits.get(&did) {
|
||||
try!(render_default_methods(w, did, t, &i.impl_));
|
||||
try!(render_default_items(w, did, t, &i.impl_));
|
||||
}
|
||||
}
|
||||
try!(write!(w, "</div>"));
|
||||
|
@ -2458,7 +2481,7 @@ fn item_primitive(w: &mut fmt::Formatter,
|
|||
it: &clean::Item,
|
||||
_p: &clean::PrimitiveType) -> fmt::Result {
|
||||
try!(document(w, it));
|
||||
render_methods(w, it.def_id, MethodRender::All)
|
||||
render_assoc_items(w, it.def_id, AssocItemRender::All)
|
||||
}
|
||||
|
||||
fn get_basic_keywords() -> &'static str {
|
||||
|
|
|
@ -184,7 +184,8 @@ impl<'a> fold::DocFolder for Stripper<'a> {
|
|||
// Primitives are never stripped
|
||||
clean::PrimitiveItem(..) => {}
|
||||
|
||||
// Associated types are never stripped
|
||||
// Associated consts and types are never stripped
|
||||
clean::AssociatedConstItem(..) |
|
||||
clean::AssociatedTypeItem(..) => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -593,6 +593,12 @@ pub enum Pat_ {
|
|||
/// "None" means a * pattern where we don't bind the fields to names.
|
||||
PatEnum(Path, Option<Vec<P<Pat>>>),
|
||||
|
||||
/// An associated const named using the qualified path `<T>::CONST` or
|
||||
/// `<T as Trait>::CONST`. Associated consts from inherent impls can be
|
||||
/// refered to as simply `T::CONST`, in which case they will end up as
|
||||
/// PatEnum, and the resolver will have to sort that out.
|
||||
PatQPath(QSelf, Path),
|
||||
|
||||
/// Destructuring of a struct, e.g. `Foo {x, y, ..}`
|
||||
/// The `bool` is `true` in the presence of a `..`
|
||||
PatStruct(Path, Vec<Spanned<FieldPat>>, bool),
|
||||
|
@ -1230,6 +1236,7 @@ pub struct TraitItem {
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum TraitItem_ {
|
||||
ConstTraitItem(P<Ty>, Option<P<Expr>>),
|
||||
MethodTraitItem(MethodSig, Option<P<Block>>),
|
||||
TypeTraitItem(TyParamBounds, Option<P<Ty>>),
|
||||
}
|
||||
|
@ -1246,6 +1253,7 @@ pub struct ImplItem {
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
|
||||
pub enum ImplItem_ {
|
||||
ConstImplItem(P<Ty>, P<Expr>),
|
||||
MethodImplItem(MethodSig, P<Block>),
|
||||
TypeImplItem(P<Ty>),
|
||||
MacImplItem(Mac),
|
||||
|
|
|
@ -222,8 +222,7 @@ impl<'a> FnLikeNode<'a> {
|
|||
ast::MethodImplItem(ref sig, ref body) => {
|
||||
method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span)
|
||||
}
|
||||
ast::TypeImplItem(_) |
|
||||
ast::MacImplItem(_) => {
|
||||
_ => {
|
||||
panic!("impl method FnLikeNode that is not fn-like")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -940,6 +940,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
|
|||
}
|
||||
Some(NodeImplItem(ii)) => {
|
||||
match ii.node {
|
||||
ConstImplItem(..) => {
|
||||
format!("assoc const {} in {}{}",
|
||||
token::get_ident(ii.ident),
|
||||
map.path_to_string(id),
|
||||
id_str)
|
||||
}
|
||||
MethodImplItem(..) => {
|
||||
format!("method {} in {}{}",
|
||||
token::get_ident(ii.ident),
|
||||
|
@ -959,9 +965,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String {
|
|||
}
|
||||
Some(NodeTraitItem(ti)) => {
|
||||
let kind = match ti.node {
|
||||
ConstTraitItem(..) => "assoc constant",
|
||||
MethodTraitItem(..) => "trait method",
|
||||
TypeTraitItem(..) => "assoc type",
|
||||
// ConstTraitItem(..) => "assoc constant"
|
||||
};
|
||||
|
||||
format!("{} {} in {}{}",
|
||||
|
|
|
@ -579,7 +579,7 @@ pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool {
|
|||
}
|
||||
PatMac(_) => panic!("attempted to analyze unexpanded pattern"),
|
||||
PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) |
|
||||
PatEnum(_, _) => {
|
||||
PatEnum(_, _) | PatQPath(_, _) => {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -155,6 +155,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
|
|||
|
||||
// Allows use of unary negate on unsigned integers, e.g. -e for e: u8
|
||||
("negate_unsigned", "1.0.0", Active),
|
||||
|
||||
// Allows the definition of associated constants in `trait` or `impl`
|
||||
// blocks.
|
||||
("associated_consts", "1.0.0", Active),
|
||||
];
|
||||
// (changing above list without updating src/doc/reference.md makes @cmr sad)
|
||||
|
||||
|
@ -659,6 +663,30 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
|
|||
}
|
||||
visit::walk_fn(self, fn_kind, fn_decl, block, span);
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
|
||||
match ti.node {
|
||||
ast::ConstTraitItem(..) => {
|
||||
self.gate_feature("associated_consts",
|
||||
ti.span,
|
||||
"associated constants are experimental")
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_trait_item(self, ti);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
|
||||
match ii.node {
|
||||
ast::ConstImplItem(..) => {
|
||||
self.gate_feature("associated_consts",
|
||||
ii.span,
|
||||
"associated constants are experimental")
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
visit::walk_impl_item(self, ii);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler,
|
||||
|
|
|
@ -980,6 +980,10 @@ pub fn noop_fold_trait_item<T: Folder>(i: P<TraitItem>, folder: &mut T)
|
|||
ident: folder.fold_ident(ident),
|
||||
attrs: fold_attrs(attrs, folder),
|
||||
node: match node {
|
||||
ConstTraitItem(ty, default) => {
|
||||
ConstTraitItem(folder.fold_ty(ty),
|
||||
default.map(|x| folder.fold_expr(x)))
|
||||
}
|
||||
MethodTraitItem(sig, body) => {
|
||||
MethodTraitItem(noop_fold_method_sig(sig, folder),
|
||||
body.map(|x| folder.fold_block(x)))
|
||||
|
@ -1001,6 +1005,9 @@ pub fn noop_fold_impl_item<T: Folder>(i: P<ImplItem>, folder: &mut T)
|
|||
attrs: fold_attrs(attrs, folder),
|
||||
vis: vis,
|
||||
node: match node {
|
||||
ConstImplItem(ty, expr) => {
|
||||
ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr))
|
||||
}
|
||||
MethodImplItem(sig, body) => {
|
||||
MethodImplItem(noop_fold_method_sig(sig, folder),
|
||||
folder.fold_block(body))
|
||||
|
@ -1134,6 +1141,10 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
|
|||
PatEnum(folder.fold_path(pth),
|
||||
pats.map(|pats| pats.move_map(|x| folder.fold_pat(x))))
|
||||
}
|
||||
PatQPath(qself, pth) => {
|
||||
let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself};
|
||||
PatQPath(qself, folder.fold_path(pth))
|
||||
}
|
||||
PatStruct(pth, fields, etc) => {
|
||||
let pth = folder.fold_path(pth);
|
||||
let fs = fields.move_map(|f| {
|
||||
|
|
|
@ -17,8 +17,8 @@ use ast::{Public, Unsafety};
|
|||
use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue};
|
||||
use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block};
|
||||
use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause};
|
||||
use ast::{Crate, CrateConfig, Decl, DeclItem};
|
||||
use ast::{DeclLocal, DefaultBlock, DefaultReturn};
|
||||
use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig};
|
||||
use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn};
|
||||
use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf};
|
||||
use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain};
|
||||
use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox};
|
||||
|
@ -40,8 +40,9 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces};
|
|||
use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource};
|
||||
use ast::{MutTy, BiMul, Mutability};
|
||||
use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot};
|
||||
use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion};
|
||||
use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle};
|
||||
use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange};
|
||||
use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti};
|
||||
use ast::PatWildSingle;
|
||||
use ast::{PolyTraitRef, QSelf};
|
||||
use ast::{Return, BiShl, BiShr, Stmt, StmtDecl};
|
||||
use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField};
|
||||
|
@ -109,6 +110,15 @@ pub enum PathParsingMode {
|
|||
LifetimeAndTypesWithColons,
|
||||
}
|
||||
|
||||
/// How to parse a qualified path, whether to allow trailing parameters.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum QPathParsingMode {
|
||||
/// No trailing parameters, e.g. `<T as Trait>::Item`
|
||||
NoParameters,
|
||||
/// Optional parameters, e.g. `<T as Trait>::item::<'a, U>`
|
||||
MaybeParameters,
|
||||
}
|
||||
|
||||
/// How to parse a bound, whether to allow bound modifiers such as `?`.
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum BoundParsingMode {
|
||||
|
@ -1161,6 +1171,20 @@ impl<'a> Parser<'a> {
|
|||
let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param());
|
||||
try!(p.expect(&token::Semi));
|
||||
(ident, TypeTraitItem(bounds, default))
|
||||
} else if try!(p.eat_keyword(keywords::Const)) {
|
||||
let ident = try!(p.parse_ident());
|
||||
try!(p.expect(&token::Colon));
|
||||
let ty = try!(p.parse_ty_sum());
|
||||
let default = if p.check(&token::Eq) {
|
||||
try!(p.bump());
|
||||
let expr = try!(p.parse_expr_nopanic());
|
||||
try!(p.commit_expr_expecting(&expr, token::Semi));
|
||||
Some(expr)
|
||||
} else {
|
||||
try!(p.expect(&token::Semi));
|
||||
None
|
||||
};
|
||||
(ident, ConstTraitItem(ty, default))
|
||||
} else {
|
||||
let style = try!(p.parse_unsafety());
|
||||
let abi = if try!(p.eat_keyword(keywords::Extern)) {
|
||||
|
@ -1334,36 +1358,9 @@ impl<'a> Parser<'a> {
|
|||
try!(self.expect(&token::CloseDelim(token::Paren)));
|
||||
TyTypeof(e)
|
||||
} else if try!(self.eat_lt()) {
|
||||
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item`
|
||||
let self_type = try!(self.parse_ty_sum());
|
||||
|
||||
let mut path = if try!(self.eat_keyword(keywords::As) ){
|
||||
try!(self.parse_path(LifetimeAndTypesWithoutColons))
|
||||
} else {
|
||||
ast::Path {
|
||||
span: self.span,
|
||||
global: false,
|
||||
segments: vec![]
|
||||
}
|
||||
};
|
||||
|
||||
let qself = QSelf {
|
||||
ty: self_type,
|
||||
position: path.segments.len()
|
||||
};
|
||||
|
||||
try!(self.expect(&token::Gt));
|
||||
try!(self.expect(&token::ModSep));
|
||||
|
||||
path.segments.push(ast::PathSegment {
|
||||
identifier: try!(self.parse_ident()),
|
||||
parameters: ast::PathParameters::none()
|
||||
});
|
||||
|
||||
if path.segments.len() == 1 {
|
||||
path.span.lo = self.last_span.lo;
|
||||
}
|
||||
path.span.hi = self.last_span.hi;
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||
|
||||
TyPath(Some(qself), path)
|
||||
} else if self.check(&token::ModSep) ||
|
||||
|
@ -1580,6 +1577,61 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
// QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]`
|
||||
// Assumes that the leading `<` has been parsed already.
|
||||
pub fn parse_qualified_path(&mut self, mode: QPathParsingMode)
|
||||
-> PResult<(QSelf, ast::Path)> {
|
||||
let self_type = try!(self.parse_ty_sum());
|
||||
let mut path = if try!(self.eat_keyword(keywords::As)) {
|
||||
try!(self.parse_path(LifetimeAndTypesWithoutColons))
|
||||
} else {
|
||||
ast::Path {
|
||||
span: self.span,
|
||||
global: false,
|
||||
segments: vec![]
|
||||
}
|
||||
};
|
||||
|
||||
let qself = QSelf {
|
||||
ty: self_type,
|
||||
position: path.segments.len()
|
||||
};
|
||||
|
||||
try!(self.expect(&token::Gt));
|
||||
try!(self.expect(&token::ModSep));
|
||||
|
||||
let item_name = try!(self.parse_ident());
|
||||
let parameters = match mode {
|
||||
QPathParsingMode::NoParameters => ast::PathParameters::none(),
|
||||
QPathParsingMode::MaybeParameters => {
|
||||
if try!(self.eat(&token::ModSep)) {
|
||||
try!(self.expect_lt());
|
||||
// Consumed `item::<`, go look for types
|
||||
let (lifetimes, types, bindings) =
|
||||
try!(self.parse_generic_values_after_lt());
|
||||
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
|
||||
lifetimes: lifetimes,
|
||||
types: OwnedSlice::from_vec(types),
|
||||
bindings: OwnedSlice::from_vec(bindings),
|
||||
})
|
||||
} else {
|
||||
ast::PathParameters::none()
|
||||
}
|
||||
}
|
||||
};
|
||||
path.segments.push(ast::PathSegment {
|
||||
identifier: item_name,
|
||||
parameters: parameters
|
||||
});
|
||||
|
||||
if path.segments.len() == 1 {
|
||||
path.span.lo = self.last_span.lo;
|
||||
}
|
||||
path.span.hi = self.last_span.hi;
|
||||
|
||||
Ok((qself, path))
|
||||
}
|
||||
|
||||
/// Parses a path and optional type parameter bounds, depending on the
|
||||
/// mode. The `mode` parameter determines whether lifetimes, types, and/or
|
||||
/// bounds are permitted and whether `::` must precede type parameter
|
||||
|
@ -2043,49 +2095,10 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
_ => {
|
||||
if try!(self.eat_lt()){
|
||||
// QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>`
|
||||
let self_type = try!(self.parse_ty_sum());
|
||||
let mut path = if try!(self.eat_keyword(keywords::As) ){
|
||||
try!(self.parse_path(LifetimeAndTypesWithoutColons))
|
||||
} else {
|
||||
ast::Path {
|
||||
span: self.span,
|
||||
global: false,
|
||||
segments: vec![]
|
||||
}
|
||||
};
|
||||
let qself = QSelf {
|
||||
ty: self_type,
|
||||
position: path.segments.len()
|
||||
};
|
||||
try!(self.expect(&token::Gt));
|
||||
try!(self.expect(&token::ModSep));
|
||||
|
||||
let item_name = try!(self.parse_ident());
|
||||
let parameters = if try!(self.eat(&token::ModSep) ){
|
||||
try!(self.expect_lt());
|
||||
// Consumed `item::<`, go look for types
|
||||
let (lifetimes, types, bindings) =
|
||||
try!(self.parse_generic_values_after_lt());
|
||||
ast::AngleBracketedParameters(ast::AngleBracketedParameterData {
|
||||
lifetimes: lifetimes,
|
||||
types: OwnedSlice::from_vec(types),
|
||||
bindings: OwnedSlice::from_vec(bindings),
|
||||
})
|
||||
} else {
|
||||
ast::PathParameters::none()
|
||||
};
|
||||
path.segments.push(ast::PathSegment {
|
||||
identifier: item_name,
|
||||
parameters: parameters
|
||||
});
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters));
|
||||
|
||||
if path.segments.len() == 1 {
|
||||
path.span.lo = self.last_span.lo;
|
||||
}
|
||||
path.span.hi = self.last_span.hi;
|
||||
|
||||
let hi = self.span.hi;
|
||||
return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path)));
|
||||
}
|
||||
if try!(self.eat_keyword(keywords::Move) ){
|
||||
|
@ -3158,16 +3171,25 @@ impl<'a> Parser<'a> {
|
|||
fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> {
|
||||
if self.is_path_start() {
|
||||
let lo = self.span.lo;
|
||||
let path = try!(self.parse_path(LifetimeAndTypesWithColons));
|
||||
let (qself, path) = if try!(self.eat_lt()) {
|
||||
// Parse a qualified path
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||
(Some(qself), path)
|
||||
} else {
|
||||
// Parse an unqualified path
|
||||
(None, try!(self.parse_path(LifetimeAndTypesWithColons)))
|
||||
};
|
||||
let hi = self.last_span.hi;
|
||||
Ok(self.mk_expr(lo, hi, ExprPath(None, path)))
|
||||
Ok(self.mk_expr(lo, hi, ExprPath(qself, path)))
|
||||
} else {
|
||||
self.parse_literal_maybe_minus()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_path_start(&self) -> bool {
|
||||
(self.token == token::ModSep || self.token.is_ident() || self.token.is_path())
|
||||
(self.token == token::Lt || self.token == token::ModSep
|
||||
|| self.token.is_ident() || self.token.is_path())
|
||||
&& !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False)
|
||||
}
|
||||
|
||||
|
@ -3243,25 +3265,44 @@ impl<'a> Parser<'a> {
|
|||
pat = try!(self.parse_pat_ident(BindByValue(MutImmutable)));
|
||||
}
|
||||
} else {
|
||||
// Parse as a general path
|
||||
let path = try!(self.parse_path(LifetimeAndTypesWithColons));
|
||||
let (qself, path) = if try!(self.eat_lt()) {
|
||||
// Parse a qualified path
|
||||
let (qself, path) =
|
||||
try!(self.parse_qualified_path(QPathParsingMode::NoParameters));
|
||||
(Some(qself), path)
|
||||
} else {
|
||||
// Parse an unqualified path
|
||||
(None, try!(self.parse_path(LifetimeAndTypesWithColons)))
|
||||
};
|
||||
match self.token {
|
||||
token::DotDotDot => {
|
||||
// Parse range
|
||||
let hi = self.last_span.hi;
|
||||
let begin = self.mk_expr(lo, hi, ExprPath(None, path));
|
||||
let begin = self.mk_expr(lo, hi, ExprPath(qself, path));
|
||||
try!(self.bump());
|
||||
let end = try!(self.parse_pat_range_end());
|
||||
pat = PatRange(begin, end);
|
||||
}
|
||||
token::OpenDelim(token::Brace) => {
|
||||
// Parse struct pattern
|
||||
if qself.is_some() {
|
||||
let span = self.span;
|
||||
self.span_err(span,
|
||||
"unexpected `{` after qualified path");
|
||||
self.abort_if_errors();
|
||||
}
|
||||
// Parse struct pattern
|
||||
try!(self.bump());
|
||||
let (fields, etc) = try!(self.parse_pat_fields());
|
||||
try!(self.bump());
|
||||
pat = PatStruct(path, fields, etc);
|
||||
}
|
||||
token::OpenDelim(token::Paren) => {
|
||||
if qself.is_some() {
|
||||
let span = self.span;
|
||||
self.span_err(span,
|
||||
"unexpected `(` after qualified path");
|
||||
self.abort_if_errors();
|
||||
}
|
||||
// Parse tuple struct or enum pattern
|
||||
if self.look_ahead(1, |t| *t == token::DotDot) {
|
||||
// This is a "top constructor only" pat
|
||||
|
@ -3278,6 +3319,10 @@ impl<'a> Parser<'a> {
|
|||
pat = PatEnum(path, Some(args));
|
||||
}
|
||||
}
|
||||
_ if qself.is_some() => {
|
||||
// Parse qualified path
|
||||
pat = PatQPath(qself.unwrap(), path);
|
||||
}
|
||||
_ => {
|
||||
// Parse nullary enum
|
||||
pat = PatEnum(path, Some(vec![]));
|
||||
|
@ -4349,6 +4394,14 @@ impl<'a> Parser<'a> {
|
|||
let typ = try!(self.parse_ty_sum());
|
||||
try!(self.expect(&token::Semi));
|
||||
(name, TypeImplItem(typ))
|
||||
} else if try!(self.eat_keyword(keywords::Const)) {
|
||||
let name = try!(self.parse_ident());
|
||||
try!(self.expect(&token::Colon));
|
||||
let typ = try!(self.parse_ty_sum());
|
||||
try!(self.expect(&token::Eq));
|
||||
let expr = try!(self.parse_expr_nopanic());
|
||||
try!(self.commit_expr_expecting(&expr, token::Semi));
|
||||
(name, ConstImplItem(typ, expr))
|
||||
} else {
|
||||
let (name, inner_attrs, node) = try!(self.parse_impl_method(vis));
|
||||
attrs.extend(inner_attrs.into_iter());
|
||||
|
|
|
@ -761,6 +761,26 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn print_associated_const(&mut self,
|
||||
ident: ast::Ident,
|
||||
ty: &ast::Ty,
|
||||
default: Option<&ast::Expr>,
|
||||
vis: ast::Visibility)
|
||||
-> io::Result<()>
|
||||
{
|
||||
try!(word(&mut self.s, &visibility_qualified(vis, "")));
|
||||
try!(self.word_space("const"));
|
||||
try!(self.print_ident(ident));
|
||||
try!(self.word_space(":"));
|
||||
try!(self.print_type(ty));
|
||||
if let Some(expr) = default {
|
||||
try!(space(&mut self.s));
|
||||
try!(self.word_space("="));
|
||||
try!(self.print_expr(expr));
|
||||
}
|
||||
word(&mut self.s, ";")
|
||||
}
|
||||
|
||||
fn print_associated_type(&mut self,
|
||||
ident: ast::Ident,
|
||||
bounds: Option<&ast::TyParamBounds>,
|
||||
|
@ -1234,6 +1254,11 @@ impl<'a> State<'a> {
|
|||
try!(self.maybe_print_comment(ti.span.lo));
|
||||
try!(self.print_outer_attributes(&ti.attrs));
|
||||
match ti.node {
|
||||
ast::ConstTraitItem(ref ty, ref default) => {
|
||||
try!(self.print_associated_const(ti.ident, &ty,
|
||||
default.as_ref().map(|expr| &**expr),
|
||||
ast::Inherited));
|
||||
}
|
||||
ast::MethodTraitItem(ref sig, ref body) => {
|
||||
if body.is_some() {
|
||||
try!(self.head(""));
|
||||
|
@ -1260,6 +1285,9 @@ impl<'a> State<'a> {
|
|||
try!(self.maybe_print_comment(ii.span.lo));
|
||||
try!(self.print_outer_attributes(&ii.attrs));
|
||||
match ii.node {
|
||||
ast::ConstImplItem(ref ty, ref expr) => {
|
||||
try!(self.print_associated_const(ii.ident, &ty, Some(&expr), ii.vis));
|
||||
}
|
||||
ast::MethodImplItem(ref sig, ref body) => {
|
||||
try!(self.head(""));
|
||||
try!(self.print_method_sig(ii.ident, sig, ii.vis));
|
||||
|
@ -2152,6 +2180,9 @@ impl<'a> State<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
ast::PatQPath(ref qself, ref path) => {
|
||||
try!(self.print_qpath(path, qself, false));
|
||||
}
|
||||
ast::PatStruct(ref path, ref fields, etc) => {
|
||||
try!(self.print_path(path, true, 0));
|
||||
try!(self.nbsp());
|
||||
|
|
|
@ -464,6 +464,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
|
|||
}
|
||||
}
|
||||
}
|
||||
PatQPath(ref qself, ref path) => {
|
||||
visitor.visit_ty(&qself.ty);
|
||||
visitor.visit_path(path, pattern.id)
|
||||
}
|
||||
PatStruct(ref path, ref fields, _) => {
|
||||
visitor.visit_path(path, pattern.id);
|
||||
for field in fields {
|
||||
|
@ -619,6 +623,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai
|
|||
visitor.visit_attribute(attr);
|
||||
}
|
||||
match trait_item.node {
|
||||
ConstTraitItem(ref ty, ref default) => {
|
||||
visitor.visit_ty(ty);
|
||||
if let Some(ref expr) = *default {
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
}
|
||||
MethodTraitItem(ref sig, None) => {
|
||||
visitor.visit_explicit_self(&sig.explicit_self);
|
||||
visitor.visit_generics(&sig.generics);
|
||||
|
@ -641,6 +651,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt
|
|||
visitor.visit_attribute(attr);
|
||||
}
|
||||
match impl_item.node {
|
||||
ConstImplItem(ref ty, ref expr) => {
|
||||
visitor.visit_ty(ty);
|
||||
visitor.visit_expr(expr);
|
||||
}
|
||||
MethodImplItem(ref sig, ref body) => {
|
||||
visitor.visit_fn(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl,
|
||||
body, impl_item.span, impl_item.id);
|
||||
|
|
46
src/test/auxiliary/associated-const-cc-lib.rs
Normal file
46
src/test/auxiliary/associated-const-cc-lib.rs
Normal file
|
@ -0,0 +1,46 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
#![crate_type="lib"]
|
||||
|
||||
// These items are for testing that associated consts work cross-crate.
|
||||
pub trait Foo {
|
||||
const BAR: usize;
|
||||
}
|
||||
|
||||
pub struct FooNoDefault;
|
||||
|
||||
impl Foo for FooNoDefault {
|
||||
const BAR: usize = 0;
|
||||
}
|
||||
|
||||
// These test that defaults and default resolution work cross-crate.
|
||||
pub trait FooDefault {
|
||||
const BAR: usize = 1;
|
||||
}
|
||||
|
||||
pub struct FooOverwriteDefault;
|
||||
|
||||
impl FooDefault for FooOverwriteDefault {
|
||||
const BAR: usize = 2;
|
||||
}
|
||||
|
||||
pub struct FooUseDefault;
|
||||
|
||||
impl FooDefault for FooUseDefault {}
|
||||
|
||||
// Test inherent impls.
|
||||
pub struct InherentBar;
|
||||
|
||||
impl InherentBar {
|
||||
pub const BAR: usize = 3;
|
||||
}
|
23
src/test/compile-fail/associated-const-dead-code.rs
Normal file
23
src/test/compile-fail/associated-const-dead-code.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
#![deny(dead_code)]
|
||||
|
||||
struct MyFoo;
|
||||
|
||||
impl MyFoo {
|
||||
const BAR: u32 = 1;
|
||||
//~^ ERROR associated const is never used: `BAR`
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let _: MyFoo = MyFoo;
|
||||
}
|
24
src/test/compile-fail/associated-const-impl-wrong-type.rs
Normal file
24
src/test/compile-fail/associated-const-impl-wrong-type.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const BAR: u32;
|
||||
}
|
||||
|
||||
struct SignedBar;
|
||||
|
||||
impl Foo for SignedBar {
|
||||
const BAR: i32 = -1;
|
||||
//~^ ERROR E0326
|
||||
}
|
||||
|
||||
fn main() {}
|
27
src/test/compile-fail/associated-const-private-impl.rs
Normal file
27
src/test/compile-fail/associated-const-private-impl.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
mod bar1 {
|
||||
pub use self::bar2::Foo;
|
||||
mod bar2 {
|
||||
pub struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, bar1::Foo::ID);
|
||||
//~^ERROR associated const `ID` is private
|
||||
}
|
22
src/test/compile-fail/associated-const-upper-case-lint.rs
Normal file
22
src/test/compile-fail/associated-const-upper-case-lint.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
#![deny(non_upper_case_globals)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const not_upper: bool = true;
|
||||
}
|
||||
//~^^ ERROR associated constant `not_upper` should have an upper case name such as `NOT_UPPER`
|
||||
|
||||
fn main() {}
|
23
src/test/compile-fail/gated-associated_consts.rs
Normal file
23
src/test/compile-fail/gated-associated_consts.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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 MyTrait {
|
||||
const C: bool;
|
||||
//~^ associated constants are experimental
|
||||
//~| add #![feature(associated_consts)] to the crate attributes to enable
|
||||
}
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const C: bool = true;
|
||||
//~^ associated constants are experimental
|
||||
//~| add #![feature(associated_consts)] to the crate attributes to enable
|
||||
}
|
45
src/test/compile-fail/impl-wrong-item-for-trait.rs
Normal file
45
src/test/compile-fail/impl-wrong-item-for-trait.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
fn bar(&self);
|
||||
const MY_CONST: u32;
|
||||
}
|
||||
|
||||
pub struct FooConstForMethod;
|
||||
|
||||
impl Foo for FooConstForMethod {
|
||||
//~^ ERROR E0046
|
||||
const bar: u64 = 1;
|
||||
//~^ ERROR E0323
|
||||
const MY_CONST: u32 = 1;
|
||||
}
|
||||
|
||||
pub struct FooMethodForConst;
|
||||
|
||||
impl Foo for FooMethodForConst {
|
||||
//~^ ERROR E0046
|
||||
fn bar(&self) {}
|
||||
fn MY_CONST() {}
|
||||
//~^ ERROR E0324
|
||||
}
|
||||
|
||||
pub struct FooTypeForMethod;
|
||||
|
||||
impl Foo for FooTypeForMethod {
|
||||
//~^ ERROR E0046
|
||||
type bar = u64;
|
||||
//~^ ERROR E0325
|
||||
const MY_CONST: u32 = 1;
|
||||
}
|
||||
|
||||
fn main () {}
|
33
src/test/compile-fail/method-path-in-pattern.rs
Normal file
33
src/test/compile-fail/method-path-in-pattern.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// 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.
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
fn bar(&self) {}
|
||||
}
|
||||
|
||||
trait MyTrait {
|
||||
fn trait_bar() {}
|
||||
}
|
||||
|
||||
impl MyTrait for Foo {}
|
||||
|
||||
fn main() {
|
||||
match 0u32 {
|
||||
Foo::bar => {} //~ ERROR E0327
|
||||
}
|
||||
match 0u32 {
|
||||
<Foo>::bar => {} //~ ERROR E0327
|
||||
}
|
||||
match 0u32 {
|
||||
<Foo>::trait_bar => {} //~ ERROR E0327
|
||||
}
|
||||
}
|
24
src/test/compile-fail/method-resolvable-path-in-pattern.rs
Normal file
24
src/test/compile-fail/method-resolvable-path-in-pattern.rs
Normal file
|
@ -0,0 +1,24 @@
|
|||
// 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.
|
||||
|
||||
struct Foo;
|
||||
|
||||
trait MyTrait {
|
||||
fn trait_bar() {}
|
||||
}
|
||||
|
||||
impl MyTrait for Foo {}
|
||||
|
||||
fn main() {
|
||||
match 0u32 {
|
||||
<Foo as MyTrait>::trait_bar => {}
|
||||
//~^ ERROR `trait_bar` is not an associated const
|
||||
}
|
||||
}
|
17
src/test/parse-fail/brace-after-qualified-path-in-match.rs
Normal file
17
src/test/parse-fail/brace-after-qualified-path-in-match.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.
|
||||
|
||||
fn foo() {
|
||||
match x {
|
||||
<T as Trait>::Type{key: value} => (),
|
||||
//~^ ERROR unexpected `{` after qualified path
|
||||
_ => (),
|
||||
}
|
||||
}
|
|
@ -16,6 +16,6 @@ impl Foo {
|
|||
fn foo() {}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
|
||||
} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -14,6 +14,6 @@ struct Foo;
|
|||
|
||||
impl Foo {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
} //~ ERROR expected one of `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
|
||||
} //~ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, or `unsafe`, found `}`
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -11,5 +11,5 @@
|
|||
// compile-flags: -Z parse-only
|
||||
|
||||
trait MyTrait<T>: Iterator {
|
||||
Item = T; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `Item`
|
||||
Item = T; //~ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `Item`
|
||||
}
|
||||
|
|
17
src/test/parse-fail/paren-after-qualified-path-in-match.rs
Normal file
17
src/test/parse-fail/paren-after-qualified-path-in-match.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.
|
||||
|
||||
fn foo() {
|
||||
match x {
|
||||
<T as Trait>::Type(2) => (),
|
||||
//~^ ERROR unexpected `(` after qualified path
|
||||
_ => (),
|
||||
}
|
||||
}
|
|
@ -14,5 +14,5 @@ struct S;
|
|||
|
||||
impl S {
|
||||
static fn f() {}
|
||||
//~^ ERROR expected one of `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
|
||||
}
|
||||
//~^^ ERROR expected one of `const`, `extern`, `fn`, `pub`, `type`, `unsafe`, or `}`, found `static`
|
||||
|
|
16
src/test/parse-fail/trait-pub-assoc-const.rs
Normal file
16
src/test/parse-fail/trait-pub-assoc-const.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
// 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 {
|
||||
pub const Foo: u32;
|
||||
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -9,7 +9,8 @@
|
|||
// except according to those terms.
|
||||
|
||||
trait Foo {
|
||||
pub type Foo; //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
|
||||
pub type Foo;
|
||||
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
// except according to those terms.
|
||||
|
||||
trait Foo {
|
||||
pub fn foo(); //~ ERROR expected one of `extern`, `fn`, `type`, or `unsafe`, found `pub`
|
||||
pub fn foo();
|
||||
//~^ ERROR expected one of `const`, `extern`, `fn`, `type`, or `unsafe`, found `pub`
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
32
src/test/run-pass/associated-const-cross-crate-defaults.rs
Normal file
32
src/test/run-pass/associated-const-cross-crate-defaults.rs
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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.
|
||||
|
||||
// aux-build:associated-const-cc-lib.rs
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
extern crate associated_const_cc_lib as foolib;
|
||||
|
||||
pub struct LocalFooUseDefault;
|
||||
|
||||
impl foolib::FooDefault for LocalFooUseDefault {}
|
||||
|
||||
pub struct LocalFooOverwriteDefault;
|
||||
|
||||
impl foolib::FooDefault for LocalFooOverwriteDefault {
|
||||
const BAR: usize = 4;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <foolib::FooUseDefault as foolib::FooDefault>::BAR);
|
||||
assert_eq!(2, <foolib::FooOverwriteDefault as foolib::FooDefault>::BAR);
|
||||
assert_eq!(1, <LocalFooUseDefault as foolib::FooDefault>::BAR);
|
||||
assert_eq!(4, <LocalFooOverwriteDefault as foolib::FooDefault>::BAR);
|
||||
}
|
27
src/test/run-pass/associated-const-cross-crate.rs
Normal file
27
src/test/run-pass/associated-const-cross-crate.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
// 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.
|
||||
|
||||
// aux-build:associated-const-cc-lib.rs
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
extern crate associated_const_cc_lib as foolib;
|
||||
|
||||
pub struct LocalFoo;
|
||||
|
||||
impl foolib::Foo for LocalFoo {
|
||||
const BAR: usize = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(0, <foolib::FooNoDefault as foolib::Foo>::BAR);
|
||||
assert_eq!(1, <LocalFoo as foolib::Foo>::BAR);
|
||||
assert_eq!(3, foolib::InherentBar::BAR);
|
||||
}
|
23
src/test/run-pass/associated-const-in-global-const.rs
Normal file
23
src/test/run-pass/associated-const-in-global-const.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const BAR: f32 = 1.5;
|
||||
}
|
||||
|
||||
const FOOBAR: f32 = <Foo>::BAR;
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1.5f32, FOOBAR);
|
||||
}
|
21
src/test/run-pass/associated-const-inherent-impl.rs
Normal file
21
src/test/run-pass/associated-const-inherent-impl.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, Foo::ID);
|
||||
}
|
25
src/test/run-pass/associated-const-marks-live-code.rs
Normal file
25
src/test/run-pass/associated-const-marks-live-code.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
#![deny(dead_code)]
|
||||
|
||||
const GLOBAL_BAR: u32 = 1;
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const BAR: u32 = GLOBAL_BAR;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let _: u32 = Foo::BAR;
|
||||
}
|
52
src/test/run-pass/associated-const-match-patterns.rs
Normal file
52
src/test/run-pass/associated-const-match-patterns.rs
Normal file
|
@ -0,0 +1,52 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
enum Bar {
|
||||
Var1,
|
||||
Var2,
|
||||
}
|
||||
|
||||
// Use inherent and trait impls to test UFCS syntax.
|
||||
impl Foo {
|
||||
const MYBAR: Bar = Bar::Var2;
|
||||
}
|
||||
|
||||
trait HasBar {
|
||||
const THEBAR: Bar;
|
||||
}
|
||||
|
||||
impl HasBar for Foo {
|
||||
const THEBAR: Bar = Bar::Var1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Inherent impl
|
||||
assert!(match Bar::Var2 {
|
||||
Foo::MYBAR => true,
|
||||
_ => false,
|
||||
});
|
||||
assert!(match Bar::Var2 {
|
||||
<Foo>::MYBAR => true,
|
||||
_ => false,
|
||||
});
|
||||
// Trait impl
|
||||
assert!(match Bar::Var1 {
|
||||
<Foo>::THEBAR => true,
|
||||
_ => false,
|
||||
});
|
||||
assert!(match Bar::Var1 {
|
||||
<Foo as HasBar>::THEBAR => true,
|
||||
_ => false,
|
||||
});
|
||||
}
|
23
src/test/run-pass/associated-const-overwrite-default.rs
Normal file
23
src/test/run-pass/associated-const-overwrite-default.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32 = 2;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <i32 as Foo>::ID);
|
||||
}
|
26
src/test/run-pass/associated-const-public-impl.rs
Normal file
26
src/test/run-pass/associated-const-public-impl.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
mod bar1 {
|
||||
pub use self::bar2::Foo;
|
||||
mod bar2 {
|
||||
pub struct Foo;
|
||||
|
||||
impl Foo {
|
||||
pub const ID: i32 = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, bar1::Foo::ID);
|
||||
}
|
35
src/test/run-pass/associated-const-resolution-order.rs
Normal file
35
src/test/run-pass/associated-const-resolution-order.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
struct MyType;
|
||||
|
||||
impl MyType {
|
||||
const IMPL_IS_INHERENT: bool = true;
|
||||
}
|
||||
|
||||
trait MyTrait {
|
||||
const IMPL_IS_INHERENT: bool;
|
||||
const IMPL_IS_ON_TRAIT: bool;
|
||||
}
|
||||
|
||||
impl MyTrait for MyType {
|
||||
const IMPL_IS_INHERENT: bool = false;
|
||||
const IMPL_IS_ON_TRAIT: bool = true;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Check that the inherent impl is used before the trait, but that the trait
|
||||
// can still be accessed.
|
||||
assert!(<MyType>::IMPL_IS_INHERENT);
|
||||
assert!(!<MyType as MyTrait>::IMPL_IS_INHERENT);
|
||||
assert!(<MyType>::IMPL_IS_ON_TRAIT);
|
||||
}
|
23
src/test/run-pass/associated-const-self-type.rs
Normal file
23
src/test/run-pass/associated-const-self-type.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait MyInt {
|
||||
const ONE: Self;
|
||||
}
|
||||
|
||||
impl MyInt for i32 {
|
||||
const ONE: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <i32>::ONE);
|
||||
}
|
23
src/test/run-pass/associated-const-ufcs-infer-trait.rs
Normal file
23
src/test/run-pass/associated-const-ufcs-infer-trait.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <i32>::ID);
|
||||
}
|
21
src/test/run-pass/associated-const-use-default.rs
Normal file
21
src/test/run-pass/associated-const-use-default.rs
Normal file
|
@ -0,0 +1,21 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
impl Foo for i32 {}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <i32 as Foo>::ID);
|
||||
}
|
35
src/test/run-pass/associated-const-use-impl-of-same-trait.rs
Normal file
35
src/test/run-pass/associated-const-use-impl-of-same-trait.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
// The main purpose of this test is to ensure that different impls of the same
|
||||
// trait can refer to each other without setting off the static recursion check
|
||||
// (as long as there's no actual recursion).
|
||||
|
||||
trait Foo {
|
||||
const BAR: u32;
|
||||
}
|
||||
|
||||
struct IsFoo1;
|
||||
|
||||
impl Foo for IsFoo1 {
|
||||
const BAR: u32 = 1;
|
||||
}
|
||||
|
||||
struct IsFoo2;
|
||||
|
||||
impl Foo for IsFoo2 {
|
||||
const BAR: u32 = <IsFoo1 as Foo>::BAR;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(<IsFoo1>::BAR, <IsFoo2 as Foo>::BAR);
|
||||
}
|
23
src/test/run-pass/associated-const.rs
Normal file
23
src/test/run-pass/associated-const.rs
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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.
|
||||
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <i32 as Foo>::ID);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue