Skip to content

Commit 857ef6e

Browse files
committed
Auto merge of #23606 - quantheory:associated_const, r=nikomatsakis
Closes #17841. The majority of the work should be done, e.g. trait and inherent impls, different forms of UFCS syntax, defaults, and cross-crate usage. It's probably enough to replace the constants in `f32`, `i8`, and so on, or close to good enough. There is still some significant functionality missing from this commit: - ~~Associated consts can't be used in match patterns at all. This is simply because I haven't updated the relevant bits in the parser or `resolve`, but it's *probably* not hard to get working.~~ - Since you can't select an impl for trait-associated consts until partway through type-checking, there are some problems with code that assumes that you can check constants earlier. Associated consts that are not in inherent impls cause ICEs if you try to use them in array sizes or match ranges. For similar reasons, `check_static_recursion` doesn't check them properly, so the stack goes ka-blooey if you use an associated constant that's recursively defined. That's a bit trickier to solve; I'm not entirely sure what the best approach is yet. - Dealing with consts associated with type parameters will raise some new issues (e.g. if you have a `T: Int` type parameter and want to use `<T>::ZERO`). See rust-lang/rfcs#865. - ~~Unused associated consts don't seem to trigger the `dead_code` lint when they should. Probably easy to fix.~~ Also, this is the first time I've been spelunking in rustc to such a large extent, so I've probably done some silly things in a couple of places.
2 parents 32f9f42 + 4c0ac6d commit 857ef6e

File tree

93 files changed

+2801
-724
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+2801
-724
lines changed

src/doc/reference.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -2135,7 +2135,10 @@ The currently implemented features of the reference compiler are:
21352135
semantics are likely to change, so this macro usage must be opted
21362136
into.
21372137

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

21402143
* `box_patterns` - Allows `box` patterns, the exact semantics of which
21412144
is subject to change.

src/grammar/parser-lalr.y

+21-2
Original file line numberDiff line numberDiff line change
@@ -505,10 +505,20 @@ trait_items
505505
;
506506

507507
trait_item
508-
: trait_type
508+
: trait_const
509+
| trait_type
509510
| trait_method
510511
;
511512

513+
trait_const
514+
: maybe_outer_attrs CONST ident maybe_const_default ';' { $$ = mk_node("ConstTraitItem", 3, $1, $3, $4); }
515+
;
516+
517+
maybe_const_default
518+
: '=' expr { $$ = mk_node("ConstDefault", 1, $2); }
519+
| %empty { $$ = mk_none(); }
520+
;
521+
512522
trait_type
513523
: maybe_outer_attrs TYPE ty_param ';' { $$ = mk_node("TypeTraitItem", 2, $1, $3); }
514524
;
@@ -611,7 +621,16 @@ impl_items
611621
impl_item
612622
: impl_method
613623
| item_macro
614-
| trait_type
624+
| impl_const
625+
| impl_type
626+
;
627+
628+
impl_const
629+
: attrs_and_vis item_const { $$ = mk_node("ImplConst", 1, $1, $2); }
630+
;
631+
632+
impl_type
633+
: attrs_and_vis TYPE ident generic_params '=' ty_sum ';' { $$ = mk_node("ImplType", 4, $1, $3, $4, $6); }
615634
;
616635

617636
item_fn

src/librustc/metadata/csearch.rs

+7
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,13 @@ pub fn get_provided_trait_methods<'tcx>(tcx: &ty::ctxt<'tcx>,
175175
decoder::get_provided_trait_methods(cstore.intr.clone(), &*cdata, def.node, tcx)
176176
}
177177

178+
pub fn get_associated_consts<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
179+
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
180+
let cstore = &tcx.sess.cstore;
181+
let cdata = cstore.get_crate_data(def.krate);
182+
decoder::get_associated_consts(cstore.intr.clone(), &*cdata, def.node, tcx)
183+
}
184+
178185
pub fn get_type_name_if_impl(cstore: &cstore::CStore, def: ast::DefId)
179186
-> Option<ast::Name> {
180187
let cdata = cstore.get_crate_data(def.krate);

src/librustc/metadata/decoder.rs

+65-6
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,25 @@ fn item_to_def_like(item: rbml::Doc, did: ast::DefId, cnum: ast::CrateNum)
305305
-> DefLike {
306306
let fam = item_family(item);
307307
match fam {
308-
Constant => DlDef(def::DefConst(did)),
308+
Constant => {
309+
// Check whether we have an associated const item.
310+
if item_sort(item) == Some('C') {
311+
// Check whether the associated const is from a trait or impl.
312+
// See the comment for methods below.
313+
let provenance = if reader::maybe_get_doc(
314+
item, tag_item_trait_parent_sort).is_some() {
315+
def::FromTrait(item_reqd_and_translated_parent_item(cnum,
316+
item))
317+
} else {
318+
def::FromImpl(item_reqd_and_translated_parent_item(cnum,
319+
item))
320+
};
321+
DlDef(def::DefAssociatedConst(did, provenance))
322+
} else {
323+
// Regular const item.
324+
DlDef(def::DefConst(did))
325+
}
326+
}
309327
ImmStatic => DlDef(def::DefStatic(did, false)),
310328
MutStatic => DlDef(def::DefStatic(did, true)),
311329
Struct => DlDef(def::DefStruct(did)),
@@ -826,6 +844,7 @@ pub fn get_impl_items(cdata: Cmd, impl_id: ast::NodeId)
826844
tag_item_impl_item, |doc| {
827845
let def_id = item_def_id(doc, cdata);
828846
match item_sort(doc) {
847+
Some('C') => impl_items.push(ty::ConstTraitItemId(def_id)),
829848
Some('r') | Some('p') => {
830849
impl_items.push(ty::MethodTraitItemId(def_id))
831850
}
@@ -877,6 +896,18 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
877896
let vis = item_visibility(method_doc);
878897

879898
match item_sort(method_doc) {
899+
Some('C') => {
900+
let ty = doc_type(method_doc, tcx, cdata);
901+
let default = get_provided_source(method_doc, cdata);
902+
ty::ConstTraitItem(Rc::new(ty::AssociatedConst {
903+
name: name,
904+
ty: ty,
905+
vis: vis,
906+
def_id: def_id,
907+
container: container,
908+
default: default,
909+
}))
910+
}
880911
Some('r') | Some('p') => {
881912
let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
882913
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)
914945
reader::tagged_docs(item, tag_item_trait_item, |mth| {
915946
let def_id = item_def_id(mth, cdata);
916947
match item_sort(mth) {
948+
Some('C') => result.push(ty::ConstTraitItemId(def_id)),
917949
Some('r') | Some('p') => {
918950
result.push(ty::MethodTraitItemId(def_id));
919951
}
@@ -951,11 +983,8 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
951983
cdata,
952984
did.node,
953985
tcx);
954-
match trait_item {
955-
ty::MethodTraitItem(ref method) => {
956-
result.push((*method).clone())
957-
}
958-
ty::TypeTraitItem(_) => {}
986+
if let ty::MethodTraitItem(ref method) = trait_item {
987+
result.push((*method).clone())
959988
}
960989
}
961990
true
@@ -964,6 +993,36 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc<IdentInterner>,
964993
return result;
965994
}
966995

996+
pub fn get_associated_consts<'tcx>(intr: Rc<IdentInterner>,
997+
cdata: Cmd,
998+
id: ast::NodeId,
999+
tcx: &ty::ctxt<'tcx>)
1000+
-> Vec<Rc<ty::AssociatedConst<'tcx>>> {
1001+
let data = cdata.data();
1002+
let item = lookup_item(id, data);
1003+
let mut result = Vec::new();
1004+
1005+
for &tag in &[tag_item_trait_item, tag_item_impl_item] {
1006+
reader::tagged_docs(item, tag, |ac_id| {
1007+
let did = item_def_id(ac_id, cdata);
1008+
let ac_doc = lookup_item(did.node, data);
1009+
1010+
if item_sort(ac_doc) == Some('C') {
1011+
let trait_item = get_impl_or_trait_item(intr.clone(),
1012+
cdata,
1013+
did.node,
1014+
tcx);
1015+
if let ty::ConstTraitItem(ref ac) = trait_item {
1016+
result.push((*ac).clone())
1017+
}
1018+
}
1019+
true
1020+
});
1021+
}
1022+
1023+
return result;
1024+
}
1025+
9671026
pub fn get_type_name_if_impl(cdata: Cmd,
9681027
node_id: ast::NodeId) -> Option<ast::Name> {
9691028
let item = lookup_item(node_id, cdata.data());

src/librustc/metadata/encoder.rs

+82-11
Original file line numberDiff line numberDiff line change
@@ -378,14 +378,11 @@ fn encode_reexported_static_base_methods(ecx: &EncodeContext,
378378
let impl_item = ty::impl_or_trait_item(
379379
ecx.tcx,
380380
method_did.def_id());
381-
match impl_item {
382-
ty::MethodTraitItem(ref m) => {
383-
encode_reexported_static_method(rbml_w,
384-
exp,
385-
m.def_id,
386-
m.name);
387-
}
388-
ty::TypeTraitItem(_) => {}
381+
if let ty::MethodTraitItem(ref m) = impl_item {
382+
encode_reexported_static_method(rbml_w,
383+
exp,
384+
m.def_id,
385+
m.name);
389386
}
390387
}
391388
}
@@ -802,6 +799,43 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
802799
encode_provided_source(rbml_w, method_ty.provided_source);
803800
}
804801

802+
fn encode_info_for_associated_const(ecx: &EncodeContext,
803+
rbml_w: &mut Encoder,
804+
associated_const: &ty::AssociatedConst,
805+
impl_path: PathElems,
806+
parent_id: NodeId,
807+
impl_item_opt: Option<&ast::ImplItem>) {
808+
debug!("encode_info_for_associated_const({:?},{:?})",
809+
associated_const.def_id,
810+
token::get_name(associated_const.name));
811+
812+
rbml_w.start_tag(tag_items_data_item);
813+
814+
encode_def_id(rbml_w, associated_const.def_id);
815+
encode_name(rbml_w, associated_const.name);
816+
encode_visibility(rbml_w, associated_const.vis);
817+
encode_family(rbml_w, 'C');
818+
encode_provided_source(rbml_w, associated_const.default);
819+
820+
encode_parent_item(rbml_w, local_def(parent_id));
821+
encode_item_sort(rbml_w, 'C');
822+
823+
encode_bounds_and_type_for_item(rbml_w, ecx, associated_const.def_id.local_id());
824+
825+
let stab = stability::lookup(ecx.tcx, associated_const.def_id);
826+
encode_stability(rbml_w, stab);
827+
828+
let elem = ast_map::PathName(associated_const.name);
829+
encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
830+
831+
if let Some(ii) = impl_item_opt {
832+
encode_attributes(rbml_w, &ii.attrs);
833+
encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id), ii));
834+
}
835+
836+
rbml_w.end_tag();
837+
}
838+
805839
fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
806840
rbml_w: &mut Encoder,
807841
m: &ty::Method<'tcx>,
@@ -1195,6 +1229,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
11951229
for &item_def_id in items {
11961230
rbml_w.start_tag(tag_item_impl_item);
11971231
match item_def_id {
1232+
ty::ConstTraitItemId(item_def_id) => {
1233+
encode_def_id(rbml_w, item_def_id);
1234+
encode_item_sort(rbml_w, 'C');
1235+
}
11981236
ty::MethodTraitItemId(item_def_id) => {
11991237
encode_def_id(rbml_w, item_def_id);
12001238
encode_item_sort(rbml_w, 'r');
@@ -1232,6 +1270,14 @@ fn encode_info_for_item(ecx: &EncodeContext,
12321270
});
12331271

12341272
match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) {
1273+
ty::ConstTraitItem(ref associated_const) => {
1274+
encode_info_for_associated_const(ecx,
1275+
rbml_w,
1276+
&*associated_const,
1277+
path.clone(),
1278+
item.id,
1279+
ast_item)
1280+
}
12351281
ty::MethodTraitItem(ref method_type) => {
12361282
encode_info_for_method(ecx,
12371283
rbml_w,
@@ -1276,6 +1322,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
12761322
for &method_def_id in &*ty::trait_item_def_ids(tcx, def_id) {
12771323
rbml_w.start_tag(tag_item_trait_item);
12781324
match method_def_id {
1325+
ty::ConstTraitItemId(const_def_id) => {
1326+
encode_def_id(rbml_w, const_def_id);
1327+
encode_item_sort(rbml_w, 'C');
1328+
}
12791329
ty::MethodTraitItemId(method_def_id) => {
12801330
encode_def_id(rbml_w, method_def_id);
12811331
encode_item_sort(rbml_w, 'r');
@@ -1321,6 +1371,25 @@ fn encode_info_for_item(ecx: &EncodeContext,
13211371
ty::impl_or_trait_item(tcx, item_def_id.def_id());
13221372
let is_nonstatic_method;
13231373
match trait_item_type {
1374+
ty::ConstTraitItem(associated_const) => {
1375+
encode_name(rbml_w, associated_const.name);
1376+
encode_def_id(rbml_w, associated_const.def_id);
1377+
encode_visibility(rbml_w, associated_const.vis);
1378+
1379+
encode_provided_source(rbml_w, associated_const.default);
1380+
1381+
let elem = ast_map::PathName(associated_const.name);
1382+
encode_path(rbml_w,
1383+
path.clone().chain(Some(elem).into_iter()));
1384+
1385+
encode_item_sort(rbml_w, 'C');
1386+
encode_family(rbml_w, 'C');
1387+
1388+
encode_bounds_and_type_for_item(rbml_w, ecx,
1389+
associated_const.def_id.local_id());
1390+
1391+
is_nonstatic_method = false;
1392+
}
13241393
ty::MethodTraitItem(method_ty) => {
13251394
let method_def_id = item_def_id.def_id();
13261395

@@ -1365,6 +1434,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
13651434
let trait_item = &*ms[i];
13661435
encode_attributes(rbml_w, &trait_item.attrs);
13671436
match trait_item.node {
1437+
ast::ConstTraitItem(_, _) => {
1438+
encode_inlined_item(ecx, rbml_w,
1439+
IITraitItemRef(def_id, trait_item));
1440+
}
13681441
ast::MethodTraitItem(ref sig, ref body) => {
13691442
// If this is a static method, we've already
13701443
// encoded this.
@@ -1384,9 +1457,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
13841457
encode_method_argument_names(rbml_w, &sig.decl);
13851458
}
13861459

1387-
ast::TypeTraitItem(..) => {
1388-
encode_item_sort(rbml_w, 't');
1389-
}
1460+
ast::TypeTraitItem(..) => {}
13901461
}
13911462

13921463
rbml_w.end_tag();

src/librustc/middle/astencode.rs

+3
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,9 @@ impl tr for def::Def {
465465
def::DefForeignMod(did) => { def::DefForeignMod(did.tr(dcx)) }
466466
def::DefStatic(did, m) => { def::DefStatic(did.tr(dcx), m) }
467467
def::DefConst(did) => { def::DefConst(did.tr(dcx)) }
468+
def::DefAssociatedConst(did, p) => {
469+
def::DefAssociatedConst(did.tr(dcx), p.map(|did2| did2.tr(dcx)))
470+
}
468471
def::DefLocal(nid) => { def::DefLocal(dcx.tr_id(nid)) }
469472
def::DefVariant(e_did, v_did, is_s) => {
470473
def::DefVariant(e_did.tr(dcx), v_did.tr(dcx), is_s)

src/librustc/middle/cfg/construct.rs

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
105105
match pat.node {
106106
ast::PatIdent(_, _, None) |
107107
ast::PatEnum(_, None) |
108+
ast::PatQPath(..) |
108109
ast::PatLit(..) |
109110
ast::PatRange(..) |
110111
ast::PatWild(_) => {

src/librustc/middle/check_const.rs

+29-4
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,28 @@ impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> {
223223
}
224224
}
225225

226+
fn visit_trait_item(&mut self, t: &'v ast::TraitItem) {
227+
match t.node {
228+
ast::ConstTraitItem(_, ref default) => {
229+
if let Some(ref expr) = *default {
230+
self.global_expr(Mode::Const, &*expr);
231+
} else {
232+
visit::walk_trait_item(self, t);
233+
}
234+
}
235+
_ => self.with_mode(Mode::Var, |v| visit::walk_trait_item(v, t)),
236+
}
237+
}
238+
239+
fn visit_impl_item(&mut self, i: &'v ast::ImplItem) {
240+
match i.node {
241+
ast::ConstImplItem(_, ref expr) => {
242+
self.global_expr(Mode::Const, &*expr);
243+
}
244+
_ => self.with_mode(Mode::Var, |v| visit::walk_impl_item(v, i)),
245+
}
246+
}
247+
226248
fn visit_fn(&mut self,
227249
fk: visit::FnKind<'v>,
228250
fd: &'v ast::FnDecl,
@@ -468,13 +490,16 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
468490
Mode::Var => v.add_qualif(NOT_CONST)
469491
}
470492
}
471-
Some(def::DefConst(did)) => {
472-
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did) {
493+
Some(def::DefConst(did)) |
494+
Some(def::DefAssociatedConst(did, _)) => {
495+
if let Some(expr) = const_eval::lookup_const_by_id(v.tcx, did,
496+
Some(e.id)) {
473497
let inner = v.global_expr(Mode::Const, expr);
474498
v.add_qualif(inner);
475499
} else {
476-
v.tcx.sess.span_bug(e.span, "DefConst doesn't point \
477-
to an ItemConst");
500+
v.tcx.sess.span_bug(e.span,
501+
"DefConst or DefAssociatedConst \
502+
doesn't point to a constant");
478503
}
479504
}
480505
def => {

0 commit comments

Comments
 (0)