Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement associated constants #23606

Merged
merged 8 commits into from
Apr 27, 2015
5 changes: 4 additions & 1 deletion src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2340,7 +2340,10 @@ The currently implemented features of the reference compiler are:
semantics are likely to change, so this macro usage must be opted
into.

* `associated_types` - Allows type aliases in traits. Experimental.
* `associated_consts` - Allows constants to be defined in `impl` and `trait`
blocks, so that they can be associated with a type or
trait in a similar manner to methods and associated
types.

* `box_patterns` - Allows `box` patterns, the exact semantics of which
is subject to change.
Expand Down
23 changes: 21 additions & 2 deletions src/grammar/parser-lalr.y
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
;
Expand Down Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions src/librustc/metadata/csearch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
71 changes: 65 additions & 6 deletions src/librustc/metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
Expand Down Expand Up @@ -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))
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -951,11 +983,8 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
cdata,
did.node,
tcx);
match trait_item {
ty::MethodTraitItem(ref method) => {
result.push((*method).clone())
}
ty::TypeTraitItem(_) => {}
if let ty::MethodTraitItem(ref method) = trait_item {
result.push((*method).clone())
}
}
true
Expand All @@ -964,6 +993,36 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
return result;
}

pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
cdata: Cmd,
id: ast::NodeId,
tcx: &ty::ctxt<'tcx>)
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
let data = cdata.data();
let item = lookup_item(id, data);
let mut result = Vec::new();

for &tag in &[tag_item_trait_item, tag_item_impl_item] {
reader::tagged_docs(item, tag, |ac_id| {
let did = item_def_id(ac_id, cdata);
let ac_doc = lookup_item(did.node, data);

if item_sort(ac_doc) == Some('C') {
let trait_item = get_impl_or_trait_item(intr.clone(),
cdata,
did.node,
tcx);
if let ty::ConstTraitItem(ref ac) = trait_item {
result.push((*ac).clone())
}
}
true
});
}

return result;
}

pub fn get_type_name_if_impl(cdata: Cmd,
node_id: ast::NodeId) -> Option<ast::Name> {
let item = lookup_item(node_id, cdata.data());
Expand Down
93 changes: 82 additions & 11 deletions src/librustc/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,14 +378,11 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
let impl_item = ty::impl_or_trait_item(
ecx.tcx,
method_did.def_id());
match impl_item {
ty::MethodTraitItem(ref m) => {
encode_reexported_static_method(rbml_w,
exp,
m.def_id,
m.name);
}
ty::TypeTraitItem(_) => {}
if let ty::MethodTraitItem(ref m) = impl_item {
encode_reexported_static_method(rbml_w,
exp,
m.def_id,
m.name);
}
}
}
Expand Down Expand Up @@ -802,6 +799,43 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
encode_provided_source(rbml_w, method_ty.provided_source);
}

fn encode_info_for_associated_const(ecx: &EncodeContext,
rbml_w: &mut Encoder,
associated_const: &ty::AssociatedConst,
impl_path: PathElems,
parent_id: NodeId,
impl_item_opt: Option<&ast::ImplItem>) {
debug!("encode_info_for_associated_const({:?},{:?})",
associated_const.def_id,
token::get_name(associated_const.name));

rbml_w.start_tag(tag_items_data_item);

encode_def_id(rbml_w, associated_const.def_id);
encode_name(rbml_w, associated_const.name);
encode_visibility(rbml_w, associated_const.vis);
encode_family(rbml_w, 'C');
encode_provided_source(rbml_w, associated_const.default);

encode_parent_item(rbml_w, local_def(parent_id));
encode_item_sort(rbml_w, 'C');

encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());

let stab = stability::lookup(ecx.tcx, associated_const.def_id);
encode_stability(rbml_w, stab);

let elem = ast_map::PathName(associated_const.name);
encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));

if let Some(ii) = impl_item_opt {
encode_attributes(rbml_w, &ii.attrs);
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ii));
}

rbml_w.end_tag();
}

fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
rbml_w: &mut Encoder,
m: &ty::Method<'tcx>,
Expand Down Expand Up @@ -1195,6 +1229,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
for &item_def_id in items {
rbml_w.start_tag(tag_item_impl_item);
match item_def_id {
ty::ConstTraitItemId(item_def_id) => {
encode_def_id(rbml_w, item_def_id);
encode_item_sort(rbml_w, 'C');
}
ty::MethodTraitItemId(item_def_id) => {
encode_def_id(rbml_w, item_def_id);
encode_item_sort(rbml_w, 'r');
Expand Down Expand Up @@ -1232,6 +1270,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
});

match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
ty::ConstTraitItem(ref associated_const) => {
encode_info_for_associated_const(ecx,
rbml_w,
&*associated_const,
path.clone(),
item.id,
ast_item)
}
ty::MethodTraitItem(ref method_type) => {
encode_info_for_method(ecx,
rbml_w,
Expand Down Expand Up @@ -1276,6 +1322,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
rbml_w.start_tag(tag_item_trait_item);
match method_def_id {
ty::ConstTraitItemId(const_def_id) => {
encode_def_id(rbml_w, const_def_id);
encode_item_sort(rbml_w, 'C');
}
ty::MethodTraitItemId(method_def_id) => {
encode_def_id(rbml_w, method_def_id);
encode_item_sort(rbml_w, 'r');
Expand Down Expand Up @@ -1321,6 +1371,25 @@ fn encode_info_for_item(ecx: &EncodeContext,
ty::impl_or_trait_item(tcx, item_def_id.def_id());
let is_nonstatic_method;
match trait_item_type {
ty::ConstTraitItem(associated_const) => {
encode_name(rbml_w, associated_const.name);
encode_def_id(rbml_w, associated_const.def_id);
encode_visibility(rbml_w, associated_const.vis);

encode_provided_source(rbml_w, associated_const.default);

let elem = ast_map::PathName(associated_const.name);
encode_path(rbml_w,
path.clone().chain(Some(elem).into_iter()));

encode_item_sort(rbml_w, 'C');
encode_family(rbml_w, 'C');

encode_bounds_and_type_for_item(rbml_w, ecx,
associated_const.def_id.local_id());

is_nonstatic_method = false;
}
ty::MethodTraitItem(method_ty) => {
let method_def_id = item_def_id.def_id();

Expand Down Expand Up @@ -1365,6 +1434,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
let trait_item = &*ms[i];
encode_attributes(rbml_w, &trait_item.attrs);
match trait_item.node {
ast::ConstTraitItem(_, _) => {
encode_inlined_item(ecx, rbml_w,
IITraitItemRef(def_id, trait_item));
}
ast::MethodTraitItem(ref sig, ref body) => {
// If this is a static method, we've already
// encoded this.
Expand All @@ -1384,9 +1457,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_method_argument_names(rbml_w, &sig.decl);
}

ast::TypeTraitItem(..) => {
encode_item_sort(rbml_w, 't');
}
ast::TypeTraitItem(..) => {}
}

rbml_w.end_tag();
Expand Down
3 changes: 3 additions & 0 deletions src/librustc/middle/astencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,9 @@ impl tr for def::Def {
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
def::DefAssociatedConst(did, p) => {
def::DefAssociatedConst(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
}
def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
def::DefVariant(e_did, v_did, is_s) => {
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)
Expand Down
1 change: 1 addition & 0 deletions src/librustc/middle/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
match pat.node {
ast::PatIdent(_, _, None) |
ast::PatEnum(_, None) |
ast::PatQPath(..) |
ast::PatLit(..) |
ast::PatRange(..) |
ast::PatWild(_) => {
Expand Down
33 changes: 29 additions & 4 deletions src/librustc/middle/check_const.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 => {
Expand Down
Loading