Skip to content

Commit

Permalink
Auto merge of #23606 - quantheory:associated_const, r=nikomatsakis
Browse files Browse the repository at this point in the history
Closes #17841.

The majority of the work should be done, e.g. trait and inherent impls, different forms of UFCS syntax, defaults, and cross-crate usage. It's probably enough to replace the constants in `f32`, `i8`, and so on, or close to good enough.

There is still some significant functionality missing from this commit:

 - ~~Associated consts can't be used in match patterns at all. This is simply because I haven't updated the relevant bits in the parser or `resolve`, but it's *probably* not hard to get working.~~
 - Since you can't select an impl for trait-associated consts until partway through type-checking, there are some problems with code that assumes that you can check constants earlier. Associated consts that are not in inherent impls cause ICEs if you try to use them in array sizes or match ranges. For similar reasons, `check_static_recursion` doesn't check them properly, so the stack goes ka-blooey if you use an associated constant that's recursively defined. That's a bit trickier to solve; I'm not entirely sure what the best approach is yet.
 - Dealing with consts associated with type parameters will raise some new issues (e.g. if you have a `T: Int` type parameter and want to use `<T>::ZERO`). See rust-lang/rfcs#865.
 - ~~Unused associated consts don't seem to trigger the `dead_code` lint when they should. Probably easy to fix.~~

Also, this is the first time I've been spelunking in rustc to such a large extent, so I've probably done some silly things in a couple of places.
  • Loading branch information
bors committed Apr 27, 2015
2 parents 32f9f42 + 4c0ac6d commit 857ef6e
Show file tree
Hide file tree
Showing 93 changed files with 2,801 additions and 724 deletions.
5 changes: 4 additions & 1 deletion src/doc/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2135,7 +2135,10 @@ The currently implemented features of the reference compiler are:
semantics are likely to change, so this macro usage must be opted
into.

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

* `box_patterns` - Allows `box` patterns, the exact semantics of which
is subject to change.
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

0 comments on commit 857ef6e

Please sign in to comment.