Functional changes for associated constants. Cross-crate usage of associated constants is not yet working.
This commit is contained in:
parent
b5499775d6
commit
7129e8815e
43 changed files with 1387 additions and 294 deletions
|
@ -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));
|
||||
}
|
||||
|
@ -961,6 +993,34 @@ 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();
|
||||
|
||||
reader::tagged_docs(item, tag_item_trait_item, |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());
|
||||
|
|
|
@ -799,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>,
|
||||
|
@ -1192,7 +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(_) => {}
|
||||
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');
|
||||
|
@ -1230,7 +1270,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
|
|||
});
|
||||
|
||||
match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
|
||||
ty::ConstTraitItem(_) => {}
|
||||
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,
|
||||
|
@ -1275,7 +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(_) => {}
|
||||
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,7 +1371,23 @@ 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(_) => {
|
||||
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) => {
|
||||
|
@ -1368,7 +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(_, _) => {}
|
||||
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.
|
||||
|
@ -1388,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();
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -442,7 +442,8 @@ impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> {
|
|||
ast::PatIdent(..) | ast::PatEnum(..) => {
|
||||
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,7 +756,7 @@ 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)),
|
||||
|
@ -763,7 +764,7 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
|
|||
},
|
||||
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 +862,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 +877,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,
|
||||
|
@ -894,7 +895,7 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat],
|
|||
// 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,36 @@ 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(_, ref default) => {
|
||||
match maybe_ref_id {
|
||||
Some(ref_id) => {
|
||||
let trait_id = ty::trait_of_item(tcx, def_id)
|
||||
.unwrap();
|
||||
resolve_trait_associated_const(tcx, ti, trait_id,
|
||||
ref_id)
|
||||
}
|
||||
None => default.as_ref().map(|expr| &**expr),
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
Some(ast_map::NodeImplItem(ii)) => match ii.node {
|
||||
ast::ConstImplItem(_, ref expr) => {
|
||||
Some(&*expr)
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
|
@ -122,16 +146,42 @@ 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(_, ref ti)) => match ti.node {
|
||||
ast::ConstTraitItem(_, ref default) => {
|
||||
used_ref_id = true;
|
||||
match maybe_ref_id {
|
||||
Some(ref_id) => {
|
||||
let trait_id = ty::trait_of_item(tcx, def_id)
|
||||
.unwrap();
|
||||
resolve_trait_associated_const(tcx, ti, trait_id,
|
||||
ref_id).map(|e| e.id)
|
||||
}
|
||||
None => default.as_ref().map(|expr| expr.id),
|
||||
}
|
||||
}
|
||||
_ => 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 +805,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 +911,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) => {
|
||||
|
|
|
@ -78,7 +78,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};
|
||||
|
@ -5125,6 +5125,53 @@ 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 {
|
||||
let acs = csearch::get_associated_consts(cx, id);
|
||||
acs.iter().map(|ac| (*ac).clone()).collect()
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
|
|
|
@ -62,6 +62,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,9 +1068,30 @@ 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())) {
|
||||
(&ast::PatIdent(_, ref path1, _), Some(def::DefAssociatedConst(..))) |
|
||||
(&ast::PatIdent(_, ref path1, _), Some(def::DefConst(..))) => {
|
||||
NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
|
||||
path1.node, p.span);
|
||||
|
|
|
@ -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,7 +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(_, _) => {}
|
||||
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,
|
||||
|
@ -400,7 +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(_)) => ExternallyDenied,
|
||||
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);
|
||||
|
@ -794,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"),
|
||||
|
|
|
@ -1831,22 +1831,36 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
|
|||
//
|
||||
// FIXME #4951: Do we need a node ID here?
|
||||
|
||||
let type_parameters = match trait_item.node {
|
||||
ast::ConstTraitItem(..) => NoTypeParameters,
|
||||
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)
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -2096,7 +2110,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(_, _) => {}
|
||||
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
|
||||
|
|
|
@ -539,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);
|
||||
}
|
||||
|
||||
|
@ -1188,7 +1190,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(_, _,
|
||||
|
@ -1238,18 +1240,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(..) => {}
|
||||
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(..) => {}
|
||||
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);
|
||||
|
|
|
@ -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, _) => {
|
||||
|
|
|
@ -401,3 +401,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};
|
||||
|
@ -808,7 +808,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(_, _) => {}
|
||||
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);
|
||||
|
@ -824,15 +826,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::ConstTraitItem(_, _) => {}
|
||||
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.
|
||||
}
|
||||
|
@ -922,7 +924,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(_, _) => {}
|
||||
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,
|
||||
|
@ -946,13 +989,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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -982,11 +1023,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
match (associated_type, &typedef_ty) {
|
||||
(&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {}
|
||||
_ => {
|
||||
// Formerly `span_bug`, but it turns out that
|
||||
// this is not checked in resolve, so this is
|
||||
// the first place where we'll notice the
|
||||
// mismatch.
|
||||
span_err!(tcx.sess, impl_item.span, E0323,
|
||||
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()),
|
||||
|
@ -1014,10 +1051,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(_) => {}
|
||||
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| {
|
||||
|
@ -4254,7 +4308,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:
|
||||
//
|
||||
|
@ -4304,6 +4358,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());
|
||||
|
@ -4355,8 +4419,21 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
def::DefAssociatedConst(..) => {
|
||||
segment_spaces = repeat(None).take(segments.len()).collect();
|
||||
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
|
||||
|
|
|
@ -691,11 +691,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,
|
||||
|
@ -828,6 +854,23 @@ 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 {
|
||||
if let ast::TypeImplItem(ref ty) = impl_item.node {
|
||||
|
@ -906,6 +949,25 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
|
||||
debug!("convert: trait_bounds={:?}", trait_predicates);
|
||||
|
||||
// Convert all the associated types.
|
||||
for trait_item in trait_items {
|
||||
match trait_item.node {
|
||||
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 {
|
||||
|
|
|
@ -176,7 +176,10 @@ register_diagnostics! {
|
|||
E0320, // recursive overflow during dropck
|
||||
E0321, // extended coherence rules for defaulted traits violated
|
||||
E0322, // cannot implement Sized explicitly
|
||||
E0323, // implemented trait where method should have been provided
|
||||
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
|
||||
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,7 +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(_) => { return None }
|
||||
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
|
||||
|
@ -444,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);
|
||||
|
|
|
@ -1904,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>)
|
||||
|
@ -1959,7 +1970,9 @@ fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item,
|
|||
method(w, meth, m.unsafety, m.abi, &m.generics, &m.self_, &m.decl,
|
||||
link)
|
||||
}
|
||||
clean::AssociatedConstItem(_, _) => Ok(()),
|
||||
clean::AssociatedConstItem(ref ty, ref default) => {
|
||||
assoc_const(w, meth, ty, default)
|
||||
}
|
||||
clean::AssociatedTypeItem(ref bounds, ref default) => {
|
||||
assoc_type(w, meth, bounds, default)
|
||||
}
|
||||
|
@ -2319,7 +2332,14 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink,
|
|||
try!(write!(w, "type {} = {}", name, tydef.type_));
|
||||
try!(write!(w, "</code></h4>\n"));
|
||||
}
|
||||
clean::AssociatedConstItem(_, _) => {}
|
||||
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>",
|
||||
|
|
|
@ -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};
|
||||
|
@ -1158,6 +1158,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)) {
|
||||
|
@ -4313,6 +4327,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());
|
||||
|
|
|
@ -796,6 +796,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>,
|
||||
|
@ -1269,7 +1289,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(_, _) => Ok(()),
|
||||
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(""));
|
||||
|
@ -1296,7 +1320,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(_, _) => Ok(()),
|
||||
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));
|
||||
|
|
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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
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
|
||||
}
|
21
src/test/compile-fail/impl-type-where-trait-has-method.rs
Normal file
21
src/test/compile-fail/impl-type-where-trait-has-method.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.
|
||||
|
||||
trait Foo {
|
||||
fn bar(&self);
|
||||
}
|
||||
|
||||
impl Foo for u32 {
|
||||
//~^ ERROR not all trait items implemented, missing: `bar`
|
||||
type bar = u64;
|
||||
//~^ ERROR item `bar` is an associated type, which doesn't match its trait `Foo`
|
||||
}
|
||||
|
||||
fn main () {}
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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() {}
|
||||
|
|
19
src/test/run-pass/associated-const-inherent-impl.rs
Normal file
19
src/test/run-pass/associated-const-inherent-impl.rs
Normal file
|
@ -0,0 +1,19 @@
|
|||
// 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 {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, Foo::ID);
|
||||
}
|
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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
trait Foo: MarkerTrait {
|
||||
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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
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);
|
||||
}
|
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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
trait MyInt: MarkerTrait {
|
||||
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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
trait Foo: MarkerTrait {
|
||||
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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
trait Foo: MarkerTrait {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
impl Foo for i32 {}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <i32 as Foo>::ID);
|
||||
}
|
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.
|
||||
|
||||
use std::marker::MarkerTrait;
|
||||
|
||||
trait Foo: MarkerTrait {
|
||||
const ID: i32;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, <i32 as Foo>::ID);
|
||||
}
|
Loading…
Add table
Reference in a new issue