Functional changes for associated constants. Cross-crate usage of associated constants is not yet working.

This commit is contained in:
Sean Patrick Santos 2015-03-15 19:35:25 -06:00
parent b5499775d6
commit 7129e8815e
43 changed files with 1387 additions and 294 deletions

View file

@ -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

View file

@ -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);

View file

@ -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());

View file

@ -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();

View file

@ -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 => {

View file

@ -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) {

View file

@ -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,

View file

@ -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, &param_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) => {

View file

@ -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

View file

@ -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) {

View file

@ -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,

View file

@ -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);

View file

@ -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"),

View file

@ -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

View file

@ -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);

View file

@ -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, _) => {

View file

@ -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;
}
}
}

View file

@ -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()));
}
}
}

View file

@ -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))
}

View file

@ -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),

View file

@ -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

View file

@ -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 {

View file

@ -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

View file

@ -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);

View file

@ -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>",

View file

@ -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());

View file

@ -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));

View 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
}

View 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 () {}

View file

@ -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() {}

View file

@ -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() {}

View file

@ -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`
}

View file

@ -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`

View 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() {}

View file

@ -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() {}

View file

@ -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() {}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}