From b5499775d6bee080b3f46539d59d238de2c1726f Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Sat, 14 Mar 2015 12:05:00 -0600 Subject: [PATCH 1/8] Structural changes for associated constants Introduces new variants and types in syntax::ast, middle::ty, and middle::def. --- src/librustc/metadata/decoder.rs | 7 +- src/librustc/metadata/encoder.rs | 20 ++-- src/librustc/middle/astencode.rs | 3 + src/librustc/middle/dead.rs | 13 +-- src/librustc/middle/def.rs | 4 +- src/librustc/middle/expr_use_visitor.rs | 3 +- src/librustc/middle/infer/error_reporting.rs | 8 +- src/librustc/middle/mem_categorization.rs | 4 +- src/librustc/middle/pat_util.rs | 2 +- src/librustc/middle/reachable.rs | 11 ++- src/librustc/middle/traits/object_safety.rs | 4 +- src/librustc/middle/traits/project.rs | 2 +- src/librustc/middle/traits/util.rs | 6 +- src/librustc/middle/ty.rs | 84 ++++++++++++++--- src/librustc/util/ppaux.rs | 33 ++++++- src/librustc_lint/builtin.rs | 6 +- src/librustc_privacy/lib.rs | 33 ++++--- src/librustc_resolve/build_reduced_graph.rs | 9 +- src/librustc_resolve/lib.rs | 10 +- src/librustc_trans/save/mod.rs | 29 +++--- src/librustc_trans/trans/base.rs | 36 +++---- src/librustc_trans/trans/callee.rs | 5 +- src/librustc_trans/trans/debuginfo.rs | 9 +- src/librustc_trans/trans/meth.rs | 24 +++-- src/librustc_trans/trans/monomorphize.rs | 8 +- src/librustc_typeck/check/mod.rs | 32 ++++--- src/librustc_typeck/coherence/mod.rs | 10 +- src/librustc_typeck/collect.rs | 98 +++++++++----------- src/librustc_typeck/diagnostics.rs | 1 + src/librustdoc/clean/inline.rs | 1 + src/librustdoc/clean/mod.rs | 27 ++++++ src/librustdoc/html/item_type.rs | 3 + src/librustdoc/html/render.rs | 79 ++++++++-------- src/librustdoc/passes.rs | 3 +- src/libsyntax/ast.rs | 2 + src/libsyntax/ast_map/blocks.rs | 3 +- src/libsyntax/ast_map/mod.rs | 8 +- src/libsyntax/fold.rs | 7 ++ src/libsyntax/print/pprust.rs | 2 + src/libsyntax/visit.rs | 10 ++ 40 files changed, 416 insertions(+), 243 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index cbd542567709c..8e3f77f949b6b 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -951,11 +951,8 @@ pub fn get_provided_trait_methods<'tcx>(intr: Rc, 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 diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 29270bd6c624b..5f31e24a0637f 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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); } } } @@ -1195,6 +1192,7 @@ 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::MethodTraitItemId(item_def_id) => { encode_def_id(rbml_w, item_def_id); encode_item_sort(rbml_w, 'r'); @@ -1232,6 +1230,7 @@ fn encode_info_for_item(ecx: &EncodeContext, }); match ty::impl_or_trait_item(tcx, trait_item_def_id.def_id()) { + ty::ConstTraitItem(_) => {} ty::MethodTraitItem(ref method_type) => { encode_info_for_method(ecx, rbml_w, @@ -1276,6 +1275,7 @@ 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::MethodTraitItemId(method_def_id) => { encode_def_id(rbml_w, method_def_id); encode_item_sort(rbml_w, 'r'); @@ -1321,6 +1321,9 @@ 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(_) => { + is_nonstatic_method = false; + } ty::MethodTraitItem(method_ty) => { let method_def_id = item_def_id.def_id(); @@ -1365,6 +1368,7 @@ 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::MethodTraitItem(ref sig, ref body) => { // If this is a static method, we've already // encoded this. diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index ee8373279d976..61b610ab6555e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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) diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 2befbf9924577..fc40febdbf82e 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -72,7 +72,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { fn lookup_and_handle_definition(&mut self, id: &ast::NodeId) { self.tcx.def_map.borrow().get(id).map(|def| { match def.full_def() { - def::DefConst(_) => { + def::DefConst(_) | def::DefAssociatedConst(..) => { self.check_def_id(def.def_id()) } _ if self.ignore_non_const_paths => (), @@ -114,14 +114,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { let trait_item = ty::trait_item(self.tcx, trait_ref.def_id, index); - match trait_item { - ty::MethodTraitItem(method) => { - self.check_def_id(method.def_id); - } - ty::TypeTraitItem(typedef) => { - self.check_def_id(typedef.def_id); - } - } + self.check_def_id(trait_item.def_id()); } } } @@ -365,6 +358,7 @@ impl<'v> Visitor<'v> for LifeSeeder { ast::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => { for impl_item in impl_items { match impl_item.node { + ast::ConstImplItem(..) => {} ast::MethodImplItem(..) => { if opt_trait.is_some() || has_allow_dead_code_or_lang_attr(&impl_item.attrs) { @@ -584,6 +578,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { // Overwrite so that we don't warn the trait method itself. fn visit_trait_item(&mut self, trait_method: &ast::TraitItem) { match trait_method.node { + ast::ConstTraitItem(_, _) => {} ast::MethodTraitItem(_, Some(ref body)) => { visit::walk_block(self, body) } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index f0b359088549b..bce246fa4af86 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -28,6 +28,7 @@ pub enum Def { DefForeignMod(ast::DefId), DefStatic(ast::DefId, bool /* is_mutbl */), DefConst(ast::DefId), + DefAssociatedConst(ast::DefId /* const */, MethodProvenance), DefLocal(ast::NodeId), DefVariant(ast::DefId /* enum */, ast::DefId /* variant */, bool /* is_structure */), DefTy(ast::DefId, bool /* is_enum */), @@ -140,7 +141,8 @@ impl Def { DefFn(id, _) | DefMod(id) | DefForeignMod(id) | DefStatic(id, _) | DefVariant(_, id, _) | DefTy(id, _) | DefAssociatedTy(_, id) | DefTyParam(_, _, id, _) | DefUse(id) | DefStruct(id) | DefTrait(id) | - DefMethod(id, _) | DefConst(id) | DefSelfTy(Some(id), None)=> { + DefMethod(id, _) | DefConst(id) | DefAssociatedConst(id, _) | + DefSelfTy(Some(id), None)=> { id } DefLocal(id) | diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 5235bbdf9cf00..87379bd48f0c4 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -234,7 +234,7 @@ impl OverloadedCallType { ty::MethodTraitItem(ref method_descriptor) => { (*method_descriptor).clone() } - ty::TypeTraitItem(_) => { + _ => { tcx.sess.bug("overloaded call method wasn't in method map") } }; @@ -1183,6 +1183,7 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { } Some(def::DefConst(..)) | + Some(def::DefAssociatedConst(..)) | Some(def::DefLocal(..)) => { // This is a leaf (i.e. identifier binding // or constant value to match); thus no diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs index 3dbbcce27b6ea..22e3376e09ea8 100644 --- a/src/librustc/middle/infer/error_reporting.rs +++ b/src/librustc/middle/infer/error_reporting.rs @@ -843,8 +843,8 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> { Some(&sig.explicit_self.node), item.span)) } - ast::TypeImplItem(_) => None, - ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro") + ast::MacImplItem(_) => self.tcx.sess.bug("unexpanded macro"), + _ => None, } }, ast_map::NodeTraitItem(item) => { @@ -1723,8 +1723,8 @@ fn lifetimes_in_scope(tcx: &ty::ctxt, taken.push_all(&sig.generics.lifetimes); Some(ii.id) } - ast::TypeImplItem(_) => None, - ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro") + ast::MacImplItem(_) => tcx.sess.bug("unexpanded macro"), + _ => None, } } _ => None diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 003306fe558a1..6db55baf48350 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -589,7 +589,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { match def { def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) | - def::DefFn(..) | def::DefMethod(..) => { + def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => { Ok(self.cat_rvalue_node(id, span, expr_ty)) } def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) | @@ -1286,7 +1286,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { try!(self.cat_pattern_(cmt_field, &**subpat, op)); } } - Some(def::DefConst(..)) => { + Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => { for subpat in subpats { try!(self.cat_pattern_(cmt.clone(), &**subpat, op)); } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 12b56562c84d6..7a0f58947fe70 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -62,7 +62,7 @@ pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatIdent(_, _, None) | ast::PatEnum(..) => { match dm.borrow().get(&pat.id).map(|d| d.full_def()) { - Some(DefConst(..)) => true, + Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true, _ => false } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 1bd45b5fc8601..b532dc88df4cb 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -113,7 +113,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ReachableContext<'a, 'tcx> { // If this path leads to a constant, then we need to // recurse into the constant to continue finding // items that are reachable. - def::DefConst(..) => { + def::DefConst(..) | def::DefAssociatedConst(..) => { self.worklist.push(def_id.node); } @@ -183,12 +183,14 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } Some(ast_map::NodeTraitItem(trait_method)) => { match trait_method.node { + ast::ConstTraitItem(_, ref default) => default.is_some(), ast::MethodTraitItem(_, ref body) => body.is_some(), ast::TypeTraitItem(..) => false, } } Some(ast_map::NodeImplItem(impl_item)) => { match impl_item.node { + ast::ConstImplItem(..) => true, ast::MethodImplItem(ref sig, _) => { if generics_require_inlining(&sig.generics) || attr::requests_inline(&impl_item.attrs) { @@ -303,9 +305,13 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } ast_map::NodeTraitItem(trait_method) => { match trait_method.node { + ast::ConstTraitItem(_, None) | ast::MethodTraitItem(_, None) => { // Keep going, nothing to get exported } + ast::ConstTraitItem(_, Some(ref expr)) => { + self.visit_expr(&*expr); + } ast::MethodTraitItem(_, Some(ref body)) => { visit::walk_block(self, body); } @@ -314,6 +320,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { } ast_map::NodeImplItem(impl_item) => { match impl_item.node { + ast::ConstImplItem(_, ref expr) => { + self.visit_expr(&*expr); + } ast::MethodImplItem(ref sig, ref body) => { let did = self.tcx.map.get_parent_did(search_item); if method_might_be_inlined(self.tcx, sig, impl_item, did) { diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs index a2ff86cd06590..3d6ed3c344061 100644 --- a/src/librustc/middle/traits/object_safety.rs +++ b/src/librustc/middle/traits/object_safety.rs @@ -100,9 +100,7 @@ fn object_safety_violations_for_trait<'tcx>(tcx: &ty::ctxt<'tcx>, .map(|code| ObjectSafetyViolation::Method(m.clone(), code)) .into_iter() } - ty::TypeTraitItem(_) => { - None.into_iter() - } + _ => None.into_iter(), } }) .collect(); diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 7488b8f046e74..9cdae21868ed3 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -863,7 +863,7 @@ fn confirm_impl_candidate<'cx,'tcx>( for impl_item in impl_items { let assoc_type = match *impl_or_trait_items_map.get(&impl_item.def_id()).unwrap() { ty::TypeTraitItem(ref assoc_type) => assoc_type.clone(), - ty::MethodTraitItem(..) => { continue; } + ty::ConstTraitItem(..) | ty::MethodTraitItem(..) => { continue; } }; if assoc_type.name != obligation.predicate.item_name { diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index ddf941198eb0f..6ecff3b7faabe 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -434,7 +434,7 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>, for trait_item in &**trait_items { match *trait_item { ty::MethodTraitItem(_) => method_count += 1, - ty::TypeTraitItem(_) => {} + _ => {} } } } @@ -445,14 +445,14 @@ pub fn get_vtable_index_of_object_method<'tcx>(tcx: &ty::ctxt<'tcx>, for trait_item in trait_items.iter().take(method_offset_in_trait) { match *trait_item { ty::MethodTraitItem(_) => method_count += 1, - ty::TypeTraitItem(_) => {} + _ => {} } } // the item at the offset we were given really ought to be a method assert!(match trait_items[method_offset_in_trait] { ty::MethodTraitItem(_) => true, - ty::TypeTraitItem(_) => false + _ => false }); method_count diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 2c94399f92138..3f5f40ec0b59b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -131,6 +131,7 @@ impl ImplOrTraitItemContainer { #[derive(Clone, Debug)] pub enum ImplOrTraitItem<'tcx> { + ConstTraitItem(Rc>), MethodTraitItem(Rc>), TypeTraitItem(Rc), } @@ -138,6 +139,9 @@ pub enum ImplOrTraitItem<'tcx> { impl<'tcx> ImplOrTraitItem<'tcx> { fn id(&self) -> ImplOrTraitItemId { match *self { + ConstTraitItem(ref associated_const) => { + ConstTraitItemId(associated_const.def_id) + } MethodTraitItem(ref method) => MethodTraitItemId(method.def_id), TypeTraitItem(ref associated_type) => { TypeTraitItemId(associated_type.def_id) @@ -147,6 +151,7 @@ impl<'tcx> ImplOrTraitItem<'tcx> { pub fn def_id(&self) -> ast::DefId { match *self { + ConstTraitItem(ref associated_const) => associated_const.def_id, MethodTraitItem(ref method) => method.def_id, TypeTraitItem(ref associated_type) => associated_type.def_id, } @@ -154,13 +159,23 @@ impl<'tcx> ImplOrTraitItem<'tcx> { pub fn name(&self) -> ast::Name { match *self { + ConstTraitItem(ref associated_const) => associated_const.name, MethodTraitItem(ref method) => method.name, TypeTraitItem(ref associated_type) => associated_type.name, } } + pub fn vis(&self) -> ast::Visibility { + match *self { + ConstTraitItem(ref associated_const) => associated_const.vis, + MethodTraitItem(ref method) => method.vis, + TypeTraitItem(ref associated_type) => associated_type.vis, + } + } + pub fn container(&self) -> ImplOrTraitItemContainer { match *self { + ConstTraitItem(ref associated_const) => associated_const.container, MethodTraitItem(ref method) => method.container, TypeTraitItem(ref associated_type) => associated_type.container, } @@ -169,13 +184,14 @@ impl<'tcx> ImplOrTraitItem<'tcx> { pub fn as_opt_method(&self) -> Option>> { match *self { MethodTraitItem(ref m) => Some((*m).clone()), - TypeTraitItem(_) => None + _ => None, } } } #[derive(Clone, Copy, Debug)] pub enum ImplOrTraitItemId { + ConstTraitItemId(ast::DefId), MethodTraitItemId(ast::DefId), TypeTraitItemId(ast::DefId), } @@ -183,6 +199,7 @@ pub enum ImplOrTraitItemId { impl ImplOrTraitItemId { pub fn def_id(&self) -> ast::DefId { match *self { + ConstTraitItemId(def_id) => def_id, MethodTraitItemId(def_id) => def_id, TypeTraitItemId(def_id) => def_id, } @@ -236,6 +253,16 @@ impl<'tcx> Method<'tcx> { } } +#[derive(Clone, Copy, Debug)] +pub struct AssociatedConst<'tcx> { + pub name: ast::Name, + pub ty: Ty<'tcx>, + pub vis: ast::Visibility, + pub def_id: ast::DefId, + pub container: ImplOrTraitItemContainer, + pub default: Option, +} + #[derive(Clone, Copy, Debug)] pub struct AssociatedType { pub name: ast::Name, @@ -2273,6 +2300,16 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { match cx.map.find(id) { Some(ast_map::NodeImplItem(ref impl_item)) => { match impl_item.node { + ast::ConstImplItem(_, _) => { + let def_id = ast_util::local_def(id); + let scheme = lookup_item_type(cx, def_id); + let predicates = lookup_predicates(cx, def_id); + construct_parameter_environment(cx, + impl_item.span, + &scheme.generics, + &predicates, + id) + } ast::MethodImplItem(_, ref body) => { let method_def_id = ast_util::local_def(id); match ty::impl_or_trait_item(cx, method_def_id) { @@ -2286,11 +2323,10 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { method_bounds, body.id) } - TypeTraitItem(_) => { + _ => { cx.sess .bug("ParameterEnvironment::for_item(): \ - can't create a parameter environment \ - for type trait items") + got non-method item from impl method?!") } } } @@ -2304,6 +2340,25 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { } Some(ast_map::NodeTraitItem(trait_item)) => { match trait_item.node { + ast::ConstTraitItem(_, ref default) => { + match *default { + Some(_) => { + let def_id = ast_util::local_def(id); + let scheme = lookup_item_type(cx, def_id); + let predicates = lookup_predicates(cx, def_id); + construct_parameter_environment(cx, + trait_item.span, + &scheme.generics, + &predicates, + id) + } + None => { + cx.sess.bug("ParameterEnvironment::from_item(): \ + can't create a parameter environment \ + for const trait items without defaults") + } + } + } ast::MethodTraitItem(_, None) => { cx.sess.span_bug(trait_item.span, "ParameterEnvironment::for_item(): @@ -2324,11 +2379,11 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> { method_bounds, body.id) } - TypeTraitItem(_) => { + _ => { cx.sess .bug("ParameterEnvironment::for_item(): \ - can't create a parameter environment \ - for type trait items") + got non-method item from provided \ + method?!") } } } @@ -4700,7 +4755,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind { def::DefUpvar(..) | def::DefLocal(..) => LvalueExpr, - def::DefConst(..) => RvalueDatumExpr, + def::DefConst(..) | + def::DefAssociatedConst(..) => RvalueDatumExpr, def => { tcx.sess.span_bug( @@ -5051,10 +5107,10 @@ pub fn provided_trait_methods<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) if let ast::MethodTraitItem(_, Some(_)) = ti.node { match impl_or_trait_item(cx, ast_util::local_def(ti.id)) { MethodTraitItem(m) => Some(m), - TypeTraitItem(_) => { + _ => { cx.sess.bug("provided_trait_methods(): \ - associated type found from \ - looking up ProvidedMethod?!") + non-method item found from \ + looking up provided method?!") } } } else { @@ -5155,7 +5211,7 @@ pub fn is_associated_type(cx: &ctxt, id: ast::DefId) -> bool { Some(ref item) => { match **item { TypeTraitItem(_) => true, - MethodTraitItem(_) => false, + _ => false, } } None => false, @@ -6169,7 +6225,7 @@ pub fn populate_implementations_for_type_if_necessary(tcx: &ctxt, .insert(method_def_id, source); } } - TypeTraitItem(_) => {} + _ => {} } } @@ -6221,7 +6277,7 @@ pub fn populate_implementations_for_trait_if_necessary( .insert(method_def_id, source); } } - TypeTraitItem(_) => {} + _ => {} } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 12a6d5848572d..3d56371dd52ca 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -830,6 +830,7 @@ impl<'tcx> Repr<'tcx> for ty::TraitDef<'tcx> { impl<'tcx> Repr<'tcx> for ast::TraitItem { fn repr(&self, _tcx: &ctxt) -> String { let kind = match self.node { + ast::ConstTraitItem(..) => "ConstTraitItem", ast::MethodTraitItem(..) => "MethodTraitItem", ast::TypeTraitItem(..) => "TypeTraitItem", }; @@ -1054,9 +1055,39 @@ impl<'tcx> Repr<'tcx> for ty::Variance { } } +impl<'tcx> Repr<'tcx> for ty::ImplOrTraitItem<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("ImplOrTraitItem({})", + match *self { + ty::ImplOrTraitItem::MethodTraitItem(ref i) => i.repr(tcx), + ty::ImplOrTraitItem::ConstTraitItem(ref i) => i.repr(tcx), + ty::ImplOrTraitItem::TypeTraitItem(ref i) => i.repr(tcx), + }) + } +} + +impl<'tcx> Repr<'tcx> for ty::AssociatedConst<'tcx> { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("AssociatedConst(name: {}, ty: {}, vis: {}, def_id: {})", + self.name.repr(tcx), + self.ty.repr(tcx), + self.vis.repr(tcx), + self.def_id.repr(tcx)) + } +} + +impl<'tcx> Repr<'tcx> for ty::AssociatedType { + fn repr(&self, tcx: &ctxt<'tcx>) -> String { + format!("AssociatedType(name: {}, vis: {}, def_id: {})", + self.name.repr(tcx), + self.vis.repr(tcx), + self.def_id.repr(tcx)) + } +} + impl<'tcx> Repr<'tcx> for ty::Method<'tcx> { fn repr(&self, tcx: &ctxt<'tcx>) -> String { - format!("method(name: {}, generics: {}, predicates: {}, fty: {}, \ + format!("Method(name: {}, generics: {}, predicates: {}, fty: {}, \ explicit_self: {}, vis: {}, def_id: {})", self.name.repr(tcx), self.generics.repr(tcx), diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index c12ac501c45a2..f4761f9550564 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1584,8 +1584,9 @@ impl LintPass for MissingDoc { if self.private_traits.contains(&trait_item.id) { return } let desc = match trait_item.node { + ast::ConstTraitItem(..) => "an associated constant", ast::MethodTraitItem(..) => "a trait method", - ast::TypeTraitItem(..) => "an associated type" + ast::TypeTraitItem(..) => "an associated type", }; self.check_missing_docs_attrs(cx, Some(trait_item.id), @@ -1600,9 +1601,10 @@ impl LintPass for MissingDoc { } let desc = match impl_item.node { + ast::ConstImplItem(..) => "an associated constant", ast::MethodImplItem(..) => "a method", ast::TypeImplItem(_) => "an associated type", - ast::MacImplItem(_) => "an impl item macro" + ast::MacImplItem(_) => "an impl item macro", }; self.check_missing_docs_attrs(cx, Some(impl_item.id), &impl_item.attrs, diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 70c824a67a0ef..832a33e3fe0cf 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -272,6 +272,7 @@ 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::MethodImplItem(ref sig, _) => { let meth_public = match sig.explicit_self.node { ast::SelfStatic => public_ty, @@ -399,6 +400,7 @@ 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::MethodTraitItem(ref meth)) => { debug!("privacy - well at least it's a method: {:?}", *meth); @@ -490,6 +492,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { // where the method was defined? Some(ast_map::NodeImplItem(ii)) => { match ii.node { + ast::ConstImplItem(..) | ast::MethodImplItem(..) => { let imp = self.tcx.map .get_parent_did(closest_private_id); @@ -693,7 +696,11 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> { ty::MethodTraitItem(method_type) => { method_type.provided_source.unwrap_or(method_id) } - ty::TypeTraitItem(_) => method_id, + _ => { + self.tcx.sess + .span_bug(span, + "got non-method item in check_static_method") + } }; let string = token::get_name(name); @@ -1128,8 +1135,7 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { ast::MethodImplItem(..) => { check_inherited(tcx, impl_item.span, impl_item.vis); } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => {} + _ => {} } } } @@ -1307,6 +1313,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { impl_items.iter() .any(|impl_item| { match impl_item.node { + ast::ConstImplItem(..) | ast::MethodImplItem(..) => { self.exported_items.contains(&impl_item.id) } @@ -1330,6 +1337,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { // don't erroneously report errors for private // types in private items. match impl_item.node { + ast::ConstImplItem(..) | ast::MethodImplItem(..) if self.item_is_public(&impl_item.id, impl_item.vis) => { @@ -1360,12 +1368,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { // Those in 3. are warned with this call. for impl_item in impl_items { - match impl_item.node { - ast::TypeImplItem(ref ty) => { - self.visit_ty(ty); - } - ast::MethodImplItem(..) | - ast::MacImplItem(_) => {}, + if let ast::TypeImplItem(ref ty) = impl_item.node { + self.visit_ty(ty); } } } @@ -1376,15 +1380,20 @@ impl<'a, 'tcx, 'v> Visitor<'v> for VisiblePrivateTypesVisitor<'a, 'tcx> { let mut found_pub_static = false; for impl_item in impl_items { match impl_item.node { + ast::ConstImplItem(..) => { + if self.item_is_public(&impl_item.id, impl_item.vis) { + found_pub_static = true; + visit::walk_impl_item(self, impl_item); + } + } ast::MethodImplItem(ref sig, _) => { if sig.explicit_self.node == ast::SelfStatic && - self.item_is_public(&impl_item.id, impl_item.vis) { + self.item_is_public(&impl_item.id, impl_item.vis) { found_pub_static = true; visit::walk_impl_item(self, impl_item); } } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => {} + _ => {} } } if found_pub_static { diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 777154f3c9c3b..0d25700d2b7f1 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -530,6 +530,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { trait_item.span); match trait_item.node { + ast::ConstTraitItem(..) => { + let def = DefAssociatedConst(local_def(trait_item.id), + FromTrait(local_def(item.id))); + // NB: not IMPORTABLE + name_bindings.define_value(def, trait_item.span, PUBLIC); + } ast::MethodTraitItem(..) => { let def = DefMethod(local_def(trait_item.id), FromTrait(local_def(item.id))); @@ -703,7 +709,8 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { csearch::get_tuple_struct_definition_if_ctor(&self.session.cstore, ctor_id) .map_or(def, |_| DefStruct(ctor_id)), DUMMY_SP, modifiers); } - DefFn(..) | DefStatic(..) | DefConst(..) | DefMethod(..) => { + DefFn(..) | DefStatic(..) | DefConst(..) | DefAssociatedConst(..) | + DefMethod(..) => { debug!("(building reduced graph for external \ crate) building value (fn/static) {}", final_ident); // impl methods have already been defined with the correct importability modifier diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index d300045c0ec01..f43d951aaaa71 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -60,7 +60,8 @@ use rustc::middle::ty::{Freevar, FreevarMap, TraitMap, GlobMap}; use rustc::util::nodemap::{NodeMap, NodeSet, DefIdSet, FnvHashMap}; use rustc::util::lev_distance::lev_distance; -use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block, Crate, CrateNum}; +use syntax::ast::{Arm, BindByRef, BindByValue, BindingMode, Block}; +use syntax::ast::{ConstImplItem, Crate, CrateNum}; use syntax::ast::{DefId, Expr, ExprAgain, ExprBreak, ExprField}; use syntax::ast::{ExprLoop, ExprWhile, ExprMethodCall}; use syntax::ast::{ExprPath, ExprStruct, FnDecl}; @@ -1831,6 +1832,7 @@ 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, ast::MethodTraitItem(ref sig, _) => { HasTypeParameters(&sig.generics, FnSpace, @@ -2094,6 +2096,7 @@ 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(_, _) => {} MethodImplItem(ref sig, _) => { // If this is a trait impl, ensure the method // exists in trait @@ -2466,7 +2469,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // This must be an enum variant, struct or const. if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) { match path_res.base_def { - DefVariant(..) | DefStruct(..) | DefConst(..) => { + DefVariant(..) | DefStruct(..) | DefConst(..) | + DefAssociatedConst(..) => { self.record_def(pattern.id, path_res); } DefStatic(..) => { @@ -2542,7 +2546,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { def @ DefVariant(..) | def @ DefStruct(..) => { return FoundStructOrEnumVariant(def, LastMod(AllPublic)); } - def @ DefConst(..) => { + def @ DefConst(..) | def @ DefAssociatedConst(..) => { return FoundConst(def, LastMod(AllPublic)); } DefStatic(..) => { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 57dba30723f9c..237270da5628b 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -242,6 +242,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefTrait(_) => Some(recorder::TypeRef), def::DefStatic(_, _) | def::DefConst(_) | + def::DefAssociatedConst(..) | def::DefLocal(_) | def::DefVariant(_, _, _) | def::DefUpvar(..) => Some(recorder::VarRef), @@ -359,14 +360,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { // record the decl for this def (if it has one) let decl_id = ty::trait_item_of_item(&self.analysis.ty_cx, ast_util::local_def(id)) - .and_then(|def_id| { - if match def_id { - ty::MethodTraitItemId(def_id) => { - def_id.node != 0 && def_id != ast_util::local_def(id) - } - ty::TypeTraitItemId(_) => false, - } { - Some(def_id.def_id()) + .and_then(|new_id| { + let def_id = new_id.def_id(); + if def_id.node != 0 && def_id != ast_util::local_def(id) { + Some(def_id) } else { None } @@ -800,6 +797,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefLocal(..) | def::DefStatic(..) | def::DefConst(..) | + def::DefAssociatedConst(..) | def::DefVariant(..) => self.fmt.ref_str(ref_kind.unwrap_or(recorder::VarRef), span, sub_span, @@ -883,6 +881,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { def::DefLocal(_) | def::DefStatic(_,_) | def::DefConst(..) | + def::DefAssociatedConst(..) | def::DefStruct(_) | def::DefVariant(..) | def::DefFn(..) => self.write_sub_paths_truncated(path, false), @@ -966,7 +965,10 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { ty::MethodTraitItem(method) => { method.provided_source.unwrap_or(def_id) } - ty::TypeTraitItem(_) => def_id, + _ => self.sess + .span_bug(ex.span, + "save::process_method_call: non-method \ + DefId in MethodStatic or MethodStaticClosure"), }; (Some(def_id), decl_id) } @@ -1008,7 +1010,7 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { let def = self.analysis.ty_cx.def_map.borrow().get(&p.id).unwrap().full_def(); let struct_def = match def { - def::DefConst(..) => None, + def::DefConst(..) | def::DefAssociatedConst(..) => None, def::DefVariant(_, variant_id, _) => Some(variant_id), _ => { match ty::ty_to_def_id(ty::node_id_to_type(&self.analysis.ty_cx, p.id)) { @@ -1236,6 +1238,7 @@ 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::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); @@ -1246,6 +1249,7 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { match impl_item.node { + ast::ConstImplItem(..) => {} ast::MethodImplItem(ref sig, ref body) => { self.process_method(sig, Some(body), impl_item.id, impl_item.ident.name, impl_item.span); @@ -1432,8 +1436,9 @@ impl<'l, 'tcx, 'v> Visitor<'v> for DxrVisitor<'l, 'tcx> { paths_to_process.push((id, p.clone(), Some(ref_kind))) } // FIXME(nrc) what are these doing here? - def::DefStatic(_, _) => {} - def::DefConst(..) => {} + def::DefStatic(_, _) | + def::DefConst(..) | + def::DefAssociatedConst(..) => {} _ => error!("unexpected definition kind when processing collected paths: {:?}", def) } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 59f3ff7260261..1ceba3c8230d2 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1078,25 +1078,17 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option) Some(ast_map::NodeTraitItem(trait_item)) => { match trait_item.node { ast::MethodTraitItem(_, Some(ref body)) => body, - ast::MethodTraitItem(_, None) => { - tcx.sess.bug("unexpected variant: required trait method \ - in has_nested_returns") - } - ast::TypeTraitItem(..) => { - tcx.sess.bug("unexpected variant: associated type trait item in \ - has_nested_returns") + _ => { + tcx.sess.bug("unexpected variant: trait item other than a \ + provided method in has_nested_returns") } } } Some(ast_map::NodeImplItem(impl_item)) => { match impl_item.node { ast::MethodImplItem(_, ref body) => body, - ast::TypeImplItem(_) => { - tcx.sess.bug("unexpected variant: associated type impl item in \ - has_nested_returns") - } - ast::MacImplItem(_) => { - tcx.sess.bug("unexpected variant: unexpanded macro impl item in \ + _ => { + tcx.sess.bug("unexpected variant: non-method impl item in \ has_nested_returns") } } @@ -2363,13 +2355,14 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { ast_map::NodeTraitItem(trait_item) => { debug!("get_item_val(): processing a NodeTraitItem"); match trait_item.node { - ast::MethodTraitItem(_, None) | ast::TypeTraitItem(..) => { - ccx.sess().span_bug(trait_item.span, - "unexpected variant: required trait method in get_item_val()"); - } ast::MethodTraitItem(_, Some(_)) => { register_method(ccx, id, &trait_item.attrs, trait_item.span) } + _ => { + ccx.sess().span_bug(trait_item.span, + "unexpected variant: trait item other than a provided \ + method in get_item_val()"); + } } } @@ -2378,13 +2371,10 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { ast::MethodImplItem(..) => { register_method(ccx, id, &impl_item.attrs, impl_item.span) } - ast::TypeImplItem(_) => { - ccx.sess().span_bug(impl_item.span, - "unexpected variant: associated type in get_item_val()") - } - ast::MacImplItem(_) => { + _ => { ccx.sess().span_bug(impl_item.span, - "unexpected variant: unexpanded macro in get_item_val()") + "unexpected variant: non-method impl item in \ + get_item_val()"); } } } diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 0e8c33cd93a5b..0e4680723073f 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -202,6 +202,7 @@ fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &ast::Expr) } def::DefStatic(..) | def::DefConst(..) | + def::DefAssociatedConst(..) | def::DefLocal(..) | def::DefUpvar(..) => { datum_callee(bcx, ref_expr) @@ -465,9 +466,9 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( (true, source_id, new_substs) } - ty::TypeTraitItem(_) => { + _ => { tcx.sess.bug("trans_fn_ref_with_vtables() tried \ - to translate an associated type?!") + to translate a non-method?!") } } } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 7c769eca74aab..69cd57d1bab70 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -1314,15 +1314,10 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, impl_item.span, true) } - ast::TypeImplItem(_) => { - cx.sess().span_bug(impl_item.span, - "create_function_debug_context() \ - called on associated type?!") - } - ast::MacImplItem(_) => { + _ => { cx.sess().span_bug(impl_item.span, "create_function_debug_context() \ - called on unexpanded macro?!") + called on non-method impl item?!") } } } diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index e346fb0d93189..fda931fde6e6c 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -74,8 +74,7 @@ pub fn trans_impl(ccx: &CrateContext, ast::MethodImplItem(..) => { visit::walk_impl_item(&mut v, impl_item); } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => {} + _ => {} } } return; @@ -98,8 +97,7 @@ pub fn trans_impl(ccx: &CrateContext, } visit::walk_impl_item(&mut v, impl_item); } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => {} + _ => {} } } } @@ -336,9 +334,9 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let impl_did = vtable_impl.impl_def_id; let mname = match ty::trait_item(ccx.tcx(), trait_id, n_method) { ty::MethodTraitItem(method) => method.name, - ty::TypeTraitItem(_) => { - bcx.tcx().sess.bug("can't monomorphize an associated \ - type") + _ => { + bcx.tcx().sess.bug("can't monomorphize a non-method trait \ + item") } }; let mth_id = method_with_name(bcx.ccx(), impl_did, mname); @@ -579,8 +577,8 @@ pub fn trans_object_shim<'a, 'tcx>( // Lookup the type of this method as declared in the trait and apply substitutions. let method_ty = match ty::trait_item(tcx, trait_id, method_offset_in_trait) { ty::MethodTraitItem(method) => method, - ty::TypeTraitItem(_) => { - tcx.sess.bug("can't create a method shim for an associated type") + _ => { + tcx.sess.bug("can't create a method shim for a non-method item") } }; let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty); @@ -789,11 +787,11 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trait_item_def_ids .iter() - // Filter out the associated types. + // Filter out non-method items. .filter_map(|item_def_id| { match *item_def_id { ty::MethodTraitItemId(def_id) => Some(def_id), - ty::TypeTraitItemId(_) => None, + _ => None, } }) @@ -806,7 +804,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let trait_method_type = match ty::impl_or_trait_item(tcx, trait_method_def_id) { ty::MethodTraitItem(m) => m, - ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type") + _ => ccx.sess().bug("should be a method, not other assoc item"), }; let name = trait_method_type.name; @@ -824,7 +822,7 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let impl_method_def_id = method_with_name(ccx, impl_id, name); let impl_method_type = match ty::impl_or_trait_item(tcx, impl_method_def_id) { ty::MethodTraitItem(m) => m, - ty::TypeTraitItem(_) => ccx.sess().bug("should be a method, not assoc type") + _ => ccx.sess().bug("should be a method, not other assoc item"), }; debug!("emit_vtable_methods: impl_method_type={}", diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 1c8d020494fab..03fdd0c45c16a 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -236,11 +236,9 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } d } - ast::TypeImplItem(_) => { - ccx.sess().bug("can't monomorphize an associated type") - } - ast::MacImplItem(_) => { - ccx.sess().bug("can't monomorphize an unexpanded macro") + _ => { + ccx.sess().bug(&format!("can't monomorphize a {:?}", + map_node)) } } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 348846b8ad401..47388e0e5583f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -808,6 +808,7 @@ 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::MethodImplItem(ref sig, ref body) => { check_method_body(ccx, &impl_pty.generics, sig, body, impl_item.id, impl_item.span); @@ -823,6 +824,7 @@ 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. @@ -920,6 +922,7 @@ 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::MethodImplItem(_, ref body) => { let impl_method_def_id = local_def(impl_item.id); let impl_item_ty = ty::impl_or_trait_item(ccx.tcx, @@ -979,13 +982,15 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, match (associated_type, &typedef_ty) { (&ty::TypeTraitItem(_), &ty::TypeTraitItem(_)) => {} _ => { - // 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(typedef_ty.name()), - impl_trait_ref.repr(tcx))); + // 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, + "item `{}` is an associated type, \ + which doesn't match its trait `{}`", + token::get_name(typedef_ty.name()), + impl_trait_ref.repr(tcx)) } } } @@ -1012,6 +1017,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let mut missing_methods = Vec::new(); for trait_item in &*trait_items { match *trait_item { + ty::ConstTraitItem(_) => {} ty::MethodTraitItem(ref trait_method) => { let is_implemented = impl_items.iter().any(|ii| { @@ -1019,8 +1025,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::MethodImplItem(..) => { ii.ident.name == trait_method.name } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => false, + _ => false, } }); let is_provided = @@ -1035,8 +1040,7 @@ fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, ast::TypeImplItem(_) => { ii.ident.name == associated_type.name } - ast::MethodImplItem(..) | - ast::MacImplItem(_) => false, + _ => false, } }); if !is_implemented { @@ -4208,7 +4212,7 @@ fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } def::DefFn(id, _) | def::DefMethod(id, _) | def::DefStatic(id, _) | def::DefVariant(_, id, _) | - def::DefStruct(id) | def::DefConst(id) => { + def::DefStruct(id) | def::DefConst(id) | def::DefAssociatedConst(id, _) => { (ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id)) } def::DefTrait(_) | @@ -4351,6 +4355,10 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } + def::DefAssociatedConst(..) => { + segment_spaces = repeat(None).take(segments.len()).collect(); + } + // Other cases. Various nonsense that really shouldn't show up // here. If they do, an error will have been reported // elsewhere. (I hope) diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index b0c994f7f6405..fbfe73674e160 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -20,8 +20,9 @@ use metadata::csearch::{each_impl, get_impl_trait}; use metadata::csearch; use middle::subst::{self, Subst}; use middle::ty::RegionEscape; -use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId}; -use middle::ty::{ParameterEnvironment, TypeTraitItemId, lookup_item_type}; +use middle::ty::{ImplContainer, ImplOrTraitItemId, ConstTraitItemId}; +use middle::ty::{MethodTraitItemId, TypeTraitItemId}; +use middle::ty::{ParameterEnvironment, lookup_item_type}; use middle::ty::{Ty, ty_bool, ty_char, ty_enum, ty_err}; use middle::ty::{ty_param, TypeScheme, ty_ptr}; use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup}; @@ -278,6 +279,9 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let mut items: Vec = impl_items.iter().map(|impl_item| { match impl_item.node { + ast::ConstImplItem(..) => { + ConstTraitItemId(local_def(impl_item.id)) + } ast::MethodImplItem(..) => { MethodTraitItemId(local_def(impl_item.id)) } @@ -348,7 +352,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { .insert(item_def_id.def_id(), source); } } - ty::TypeTraitItem(_) => {} + _ => {} } } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 5ed93703d977f..d04e447a4608a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -196,7 +196,7 @@ impl<'a,'tcx> CrateCtxt<'a,'tcx> { let def_id = local_def(method_id); match *self.tcx.impl_or_trait_items.borrow().get(&def_id).unwrap() { ty::MethodTraitItem(ref mty) => mty.clone(), - ty::TypeTraitItem(..) => { + _ => { self.tcx.sess.bug(&format!("method with id {} has the wrong type", method_id)); } } @@ -830,43 +830,37 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { // Convert all the associated types. for impl_item in impl_items { - match impl_item.node { - ast::TypeImplItem(ref ty) => { - if opt_trait_ref.is_none() { - span_err!(tcx.sess, impl_item.span, E0202, - "associated items are not allowed in inherent impls"); - } - - as_refsociated_type(ccx, ImplContainer(local_def(it.id)), - impl_item.ident, impl_item.id, impl_item.vis); - - let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); - tcx.tcache.borrow_mut().insert(local_def(impl_item.id), - TypeScheme { - generics: ty::Generics::empty(), - ty: typ, - }); - tcx.predicates.borrow_mut().insert(local_def(impl_item.id), - ty::GenericPredicates::empty()); - write_ty_to_tcx(tcx, impl_item.id, typ); + if let ast::TypeImplItem(ref ty) = impl_item.node { + if opt_trait_ref.is_none() { + span_err!(tcx.sess, impl_item.span, E0202, + "associated items are not allowed in inherent impls"); } - ast::MethodImplItem(..) | - ast::MacImplItem(_) => {} + + as_refsociated_type(ccx, ImplContainer(local_def(it.id)), + impl_item.ident, impl_item.id, impl_item.vis); + + let typ = ccx.icx(&ty_predicates).to_ty(&ExplicitRscope, ty); + tcx.tcache.borrow_mut().insert(local_def(impl_item.id), + TypeScheme { + generics: ty::Generics::empty(), + ty: typ, + }); + tcx.predicates.borrow_mut().insert(local_def(impl_item.id), + ty::GenericPredicates::empty()); + write_ty_to_tcx(tcx, impl_item.id, typ); } } let methods = impl_items.iter().filter_map(|ii| { - match ii.node { - ast::MethodImplItem(ref sig, _) => { - // if the method specifies a visibility, use that, otherwise - // inherit the visibility from the impl (so `foo` in `pub impl - // { fn foo(); }` is public, but private in `priv impl { fn - // foo(); }`). - let method_vis = ii.vis.inherit_from(parent_visibility); - Some((sig, ii.id, ii.ident, method_vis, ii.span)) - } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => None + if let ast::MethodImplItem(ref sig, _) = ii.node { + // if the method specifies a visibility, use that, otherwise + // inherit the visibility from the impl (so `foo` in `pub impl + // { fn foo(); }` is public, but private in `priv impl { fn + // foo(); }`). + let method_vis = ii.vis.inherit_from(parent_visibility); + Some((sig, ii.id, ii.ident, method_vis, ii.span)) + } else { + None } }); convert_methods(ccx, @@ -877,18 +871,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { &ty_predicates); for impl_item in impl_items { - match impl_item.node { - ast::MethodImplItem(ref sig, ref body) => { - let body_id = body.id; - check_method_self_type(ccx, - &BindingRscope::new(), - ccx.method_ty(impl_item.id), - selfty, - &sig.explicit_self, - body_id); - } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => {} + if let ast::MethodImplItem(ref sig, ref body) = impl_item.node { + let body_id = body.id; + check_method_self_type(ccx, + &BindingRscope::new(), + ccx.method_ty(impl_item.id), + selfty, + &sig.explicit_self, + body_id); } } @@ -919,18 +909,18 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { // Convert all the associated types. for trait_item in trait_items { match trait_item.node { - ast::MethodTraitItem(..) => {} ast::TypeTraitItem(..) => { as_refsociated_type(ccx, TraitContainer(local_def(it.id)), trait_item.ident, trait_item.id, ast::Public); } + _ => {} } }; let methods = trait_items.iter().filter_map(|ti| { let sig = match ti.node { ast::MethodTraitItem(ref sig, _) => sig, - ast::TypeTraitItem(..) => return None, + _ => return None, }; Some((sig, ti.id, ti.ident, ast::Inherited, ti.span)) }); @@ -947,6 +937,9 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { let trait_item_def_ids = Rc::new(trait_items.iter().map(|trait_item| { let def_id = local_def(trait_item.id); match trait_item.node { + ast::ConstTraitItem(..) => { + ty::ConstTraitItemId(def_id) + } ast::MethodTraitItem(..) => { ty::MethodTraitItemId(def_id) } @@ -962,7 +955,7 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) { for trait_item in trait_items { let sig = match trait_item.node { ast::MethodTraitItem(ref sig, _) => sig, - ast::TypeTraitItem(..) => continue + _ => continue }; check_method_self_type(ccx, &BindingRscope::new(), @@ -1185,8 +1178,8 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, let associated_type_names: Vec<_> = items.iter().filter_map(|trait_item| { match trait_item.node { - ast::MethodTraitItem(..) => None, ast::TypeTraitItem(..) => Some(trait_item.ident.name), + _ => None, } }).collect(); @@ -1260,7 +1253,7 @@ fn trait_defines_associated_type_named(ccx: &CrateCtxt, trait_items.iter().any(|trait_item| { match trait_item.node { ast::TypeTraitItem(..) => trait_item.ident.name == assoc_name, - ast::MethodTraitItem(..) => false, + _ => false, } }) } @@ -1320,7 +1313,7 @@ fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &ast::Item) trait_items.iter().flat_map(|trait_item| { let bounds = match trait_item.node { ast::TypeTraitItem(ref bounds, _) => bounds, - ast::MethodTraitItem(..) => { + _ => { return vec!().into_iter(); } }; @@ -2227,7 +2220,8 @@ fn enforce_impl_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>, impl_items.iter() .filter_map(|item| match item.node { ast::TypeImplItem(..) => Some(ty::node_id_to_type(tcx, item.id)), - ast::MethodImplItem(..) | ast::MacImplItem(..) => None, + ast::ConstImplItem(..) | ast::MethodImplItem(..) | + ast::MacImplItem(..) => None, }) .flat_map(|ty| ctp::parameters_for_type(ty).into_iter()) .filter_map(|p| match p { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index b17702cfb8cb5..b17a7f4f3189d 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -176,6 +176,7 @@ 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 E0366, // dropck forbid specialization to concrete type or region E0367, // dropck forbid specialization to predicate not in struct/enum E0368, // binary operation `=` cannot be applied to types diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 4fc86cf181b8d..0bc3da416cb55 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -312,6 +312,7 @@ 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::MethodTraitItem(method) => { if method.vis != ast::Public && associated_trait.is_none() { return None diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 23c9edde77c33..73fbfe29224ee 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -361,6 +361,7 @@ pub enum ItemEnum { ForeignStaticItem(Static), MacroItem(Macro), PrimitiveItem(PrimitiveType), + AssociatedConstItem(Type, Option), AssociatedTypeItem(Vec, Option), DefaultImplItem(DefaultImpl), } @@ -1235,6 +1236,11 @@ impl Clean for ast::PolyTraitRef { impl Clean for ast::TraitItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.node { + ast::ConstTraitItem(ref ty, ref default) => { + AssociatedConstItem(ty.clean(cx), + default.as_ref().map(|expr| + expr.span.to_src(cx))) + } ast::MethodTraitItem(ref sig, Some(_)) => { MethodItem(sig.clean(cx)) } @@ -1260,6 +1266,12 @@ impl Clean for ast::TraitItem { impl Clean for ast::ImplItem { fn clean(&self, cx: &DocContext) -> Item { let inner = match self.node { + ast::ConstImplItem(ref ty, ref expr) => { + ConstantItem(Constant{ + type_: ty.clean(cx), + expr: expr.span.to_src(cx), + }) + } ast::MethodImplItem(ref sig, _) => { MethodItem(sig.clean(cx)) } @@ -1363,6 +1375,7 @@ impl<'tcx> Clean for ty::Method<'tcx> { impl<'tcx> Clean for ty::ImplOrTraitItem<'tcx> { fn clean(&self, cx: &DocContext) -> Item { match *self { + ty::ConstTraitItem(ref cti) => cti.clean(cx), ty::MethodTraitItem(ref mti) => mti.clean(cx), ty::TypeTraitItem(ref tti) => tti.clean(cx), } @@ -2672,6 +2685,20 @@ impl Clean for attr::Stability { } } +impl<'tcx> Clean for ty::AssociatedConst<'tcx> { + fn clean(&self, cx: &DocContext) -> Item { + Item { + source: DUMMY_SP.clean(cx), + name: Some(self.name.clean(cx)), + attrs: Vec::new(), + inner: AssociatedConstItem(self.ty.clean(cx), None), + visibility: None, + def_id: self.def_id, + stability: None, + } + } +} + impl Clean for ty::AssociatedType { fn clean(&self, cx: &DocContext) -> Item { // When loading a cross-crate associated type, the bounds for this type diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index d2385702a73d2..afc93f41172e8 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -39,6 +39,7 @@ pub enum ItemType { Primitive = 15, AssociatedType = 16, Constant = 17, + AssociatedConst = 18, } impl ItemType { @@ -63,6 +64,7 @@ impl ItemType { clean::ForeignStaticItem(..) => ItemType::Static, // no ForeignStatic clean::MacroItem(..) => ItemType::Macro, clean::PrimitiveItem(..) => ItemType::Primitive, + clean::AssociatedConstItem(..) => ItemType::AssociatedConst, clean::AssociatedTypeItem(..) => ItemType::AssociatedType, clean::DefaultImplItem(..) => ItemType::Impl, } @@ -102,6 +104,7 @@ impl ItemType { ItemType::Primitive => "primitive", ItemType::AssociatedType => "associatedtype", ItemType::Constant => "constant", + ItemType::AssociatedConst => "associatedconstant", } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1993f03efd1fa..447cf7eab458d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1629,6 +1629,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context, ItemType::Macro => ("macros", "Macros"), ItemType::Primitive => ("primitives", "Primitive Types"), ItemType::AssociatedType => ("associated-types", "Associated Types"), + ItemType::AssociatedConst => ("associated-consts", "Associated Constants"), }; try!(write!(w, "

\ @@ -1799,7 +1800,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, try!(write!(w, "{{\n")); for t in &types { try!(write!(w, " ")); - try!(render_method(w, t, MethodLink::Anchor)); + try!(render_assoc_item(w, t, AssocItemLink::Anchor)); try!(write!(w, ";\n")); } if !types.is_empty() && !required.is_empty() { @@ -1807,7 +1808,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for m in &required { try!(write!(w, " ")); - try!(render_method(w, m, MethodLink::Anchor)); + try!(render_assoc_item(w, m, AssocItemLink::Anchor)); try!(write!(w, ";\n")); } if !required.is_empty() && !provided.is_empty() { @@ -1815,7 +1816,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for m in &provided { try!(write!(w, " ")); - try!(render_method(w, m, MethodLink::Anchor)); + try!(render_assoc_item(w, m, AssocItemLink::Anchor)); try!(write!(w, " {{ ... }}\n")); } try!(write!(w, "}}")); @@ -1831,7 +1832,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, ty = shortty(m), name = *m.name.as_ref().unwrap(), stab = m.stability_class())); - try!(render_method(w, m, MethodLink::Anchor)); + try!(render_assoc_item(w, m, AssocItemLink::Anchor)); try!(write!(w, "

")); try!(document(w, m)); Ok(()) @@ -1871,7 +1872,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } // If there are methods directly on this trait object, render them here. - try!(render_methods(w, it.def_id, MethodRender::All)); + try!(render_assoc_items(w, it.def_id, AssocItemRender::All)); let cache = cache(); try!(write!(w, " @@ -1917,19 +1918,19 @@ fn assoc_type(w: &mut fmt::Formatter, it: &clean::Item, Ok(()) } -fn render_method(w: &mut fmt::Formatter, meth: &clean::Item, - link: MethodLink) -> fmt::Result { +fn render_assoc_item(w: &mut fmt::Formatter, meth: &clean::Item, + link: AssocItemLink) -> fmt::Result { fn method(w: &mut fmt::Formatter, it: &clean::Item, unsafety: ast::Unsafety, abi: abi::Abi, g: &clean::Generics, selfty: &clean::SelfTy, - d: &clean::FnDecl, link: MethodLink) -> fmt::Result { + d: &clean::FnDecl, link: AssocItemLink) -> fmt::Result { use syntax::abi::Abi; let name = it.name.as_ref().unwrap(); let anchor = format!("#{}.{}", shortty(it), name); let href = match link { - MethodLink::Anchor => anchor, - MethodLink::GotoSource(did) => { + AssocItemLink::Anchor => anchor, + AssocItemLink::GotoSource(did) => { href(did).map(|p| format!("{}{}", p.0, anchor)).unwrap_or(anchor) } }; @@ -1958,10 +1959,11 @@ fn render_method(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::AssociatedTypeItem(ref bounds, ref default) => { assoc_type(w, meth, bounds, default) } - _ => panic!("render_method called on non-method") + _ => panic!("render_assoc_item called on non-associated-item") } } @@ -2001,7 +2003,7 @@ fn item_struct(w: &mut fmt::Formatter, it: &clean::Item, try!(write!(w, "")); } } - render_methods(w, it.def_id, MethodRender::All) + render_assoc_items(w, it.def_id, AssocItemRender::All) } fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, @@ -2100,7 +2102,7 @@ fn item_enum(w: &mut fmt::Formatter, it: &clean::Item, try!(write!(w, "")); } - try!(render_methods(w, it.def_id, MethodRender::All)); + try!(render_assoc_items(w, it.def_id, AssocItemRender::All)); Ok(()) } @@ -2184,19 +2186,19 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item, } #[derive(Copy, Clone)] -enum MethodLink { +enum AssocItemLink { Anchor, GotoSource(ast::DefId), } -enum MethodRender<'a> { +enum AssocItemRender<'a> { All, DerefFor { trait_: &'a clean::Type, type_: &'a clean::Type }, } -fn render_methods(w: &mut fmt::Formatter, - it: ast::DefId, - what: MethodRender) -> fmt::Result { +fn render_assoc_items(w: &mut fmt::Formatter, + it: ast::DefId, + what: AssocItemRender) -> fmt::Result { let c = cache(); let v = match c.impls.get(&it) { Some(v) => v, @@ -2207,21 +2209,21 @@ fn render_methods(w: &mut fmt::Formatter, }); if !non_trait.is_empty() { let render_header = match what { - MethodRender::All => { + AssocItemRender::All => { try!(write!(w, "

Methods

")); true } - MethodRender::DerefFor { trait_, type_ } => { + AssocItemRender::DerefFor { trait_, type_ } => { try!(write!(w, "

Methods from \ {}<Target={}>

", trait_, type_)); false } }; for i in &non_trait { - try!(render_impl(w, i, MethodLink::Anchor, render_header)); + try!(render_impl(w, i, AssocItemLink::Anchor, render_header)); } } - if let MethodRender::DerefFor { .. } = what { + if let AssocItemRender::DerefFor { .. } = what { return Ok(()) } if !traits.is_empty() { @@ -2243,7 +2245,7 @@ fn render_methods(w: &mut fmt::Formatter, }); for i in &manual { let did = i.trait_did().unwrap(); - try!(render_impl(w, i, MethodLink::GotoSource(did), true)); + try!(render_impl(w, i, AssocItemLink::GotoSource(did), true)); } if !derived.is_empty() { try!(write!(w, "

\ @@ -2251,7 +2253,7 @@ fn render_methods(w: &mut fmt::Formatter,

")); for i in &derived { let did = i.trait_did().unwrap(); - try!(render_impl(w, i, MethodLink::GotoSource(did), true)); + try!(render_impl(w, i, AssocItemLink::GotoSource(did), true)); } } } @@ -2266,14 +2268,14 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result { _ => None, } }).next().unwrap(); - let what = MethodRender::DerefFor { trait_: deref_type, type_: target }; + let what = AssocItemRender::DerefFor { trait_: deref_type, type_: target }; match *target { - clean::ResolvedPath { did, .. } => render_methods(w, did, what), + clean::ResolvedPath { did, .. } => render_assoc_items(w, did, what), _ => { if let Some(prim) = target.primitive_type() { if let Some(c) = cache().primitive_locations.get(&prim) { let did = ast::DefId { krate: *c, node: prim.to_node_id() }; - try!(render_methods(w, did, what)); + try!(render_assoc_items(w, did, what)); } } Ok(()) @@ -2281,7 +2283,7 @@ fn render_deref_methods(w: &mut fmt::Formatter, impl_: &Impl) -> fmt::Result { } } -fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, +fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: AssocItemLink, render_header: bool) -> fmt::Result { if render_header { try!(write!(w, "

impl{} ", @@ -2300,13 +2302,13 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, } fn doctraititem(w: &mut fmt::Formatter, item: &clean::Item, - link: MethodLink) -> fmt::Result { + link: AssocItemLink) -> fmt::Result { match item.inner { clean::MethodItem(..) | clean::TyMethodItem(..) => { try!(write!(w, "

", *item.name.as_ref().unwrap(), shortty(item))); - try!(render_method(w, item, link)); + try!(render_assoc_item(w, item, link)); try!(write!(w, "

\n")); } clean::TypedefItem(ref tydef) => { @@ -2317,6 +2319,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, try!(write!(w, "type {} = {}", name, tydef.type_)); try!(write!(w, "

\n")); } + clean::AssociatedConstItem(_, _) => {} clean::AssociatedTypeItem(ref bounds, ref default) => { let name = item.name.as_ref().unwrap(); try!(write!(w, "

", @@ -2327,7 +2330,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, } _ => panic!("can't make docs for trait item with name {:?}", item.name) } - if let MethodLink::Anchor = link { + if let AssocItemLink::Anchor = link { document(w, item) } else { Ok(()) @@ -2339,10 +2342,10 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, try!(doctraititem(w, trait_item, link)); } - fn render_default_methods(w: &mut fmt::Formatter, - did: ast::DefId, - t: &clean::Trait, - i: &clean::Impl) -> fmt::Result { + fn render_default_items(w: &mut fmt::Formatter, + did: ast::DefId, + t: &clean::Trait, + i: &clean::Impl) -> fmt::Result { for trait_item in &t.items { let n = trait_item.name.clone(); match i.items.iter().find(|m| { m.name == n }) { @@ -2350,7 +2353,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, None => {} } - try!(doctraititem(w, trait_item, MethodLink::GotoSource(did))); + try!(doctraititem(w, trait_item, AssocItemLink::GotoSource(did))); } Ok(()) } @@ -2361,7 +2364,7 @@ fn render_impl(w: &mut fmt::Formatter, i: &Impl, link: MethodLink, // for them work. if let Some(clean::ResolvedPath { did, .. }) = i.impl_.trait_ { if let Some(t) = cache().traits.get(&did) { - try!(render_default_methods(w, did, t, &i.impl_)); + try!(render_default_items(w, did, t, &i.impl_)); } } try!(write!(w, "")); @@ -2458,7 +2461,7 @@ fn item_primitive(w: &mut fmt::Formatter, it: &clean::Item, _p: &clean::PrimitiveType) -> fmt::Result { try!(document(w, it)); - render_methods(w, it.def_id, MethodRender::All) + render_assoc_items(w, it.def_id, AssocItemRender::All) } fn get_basic_keywords() -> &'static str { diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 53cfbb3efdda5..74c16127f41cc 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -184,7 +184,8 @@ impl<'a> fold::DocFolder for Stripper<'a> { // Primitives are never stripped clean::PrimitiveItem(..) => {} - // Associated types are never stripped + // Associated consts and types are never stripped + clean::AssociatedConstItem(..) | clean::AssociatedTypeItem(..) => {} } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 399810cb7f501..3f2e7c765a5e4 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1236,6 +1236,7 @@ pub struct TraitItem { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum TraitItem_ { + ConstTraitItem(P, Option>), MethodTraitItem(MethodSig, Option>), TypeTraitItem(TyParamBounds, Option>), } @@ -1252,6 +1253,7 @@ pub struct ImplItem { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum ImplItem_ { + ConstImplItem(P, P), MethodImplItem(MethodSig, P), TypeImplItem(P), MacImplItem(Mac), diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 1505d1e91b820..36a7f3a93817c 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -222,8 +222,7 @@ impl<'a> FnLikeNode<'a> { ast::MethodImplItem(ref sig, ref body) => { method(ii.id, ii.ident, sig, Some(ii.vis), body, ii.span) } - ast::TypeImplItem(_) | - ast::MacImplItem(_) => { + _ => { panic!("impl method FnLikeNode that is not fn-like") } } diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 2a9a609ecd1e9..795391d400914 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -940,6 +940,12 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { } Some(NodeImplItem(ii)) => { match ii.node { + ConstImplItem(..) => { + format!("assoc const {} in {}{}", + token::get_ident(ii.ident), + map.path_to_string(id), + id_str) + } MethodImplItem(..) => { format!("method {} in {}{}", token::get_ident(ii.ident), @@ -959,9 +965,9 @@ fn node_id_to_string(map: &Map, id: NodeId, include_id: bool) -> String { } Some(NodeTraitItem(ti)) => { let kind = match ti.node { + ConstTraitItem(..) => "assoc constant", MethodTraitItem(..) => "trait method", TypeTraitItem(..) => "assoc type", -// ConstTraitItem(..) => "assoc constant" }; format!("{} {} in {}{}", diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 8ba36cefc65dd..22bc3a198e231 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -973,6 +973,10 @@ pub fn noop_fold_trait_item(i: P, folder: &mut T) ident: folder.fold_ident(ident), attrs: fold_attrs(attrs, folder), node: match node { + ConstTraitItem(ty, default) => { + ConstTraitItem(folder.fold_ty(ty), + default.map(|x| folder.fold_expr(x))) + } MethodTraitItem(sig, body) => { MethodTraitItem(noop_fold_method_sig(sig, folder), body.map(|x| folder.fold_block(x))) @@ -994,6 +998,9 @@ pub fn noop_fold_impl_item(i: P, folder: &mut T) attrs: fold_attrs(attrs, folder), vis: vis, node: match node { + ConstImplItem(ty, expr) => { + ConstImplItem(folder.fold_ty(ty), folder.fold_expr(expr)) + } MethodImplItem(sig, body) => { MethodImplItem(noop_fold_method_sig(sig, folder), folder.fold_block(body)) diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 5a57e09fcfff2..6fd2a8b181518 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1269,6 +1269,7 @@ 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::MethodTraitItem(ref sig, ref body) => { if body.is_some() { try!(self.head("")); @@ -1295,6 +1296,7 @@ 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::MethodImplItem(ref sig, ref body) => { try!(self.head("")); try!(self.print_method_sig(ii.ident, sig, ii.vis)); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 4c70fc9f81fb9..2ab353676251e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -619,6 +619,12 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai visitor.visit_attribute(attr); } match trait_item.node { + ConstTraitItem(ref ty, ref default) => { + visitor.visit_ty(ty); + if let Some(ref expr) = *default { + visitor.visit_expr(expr); + } + } MethodTraitItem(ref sig, None) => { visitor.visit_explicit_self(&sig.explicit_self); visitor.visit_generics(&sig.generics); @@ -641,6 +647,10 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_attribute(attr); } match impl_item.node { + ConstImplItem(ref ty, ref expr) => { + visitor.visit_ty(ty); + visitor.visit_expr(expr); + } MethodImplItem(ref sig, ref body) => { visitor.visit_fn(FkMethod(impl_item.ident, sig, Some(impl_item.vis)), &sig.decl, body, impl_item.span, impl_item.id); From 7129e8815e3203ceae5bb85b0faa8e8753e520e3 Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Sun, 15 Mar 2015 19:35:25 -0600 Subject: [PATCH 2/8] Functional changes for associated constants. Cross-crate usage of associated constants is not yet working. --- src/grammar/parser-lalr.y | 23 +- src/librustc/metadata/csearch.rs | 7 + src/librustc/metadata/decoder.rs | 62 +++- src/librustc/metadata/encoder.rs | 83 +++++- src/librustc/middle/check_const.rs | 33 ++- src/librustc/middle/check_match.rs | 15 +- src/librustc/middle/check_static_recursion.rs | 112 ++++--- src/librustc/middle/const_eval.rs | 161 +++++++++- src/librustc/middle/ty.rs | 49 +++- src/librustc_borrowck/borrowck/mod.rs | 14 + src/librustc_driver/pretty.rs | 24 ++ src/librustc_lint/builtin.rs | 21 ++ src/librustc_privacy/lib.rs | 45 ++- src/librustc_resolve/lib.rs | 42 ++- src/librustc_trans/save/mod.rs | 33 ++- src/librustc_trans/trans/consts.rs | 16 +- src/librustc_typeck/check/compare_method.rs | 82 ++++++ src/librustc_typeck/check/method/confirm.rs | 23 +- src/librustc_typeck/check/method/mod.rs | 17 +- src/librustc_typeck/check/method/probe.rs | 276 +++++++++--------- src/librustc_typeck/check/mod.rs | 123 ++++++-- src/librustc_typeck/collect.rs | 70 ++++- src/librustc_typeck/diagnostics.rs | 5 +- src/librustdoc/clean/inline.rs | 29 +- src/librustdoc/html/render.rs | 24 +- src/libsyntax/parse/parser.rs | 26 +- src/libsyntax/print/pprust.rs | 30 +- .../associated-const-private-impl.rs | 27 ++ .../impl-type-where-trait-has-method.rs | 21 ++ src/test/parse-fail/issue-20711-2.rs | 2 +- src/test/parse-fail/issue-20711.rs | 2 +- src/test/parse-fail/issue-21153.rs | 2 +- .../parse-fail/removed-syntax-static-fn.rs | 2 +- src/test/parse-fail/trait-pub-assoc-const.rs | 16 + src/test/parse-fail/trait-pub-assoc-ty.rs | 3 +- src/test/parse-fail/trait-pub-method.rs | 3 +- .../associated-const-inherent-impl.rs | 19 ++ .../associated-const-overwrite-default.rs | 23 ++ .../run-pass/associated-const-public-impl.rs | 26 ++ .../run-pass/associated-const-self-type.rs | 23 ++ .../associated-const-ufcs-infer-trait.rs | 23 ++ .../run-pass/associated-const-use-default.rs | 21 ++ src/test/run-pass/associated-const.rs | 23 ++ 43 files changed, 1387 insertions(+), 294 deletions(-) create mode 100644 src/test/compile-fail/associated-const-private-impl.rs create mode 100644 src/test/compile-fail/impl-type-where-trait-has-method.rs create mode 100644 src/test/parse-fail/trait-pub-assoc-const.rs create mode 100644 src/test/run-pass/associated-const-inherent-impl.rs create mode 100644 src/test/run-pass/associated-const-overwrite-default.rs create mode 100644 src/test/run-pass/associated-const-public-impl.rs create mode 100644 src/test/run-pass/associated-const-self-type.rs create mode 100644 src/test/run-pass/associated-const-ufcs-infer-trait.rs create mode 100644 src/test/run-pass/associated-const-use-default.rs create mode 100644 src/test/run-pass/associated-const.rs diff --git a/src/grammar/parser-lalr.y b/src/grammar/parser-lalr.y index 6c3fd186cd423..27e15bc2f0eea 100644 --- a/src/grammar/parser-lalr.y +++ b/src/grammar/parser-lalr.y @@ -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 diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index d528e38d341cf..93056d949dbb0 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -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>> { + 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 { let cdata = cstore.get_crate_data(def.krate); diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 8e3f77f949b6b..00a7fe68f2fb0 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -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, 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, return result; } +pub fn get_associated_consts<'tcx>(intr: Rc, + cdata: Cmd, + id: ast::NodeId, + tcx: &ty::ctxt<'tcx>) + -> Vec>> { + 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 { let item = lookup_item(node_id, cdata.data()); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 5f31e24a0637f..bcbb350fc34ee 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -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(); diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index ee9d1e015539e..80326229618c2 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -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 => { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 912854a6d7dfb..13be6d0cb7d9b 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -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) { diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index b97978fc03fff..a521c4531c9a7 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -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 } -// 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(&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, diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 2c6ffb3281fcb..b5a173a569f45 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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) + -> Option<&'tcx Expr> { if ast_util::is_local(def_id) { match tcx.map.find(def_id.node) { None => None, Some(ast_map::NodeItem(it)) => match it.node { ast::ItemConst(_, ref const_expr) => { - Some(&**const_expr) + Some(&*const_expr) + } + _ => None + }, + Some(ast_map::NodeTraitItem(ti)) => match ti.node { + ast::ConstTraitItem(_, ref default) => { + match maybe_ref_id { + Some(ref_id) => { + let trait_id = ty::trait_of_item(tcx, def_id) + .unwrap(); + resolve_trait_associated_const(tcx, ti, trait_id, + ref_id) + } + None => default.as_ref().map(|expr| &**expr), + } + } + _ => None + }, + Some(ast_map::NodeImplItem(ii)) => match ii.node { + ast::ConstImplItem(_, ref expr) => { + Some(&*expr) } _ => None }, @@ -122,16 +146,42 @@ pub fn lookup_const_by_id<'a>(tcx: &'a ty::ctxt, def_id: ast::DefId) } None => {} } + let mut used_ref_id = false; let expr_id = match csearch::maybe_get_item_ast(tcx, def_id, Box::new(|a, b, c, d| astencode::decode_inlined_item(a, b, c, d))) { csearch::FoundAst::Found(&ast::IIItem(ref item)) => match item.node { ast::ItemConst(_, ref const_expr) => Some(const_expr.id), _ => None }, + csearch::FoundAst::Found(&ast::IITraitItem(_, ref ti)) => match ti.node { + ast::ConstTraitItem(_, ref default) => { + used_ref_id = true; + match maybe_ref_id { + Some(ref_id) => { + let trait_id = ty::trait_of_item(tcx, def_id) + .unwrap(); + resolve_trait_associated_const(tcx, ti, trait_id, + ref_id).map(|e| e.id) + } + None => default.as_ref().map(|expr| expr.id), + } + } + _ => None + }, + csearch::FoundAst::Found(&ast::IIImplItem(_, ref ii)) => match ii.node { + ast::ConstImplItem(_, ref expr) => Some(expr.id), + _ => None + }, _ => None }; - tcx.extern_const_statics.borrow_mut().insert(def_id, - expr_id.unwrap_or(ast::DUMMY_NODE_ID)); + // If we used the reference expression, particularly to choose an impl + // of a trait-associated const, don't cache that, because the next + // lookup with the same def_id may yield a different result. + if used_ref_id { + tcx.extern_const_statics + .borrow_mut().insert(def_id, + expr_id.unwrap_or(ast::DUMMY_NODE_ID)); + } expr_id.map(|id| tcx.map.expect_expr(id)) } } @@ -755,7 +805,35 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, _ => (None, None) } } else { - (lookup_const_by_id(tcx, def_id), None) + (lookup_const_by_id(tcx, def_id, Some(e.id)), None) + } + } + Some(def::DefAssociatedConst(def_id, provenance)) => { + if ast_util::is_local(def_id) { + match provenance { + def::FromTrait(trait_id) => match tcx.map.find(def_id.node) { + Some(ast_map::NodeTraitItem(ti)) => match ti.node { + ast::ConstTraitItem(ref ty, _) => { + (resolve_trait_associated_const(tcx, ti, + trait_id, e.id), + Some(&**ty)) + } + _ => (None, None) + }, + _ => (None, None) + }, + def::FromImpl(_) => match tcx.map.find(def_id.node) { + Some(ast_map::NodeImplItem(ii)) => match ii.node { + ast::ConstImplItem(ref ty, ref expr) => { + (Some(&**expr), Some(&**ty)) + } + _ => (None, None) + }, + _ => (None, None) + }, + } + } else { + (lookup_const_by_id(tcx, def_id, Some(e.id)), None) } } Some(def::DefVariant(enum_def, variant_def, _)) => { @@ -833,6 +911,71 @@ pub fn eval_const_expr_partial<'tcx>(tcx: &ty::ctxt<'tcx>, Ok(result) } +fn resolve_trait_associated_const<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, + ti: &'tcx ast::TraitItem, + trait_id: ast::DefId, + ref_id: ast::NodeId) + -> Option<&'tcx Expr> +{ + let rcvr_substs = ty::node_id_item_substs(tcx, ref_id).substs; + let subst::SeparateVecsPerParamSpace { + types: rcvr_type, + selfs: rcvr_self, + fns: _, + } = rcvr_substs.types.split(); + let trait_substs = + subst::Substs::erased(subst::VecPerParamSpace::new(rcvr_type, + rcvr_self, + Vec::new())); + let trait_substs = tcx.mk_substs(trait_substs); + debug!("resolve_trait_associated_const: trait_substs={}", + trait_substs.repr(tcx)); + let trait_ref = ty::Binder(Rc::new(ty::TraitRef { def_id: trait_id, + substs: trait_substs })); + + ty::populate_implementations_for_trait_if_necessary(tcx, trait_ref.def_id()); + let infcx = infer::new_infer_ctxt(tcx); + + let param_env = ty::empty_parameter_environment(tcx); + let mut selcx = traits::SelectionContext::new(&infcx, ¶m_env); + let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), + trait_ref.to_poly_trait_predicate()); + let selection = match selcx.select(&obligation) { + Ok(Some(vtable)) => vtable, + // Still ambiguous, so give up and let the caller decide whether this + // expression is really needed yet. Some associated constant values + // can't be evaluated until monomorphization is done in trans. + Ok(None) => { + return None + } + Err(e) => { + tcx.sess.span_bug(ti.span, + &format!("Encountered error `{}` when trying \ + to select an implementation for \ + constant trait item reference.", + e.repr(tcx))) + } + }; + + match selection { + traits::VtableImpl(ref impl_data) => { + match ty::associated_consts(tcx, impl_data.impl_def_id) + .iter().find(|ic| ic.name == ti.ident.name) { + Some(ic) => lookup_const_by_id(tcx, ic.def_id, None), + None => match ti.node { + ast::ConstTraitItem(_, Some(ref expr)) => Some(&*expr), + _ => None, + }, + } + } + _ => { + tcx.sess.span_bug( + ti.span, + &format!("resolve_trait_associated_const: unexpected vtable type")) + } + } +} + fn cast_const<'tcx>(tcx: &ty::ctxt<'tcx>, val: const_val, ty: Ty) -> CastResult { macro_rules! convert_val { ($intermediate_ty:ty, $const_type:ident, $target_ty:ty) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3f5f40ec0b59b..1b5e31f61d8ae 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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>> { + 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 diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 502321d07598c..19cdc19415337 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -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) { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 00c3450ebb935..b8032bda8d070 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -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) -> SmallVector> { + 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) -> SmallVector> { + 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) -> P { fn expr_to_block(rules: ast::BlockCheckMode, diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index f4761f9550564..902e9ffca1f64 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -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); diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 832a33e3fe0cf..128e29ee76e7d 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -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"), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index f43d951aaaa71..41a6f4adfe038 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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 diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 237270da5628b..dc14ef3696f5f 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -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); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index 38136b03a2141..9932899ed8f0f 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -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, _) => { diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 532277d75b2e0..9f0a03878be79 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -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; + } + } +} diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 7eb15a1479634..cf1323e71bd0e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -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())); } } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index f1a4dbf7cd528..c5d8e2758ba5c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -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)) } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 08e2f47c5a675..7ff1355184b56 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -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>>, opt_simplified_steps: Option>, inherent_candidates: Vec>, @@ -54,7 +54,7 @@ struct CandidateStep<'tcx> { struct Candidate<'tcx> { xform_self_ty: Ty<'tcx>, - method_ty: Rc>, + 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>, - 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>, + 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, 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 `::method`. + // An expression of the form `Type::item` or `::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>, opt_simplified_steps: Option>) -> 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::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>, - 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>, - 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>, - 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>, - 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` 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>, + 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>, + 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>> +fn impl_item<'tcx>(tcx: &ty::ctxt<'tcx>, + impl_def_id: ast::DefId, + item_name: ast::Name) + -> Option> { 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>)> +/// 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), diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 47388e0e5583f..d04205666f2ea 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -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::`, contains parameters in TypeSpace, and the // final segment, `foo::` contains parameters in fn space. // + // 4. Reference to an *associated const*: + // + // impl AnotherStruct { + // const FOO: B = BAR; + // } + // + // The path in this case will look like + // `a::b::AnotherStruct::::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 diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index d04e447a4608a..8bb0596753c7b 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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 { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index b17a7f4f3189d..a4814b36fe5b1 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -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 `=` cannot be applied to types diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 0bc3da416cb55..0d59577a6d802 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 447cf7eab458d..3d1e47345d42f 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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) + -> 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, default: &Option) @@ -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, "

\n")); } - clean::AssociatedConstItem(_, _) => {} + clean::AssociatedConstItem(ref ty, ref default) => { + let name = item.name.as_ref().unwrap(); + try!(write!(w, "

", + *name, + shortty(item))); + try!(assoc_const(w, item, ty, default)); + try!(write!(w, "

\n")); + } clean::AssociatedTypeItem(ref bounds, ref default) => { let name = item.name.as_ref().unwrap(); try!(write!(w, "

", diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index dc577f603f621..9a1c963b8eb0b 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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()); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6fd2a8b181518..4cfb9e4147a95 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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)); diff --git a/src/test/compile-fail/associated-const-private-impl.rs b/src/test/compile-fail/associated-const-private-impl.rs new file mode 100644 index 0000000000000..1d74873a5d50b --- /dev/null +++ b/src/test/compile-fail/associated-const-private-impl.rs @@ -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 or the MIT license +// , 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 +} diff --git a/src/test/compile-fail/impl-type-where-trait-has-method.rs b/src/test/compile-fail/impl-type-where-trait-has-method.rs new file mode 100644 index 0000000000000..eb75b82424d71 --- /dev/null +++ b/src/test/compile-fail/impl-type-where-trait-has-method.rs @@ -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 or the MIT license +// , 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 () {} diff --git a/src/test/parse-fail/issue-20711-2.rs b/src/test/parse-fail/issue-20711-2.rs index 2c993b7654e67..be6bd516d6fe4 100644 --- a/src/test/parse-fail/issue-20711-2.rs +++ b/src/test/parse-fail/issue-20711-2.rs @@ -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() {} diff --git a/src/test/parse-fail/issue-20711.rs b/src/test/parse-fail/issue-20711.rs index 8462bd8fd016a..d1d8d3acf9187 100644 --- a/src/test/parse-fail/issue-20711.rs +++ b/src/test/parse-fail/issue-20711.rs @@ -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() {} diff --git a/src/test/parse-fail/issue-21153.rs b/src/test/parse-fail/issue-21153.rs index 44d979ba9798b..76a4687f544da 100644 --- a/src/test/parse-fail/issue-21153.rs +++ b/src/test/parse-fail/issue-21153.rs @@ -11,5 +11,5 @@ // compile-flags: -Z parse-only trait MyTrait: 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` } diff --git a/src/test/parse-fail/removed-syntax-static-fn.rs b/src/test/parse-fail/removed-syntax-static-fn.rs index be1e89dd71799..7b6caad86b6cc 100644 --- a/src/test/parse-fail/removed-syntax-static-fn.rs +++ b/src/test/parse-fail/removed-syntax-static-fn.rs @@ -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` diff --git a/src/test/parse-fail/trait-pub-assoc-const.rs b/src/test/parse-fail/trait-pub-assoc-const.rs new file mode 100644 index 0000000000000..adce0d7bbf4b6 --- /dev/null +++ b/src/test/parse-fail/trait-pub-assoc-const.rs @@ -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 or the MIT license +// , 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() {} diff --git a/src/test/parse-fail/trait-pub-assoc-ty.rs b/src/test/parse-fail/trait-pub-assoc-ty.rs index 02d76234d4e57..dab6c433aba4c 100644 --- a/src/test/parse-fail/trait-pub-assoc-ty.rs +++ b/src/test/parse-fail/trait-pub-assoc-ty.rs @@ -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() {} diff --git a/src/test/parse-fail/trait-pub-method.rs b/src/test/parse-fail/trait-pub-method.rs index e76802d2ea0f7..7cb9363830c43 100644 --- a/src/test/parse-fail/trait-pub-method.rs +++ b/src/test/parse-fail/trait-pub-method.rs @@ -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() {} diff --git a/src/test/run-pass/associated-const-inherent-impl.rs b/src/test/run-pass/associated-const-inherent-impl.rs new file mode 100644 index 0000000000000..71f7a925d55d9 --- /dev/null +++ b/src/test/run-pass/associated-const-inherent-impl.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/run-pass/associated-const-overwrite-default.rs b/src/test/run-pass/associated-const-overwrite-default.rs new file mode 100644 index 0000000000000..26ece859e143d --- /dev/null +++ b/src/test/run-pass/associated-const-overwrite-default.rs @@ -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 or the MIT license +// , 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, ::ID); +} diff --git a/src/test/run-pass/associated-const-public-impl.rs b/src/test/run-pass/associated-const-public-impl.rs new file mode 100644 index 0000000000000..08676425a514d --- /dev/null +++ b/src/test/run-pass/associated-const-public-impl.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/run-pass/associated-const-self-type.rs b/src/test/run-pass/associated-const-self-type.rs new file mode 100644 index 0000000000000..b4fb452e02003 --- /dev/null +++ b/src/test/run-pass/associated-const-self-type.rs @@ -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 or the MIT license +// , 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, ::ONE); +} diff --git a/src/test/run-pass/associated-const-ufcs-infer-trait.rs b/src/test/run-pass/associated-const-ufcs-infer-trait.rs new file mode 100644 index 0000000000000..21e1159366d5a --- /dev/null +++ b/src/test/run-pass/associated-const-ufcs-infer-trait.rs @@ -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 or the MIT license +// , 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, ::ID); +} diff --git a/src/test/run-pass/associated-const-use-default.rs b/src/test/run-pass/associated-const-use-default.rs new file mode 100644 index 0000000000000..59c83e267dbe1 --- /dev/null +++ b/src/test/run-pass/associated-const-use-default.rs @@ -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 or the MIT license +// , 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, ::ID); +} diff --git a/src/test/run-pass/associated-const.rs b/src/test/run-pass/associated-const.rs new file mode 100644 index 0000000000000..5e7cc12cf485b --- /dev/null +++ b/src/test/run-pass/associated-const.rs @@ -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 or the MIT license +// , 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, ::ID); +} From 3d9b5d04242567648800c5594695f147c6bca05b Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Sat, 21 Mar 2015 15:06:28 -0600 Subject: [PATCH 3/8] Fix a number of bugs that interfered with cross-crate usage of associated consts. --- src/librustc/metadata/decoder.rs | 30 ++++++------ src/librustc/middle/const_eval.rs | 28 +++++++---- src/librustc/middle/ty.rs | 3 +- src/librustc_trans/trans/inline.rs | 8 ++++ src/test/auxiliary/associated-const-cc-lib.rs | 46 +++++++++++++++++++ .../associated-const-cross-crate-defaults.rs | 30 ++++++++++++ .../run-pass/associated-const-cross-crate.rs | 25 ++++++++++ .../associated-const-in-global-const.rs | 21 +++++++++ 8 files changed, 167 insertions(+), 24 deletions(-) create mode 100644 src/test/auxiliary/associated-const-cc-lib.rs create mode 100644 src/test/run-pass/associated-const-cross-crate-defaults.rs create mode 100644 src/test/run-pass/associated-const-cross-crate.rs create mode 100644 src/test/run-pass/associated-const-in-global-const.rs diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 00a7fe68f2fb0..f03a2d342d7be 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1002,21 +1002,23 @@ pub fn get_associated_consts<'tcx>(intr: Rc, 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()) + 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 - }); + true + }); + } return result; } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index b5a173a569f45..916874f1c51a8 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -117,15 +117,25 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, _ => None }, Some(ast_map::NodeTraitItem(ti)) => match ti.node { - ast::ConstTraitItem(_, ref default) => { + ast::ConstTraitItem(_, _) => { match maybe_ref_id { + // If we have a trait item, and we know the expression + // that's the source of the obligation to resolve it, + // `resolve_trait_associated_const` will select an impl + // or the default. 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), + // Technically, without knowing anything about the + // expression that generates the obligation, we could + // still return the default if there is one. However, + // it's safer to return `None` than to return some value + // that may differ from what you would get from + // correctly selecting an impl. + None => None } } _ => None @@ -153,17 +163,19 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, ast::ItemConst(_, ref const_expr) => Some(const_expr.id), _ => None }, - csearch::FoundAst::Found(&ast::IITraitItem(_, ref ti)) => match ti.node { - ast::ConstTraitItem(_, ref default) => { + csearch::FoundAst::Found(&ast::IITraitItem(trait_id, ref ti)) => match ti.node { + ast::ConstTraitItem(_, _) => { used_ref_id = true; match maybe_ref_id { + // As mentioned in the comments above for in-crate + // constants, we only try to find the expression for + // a trait-associated const if the caller gives us + // the expression that refers to it. 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 => None } } _ => None @@ -177,7 +189,7 @@ pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: &'a ty::ctxt<'tcx>, // 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 { + if !used_ref_id { tcx.extern_const_statics .borrow_mut().insert(def_id, expr_id.unwrap_or(ast::DUMMY_NODE_ID)); diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 1b5e31f61d8ae..41745c6384b38 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5167,8 +5167,7 @@ pub fn associated_consts<'tcx>(cx: &ctxt<'tcx>, id: ast::DefId) } } } else { - let acs = csearch::get_associated_consts(cx, id); - acs.iter().map(|ac| (*ac).clone()).collect() + csearch::get_associated_consts(cx, id) } } diff --git a/src/librustc_trans/trans/inline.rs b/src/librustc_trans/trans/inline.rs index 2034c6223c134..3f44bc40f356b 100644 --- a/src/librustc_trans/trans/inline.rs +++ b/src/librustc_trans/trans/inline.rs @@ -134,6 +134,14 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: ast::DefId) ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1); + // Associated consts already have to be evaluated in `typeck`, so + // the logic to do that already exists in `middle`. In order to + // reuse that code, it needs to be able to look up the traits for + // inlined items. + let ty_trait_item = ty::impl_or_trait_item(ccx.tcx(), fn_id).clone(); + ccx.tcx().impl_or_trait_items.borrow_mut() + .insert(local_def(trait_item.id), ty_trait_item); + // If this is a default method, we can't look up the // impl type. But we aren't going to translate anyways, so // don't. diff --git a/src/test/auxiliary/associated-const-cc-lib.rs b/src/test/auxiliary/associated-const-cc-lib.rs new file mode 100644 index 0000000000000..9735c6cb54d2b --- /dev/null +++ b/src/test/auxiliary/associated-const-cc-lib.rs @@ -0,0 +1,46 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type="lib"] + +use std::marker::MarkerTrait; + +// These items are for testing that associated consts work cross-crate. +pub trait Foo: MarkerTrait { + const BAR: usize; +} + +pub struct FooNoDefault; + +impl Foo for FooNoDefault { + const BAR: usize = 0; +} + +// These test that defaults and default resolution work cross-crate. +pub trait FooDefault: MarkerTrait { + const BAR: usize = 1; +} + +pub struct FooOverwriteDefault; + +impl FooDefault for FooOverwriteDefault { + const BAR: usize = 2; +} + +pub struct FooUseDefault; + +impl FooDefault for FooUseDefault {} + +// Test inherent impls. +pub struct InherentBar; + +impl InherentBar { + pub const BAR: usize = 3; +} diff --git a/src/test/run-pass/associated-const-cross-crate-defaults.rs b/src/test/run-pass/associated-const-cross-crate-defaults.rs new file mode 100644 index 0000000000000..944466f359da0 --- /dev/null +++ b/src/test/run-pass/associated-const-cross-crate-defaults.rs @@ -0,0 +1,30 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:associated-const-cc-lib.rs + +extern crate associated_const_cc_lib as foolib; + +pub struct LocalFooUseDefault; + +impl foolib::FooDefault for LocalFooUseDefault {} + +pub struct LocalFooOverwriteDefault; + +impl foolib::FooDefault for LocalFooOverwriteDefault { + const BAR: usize = 4; +} + +fn main() { + assert_eq!(1, ::BAR); + assert_eq!(2, ::BAR); + assert_eq!(1, ::BAR); + assert_eq!(4, ::BAR); +} diff --git a/src/test/run-pass/associated-const-cross-crate.rs b/src/test/run-pass/associated-const-cross-crate.rs new file mode 100644 index 0000000000000..c18cda018d87a --- /dev/null +++ b/src/test/run-pass/associated-const-cross-crate.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:associated-const-cc-lib.rs + +extern crate associated_const_cc_lib as foolib; + +pub struct LocalFoo; + +impl foolib::Foo for LocalFoo { + const BAR: usize = 1; +} + +fn main() { + assert_eq!(0, ::BAR); + assert_eq!(1, ::BAR); + assert_eq!(3, foolib::InherentBar::BAR); +} diff --git a/src/test/run-pass/associated-const-in-global-const.rs b/src/test/run-pass/associated-const-in-global-const.rs new file mode 100644 index 0000000000000..b9fb067d4fa87 --- /dev/null +++ b/src/test/run-pass/associated-const-in-global-const.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Foo; + +impl Foo { + const BAR: f32 = 1.5; +} + +const FOOBAR: f32 = ::BAR; + +fn main() { + assert_eq!(1.5f32, FOOBAR); +} From 7f7888754745696467d6ba8f93ce2b9e50c10b3b Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Sun, 22 Mar 2015 04:38:42 -0600 Subject: [PATCH 4/8] Add previously omitted associated const tests. --- ...rs => associated-const-impl-wrong-type.rs} | 17 +++++--- .../associated-const-upper-case-lint.rs | 21 +++++++++ .../compile-fail/impl-wrong-item-for-trait.rs | 43 +++++++++++++++++++ .../associated-const-marks-live-code.rs | 23 ++++++++++ .../associated-const-resolution-order.rs | 35 +++++++++++++++ ...associated-const-use-impl-of-same-trait.rs | 35 +++++++++++++++ 6 files changed, 167 insertions(+), 7 deletions(-) rename src/test/compile-fail/{impl-type-where-trait-has-method.rs => associated-const-impl-wrong-type.rs} (67%) create mode 100644 src/test/compile-fail/associated-const-upper-case-lint.rs create mode 100644 src/test/compile-fail/impl-wrong-item-for-trait.rs create mode 100644 src/test/run-pass/associated-const-marks-live-code.rs create mode 100644 src/test/run-pass/associated-const-resolution-order.rs create mode 100644 src/test/run-pass/associated-const-use-impl-of-same-trait.rs diff --git a/src/test/compile-fail/impl-type-where-trait-has-method.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs similarity index 67% rename from src/test/compile-fail/impl-type-where-trait-has-method.rs rename to src/test/compile-fail/associated-const-impl-wrong-type.rs index eb75b82424d71..a7b2abc99e5f9 100644 --- a/src/test/compile-fail/impl-type-where-trait-has-method.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -8,14 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait Foo { - fn bar(&self); +use std::marker::MarkerTrait; + +trait Foo: MarkerTrait { + const BAR: u32; } -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` +struct SignedBar; + +impl Foo for SignedBar { + const BAR: i32 = -1; + //~^ ERROR E0326 } -fn main () {} +fn main() {} diff --git a/src/test/compile-fail/associated-const-upper-case-lint.rs b/src/test/compile-fail/associated-const-upper-case-lint.rs new file mode 100644 index 0000000000000..497ff426b2fae --- /dev/null +++ b/src/test/compile-fail/associated-const-upper-case-lint.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(non_upper_case_globals)] +#![allow(dead_code)] + +struct Foo; + +impl Foo { + const not_upper: bool = true; +} +//~^^ ERROR associated constant `not_upper` should have an upper case name such as `NOT_UPPER` + +fn main() {} diff --git a/src/test/compile-fail/impl-wrong-item-for-trait.rs b/src/test/compile-fail/impl-wrong-item-for-trait.rs new file mode 100644 index 0000000000000..3757005b91fdd --- /dev/null +++ b/src/test/compile-fail/impl-wrong-item-for-trait.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn bar(&self); + const MY_CONST: u32; +} + +pub struct FooConstForMethod; + +impl Foo for FooConstForMethod { + //~^ ERROR E0046 + const bar: u64 = 1; + //~^ ERROR E0323 + const MY_CONST: u32 = 1; +} + +pub struct FooMethodForConst; + +impl Foo for FooMethodForConst { + //~^ ERROR E0046 + fn bar(&self) {} + fn MY_CONST() {} + //~^ ERROR E0324 +} + +pub struct FooTypeForMethod; + +impl Foo for FooTypeForMethod { + //~^ ERROR E0046 + type bar = u64; + //~^ ERROR E0325 + const MY_CONST: u32 = 1; +} + +fn main () {} diff --git a/src/test/run-pass/associated-const-marks-live-code.rs b/src/test/run-pass/associated-const-marks-live-code.rs new file mode 100644 index 0000000000000..ba47649df64dd --- /dev/null +++ b/src/test/run-pass/associated-const-marks-live-code.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(dead_code)] + +const GLOBAL_BAR: u32 = 1; + +struct Foo; + +impl Foo { + const BAR: u32 = GLOBAL_BAR; +} + +fn main() { + let _: u32 = Foo::BAR; +} diff --git a/src/test/run-pass/associated-const-resolution-order.rs b/src/test/run-pass/associated-const-resolution-order.rs new file mode 100644 index 0000000000000..e42dd25022b61 --- /dev/null +++ b/src/test/run-pass/associated-const-resolution-order.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::MarkerTrait; + +struct MyType; + +impl MyType { + const IMPL_IS_INHERENT: bool = true; +} + +trait MyTrait: MarkerTrait { + const IMPL_IS_INHERENT: bool; + const IMPL_IS_ON_TRAIT: bool; +} + +impl MyTrait for MyType { + const IMPL_IS_INHERENT: bool = false; + const IMPL_IS_ON_TRAIT: bool = true; +} + +fn main() { + // Check that the inherent impl is used before the trait, but that the trait + // can still be accessed. + assert!(::IMPL_IS_INHERENT); + assert!(!::IMPL_IS_INHERENT); + assert!(::IMPL_IS_ON_TRAIT); +} diff --git a/src/test/run-pass/associated-const-use-impl-of-same-trait.rs b/src/test/run-pass/associated-const-use-impl-of-same-trait.rs new file mode 100644 index 0000000000000..2f95d4275c561 --- /dev/null +++ b/src/test/run-pass/associated-const-use-impl-of-same-trait.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::MarkerTrait; + +// The main purpose of this test is to ensure that different impls of the same +// trait can refer to each other without setting off the static recursion check +// (as long as there's no actual recursion). + +trait Foo: MarkerTrait { + const BAR: u32; +} + +struct IsFoo1; + +impl Foo for IsFoo1 { + const BAR: u32 = 1; +} + +struct IsFoo2; + +impl Foo for IsFoo2 { + const BAR: u32 = ::BAR; +} + +fn main() { + assert_eq!(::BAR, ::BAR); +} From 91ae5e31ab57de15ef2855c700ad4b012ea00234 Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Sun, 22 Mar 2015 19:24:56 -0600 Subject: [PATCH 5/8] Fix dead code check for associated const impls. --- src/librustc/middle/dead.rs | 54 +++++++++++-------- .../associated-const-dead-code.rs | 22 ++++++++ .../associated-const-marks-live-code.rs | 2 +- 3 files changed, 55 insertions(+), 23 deletions(-) create mode 100644 src/test/compile-fail/associated-const-dead-code.rs diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index fc40febdbf82e..1aa2ca9115d2f 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -346,6 +346,7 @@ impl<'v> Visitor<'v> for LifeSeeder { ast::ItemTrait(_, _, _, ref trait_items) => { for trait_item in trait_items { match trait_item.node { + ast::ConstTraitItem(_, Some(_)) | ast::MethodTraitItem(_, Some(_)) => { if has_allow_dead_code_or_lang_attr(&trait_item.attrs) { self.worklist.push(trait_item.id); @@ -358,7 +359,7 @@ impl<'v> Visitor<'v> for LifeSeeder { ast::ItemImpl(_, _, _, ref opt_trait, _, ref impl_items) => { for impl_item in impl_items { match impl_item.node { - ast::ConstImplItem(..) => {} + ast::ConstImplItem(..) | ast::MethodImplItem(..) => { if opt_trait.is_some() || has_allow_dead_code_or_lang_attr(&impl_item.attrs) { @@ -400,7 +401,7 @@ fn create_and_seed_worklist(tcx: &ty::ctxt, None => () } - // Seed implemented trait methods + // Seed implemented trait items let mut life_seeder = LifeSeeder { worklist: worklist }; @@ -481,7 +482,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { |ctor| self.live_symbols.contains(&ctor)) { return true; } - // If it's a type whose methods are live, then it's live, too. + // If it's a type whose items are live, then it's live, too. // This is done to handle the case where, for example, the static // method of a private type is used, but the type itself is never // called directly. @@ -551,21 +552,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { visit::walk_foreign_item(self, fi); } - fn visit_fn(&mut self, fk: visit::FnKind<'v>, - _: &'v ast::FnDecl, block: &'v ast::Block, - span: codemap::Span, id: ast::NodeId) { - // Have to warn method here because methods are not ast::Item - match fk { - visit::FkMethod(name, _, _) => { - if !self.symbol_is_live(id, None) { - self.warn_dead_code(id, span, name.name, "method"); - } - } - _ => () - } - visit::walk_block(self, block); - } - fn visit_struct_field(&mut self, field: &ast::StructField) { if self.should_warn_about_field(&field.node) { self.warn_dead_code(field.node.id, field.span, @@ -575,13 +561,37 @@ impl<'a, 'tcx, 'v> Visitor<'v> for DeadVisitor<'a, 'tcx> { visit::walk_struct_field(self, field); } - // Overwrite so that we don't warn the trait method itself. - fn visit_trait_item(&mut self, trait_method: &ast::TraitItem) { - match trait_method.node { - ast::ConstTraitItem(_, _) => {} + fn visit_impl_item(&mut self, impl_item: &ast::ImplItem) { + match impl_item.node { + ast::ConstImplItem(_, ref expr) => { + if !self.symbol_is_live(impl_item.id, None) { + self.warn_dead_code(impl_item.id, impl_item.span, + impl_item.ident.name, "associated const"); + } + visit::walk_expr(self, expr) + } + ast::MethodImplItem(_, ref body) => { + if !self.symbol_is_live(impl_item.id, None) { + self.warn_dead_code(impl_item.id, impl_item.span, + impl_item.ident.name, "method"); + } + visit::walk_block(self, body) + } + ast::TypeImplItem(..) | + ast::MacImplItem(..) => {} + } + } + + // Overwrite so that we don't warn the trait item itself. + fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) { + match trait_item.node { + ast::ConstTraitItem(_, Some(ref expr)) => { + visit::walk_expr(self, expr) + } ast::MethodTraitItem(_, Some(ref body)) => { visit::walk_block(self, body) } + ast::ConstTraitItem(_, None) | ast::MethodTraitItem(_, None) | ast::TypeTraitItem(..) => {} } diff --git a/src/test/compile-fail/associated-const-dead-code.rs b/src/test/compile-fail/associated-const-dead-code.rs new file mode 100644 index 0000000000000..42db13f4f3bd4 --- /dev/null +++ b/src/test/compile-fail/associated-const-dead-code.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![deny(dead_code)] + +struct MyFoo; + +impl MyFoo { + const BAR: u32 = 1; + //~^ ERROR associated const is never used: `BAR` +} + +fn main() { + let _: MyFoo = MyFoo; +} diff --git a/src/test/run-pass/associated-const-marks-live-code.rs b/src/test/run-pass/associated-const-marks-live-code.rs index ba47649df64dd..e86ff0199a12d 100644 --- a/src/test/run-pass/associated-const-marks-live-code.rs +++ b/src/test/run-pass/associated-const-marks-live-code.rs @@ -18,6 +18,6 @@ impl Foo { const BAR: u32 = GLOBAL_BAR; } -fn main() { +pub fn main() { let _: u32 = Foo::BAR; } From 29eb550ee6a9fd6961bb00e2680a5735aab95de1 Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Wed, 25 Mar 2015 10:53:28 -0600 Subject: [PATCH 6/8] Get associated consts working in match patterns. --- src/librustc/middle/cfg/construct.rs | 1 + src/librustc/middle/check_match.rs | 10 +- src/librustc/middle/expr_use_visitor.rs | 3 +- src/librustc/middle/mem_categorization.rs | 4 + src/librustc/middle/pat_util.rs | 20 +- src/librustc_lint/builtin.rs | 1 - src/librustc_resolve/lib.rs | 225 ++++++++++++------ src/librustc_trans/save/mod.rs | 3 +- src/librustc_trans/trans/_match.rs | 3 +- src/librustc_trans/trans/debuginfo.rs | 4 + src/librustc_typeck/check/_match.rs | 87 ++++++- src/librustc_typeck/check/mod.rs | 89 ++++--- src/librustc_typeck/diagnostics.rs | 1 + src/librustdoc/clean/mod.rs | 2 + src/libsyntax/ast.rs | 6 + src/libsyntax/ast_util.rs | 2 +- src/libsyntax/fold.rs | 4 + src/libsyntax/parse/parser.rs | 189 +++++++++------ src/libsyntax/print/pprust.rs | 3 + src/libsyntax/visit.rs | 4 + .../compile-fail/method-path-in-pattern.rs | 35 +++ .../method-resolvable-path-in-pattern.rs | 26 ++ .../brace-after-qualified-path-in-match.rs | 17 ++ .../paren-after-qualified-path-in-match.rs | 17 ++ .../associated-const-match-patterns.rs | 52 ++++ 25 files changed, 610 insertions(+), 198 deletions(-) create mode 100644 src/test/compile-fail/method-path-in-pattern.rs create mode 100644 src/test/compile-fail/method-resolvable-path-in-pattern.rs create mode 100644 src/test/parse-fail/brace-after-qualified-path-in-match.rs create mode 100644 src/test/parse-fail/paren-after-qualified-path-in-match.rs create mode 100644 src/test/run-pass/associated-const-match-patterns.rs diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 359a1a486c9da..a7950a701f8c4 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -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(_) => { diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 13be6d0cb7d9b..a5ea3629abc84 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -439,7 +439,7 @@ impl<'map> ast_util::IdVisitingOperation for RenamingRecorder<'map> { impl<'a, 'tcx> Folder for StaticInliner<'a, 'tcx> { fn fold_pat(&mut self, pat: P) -> P { return match pat.node { - ast::PatIdent(..) | ast::PatEnum(..) => { + ast::PatIdent(..) | ast::PatEnum(..) | ast::PatQPath(..) => { let def = self.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()); match def { Some(DefAssociatedConst(did, _)) | @@ -762,6 +762,9 @@ fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat, Some(DefVariant(_, id, _)) => vec!(Variant(id)), _ => vec!(Single) }, + ast::PatQPath(..) => + cx.tcx.sess.span_bug(pat.span, "const pattern should've \ + been rewritten"), ast::PatStruct(..) => match cx.tcx.def_map.borrow().get(&pat.id).map(|d| d.full_def()) { Some(DefConst(..)) | Some(DefAssociatedConst(..)) => @@ -891,6 +894,11 @@ pub fn specialize<'a>(cx: &MatchCheckCtxt, r: &[&'a Pat], } } + ast::PatQPath(_, _) => { + cx.tcx.sess.span_bug(pat_span, "const pattern should've \ + been rewritten") + } + ast::PatStruct(_, ref pattern_fields, _) => { // Is this a struct or an enum variant? let def = cx.tcx.def_map.borrow().get(&pat_id).unwrap().full_def(); diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 87379bd48f0c4..d740d24e23672 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -1147,7 +1147,8 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> { let tcx = typer.tcx(); match pat.node { - ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => { + ast::PatEnum(_, _) | ast::PatQPath(..) | + ast::PatIdent(_, _, None) | ast::PatStruct(..) => { match def_map.get(&pat.id).map(|d| d.full_def()) { None => { // no definition found: pat is not a diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 6db55baf48350..587194bafada4 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1299,6 +1299,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> { } } + ast::PatQPath(..) => { + // Lone constant: ignore + } + ast::PatIdent(_, _, Some(ref subpat)) => { try!(self.cat_pattern_(cmt, &**subpat, op)); } diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 7a0f58947fe70..27a30f5cf253c 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -30,7 +30,7 @@ pub fn pat_id_map(dm: &DefMap, pat: &ast::Pat) -> PatIdMap { pub fn pat_is_refutable(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { - ast::PatLit(_) | ast::PatRange(_, _) => true, + ast::PatLit(_) | ast::PatRange(_, _) | ast::PatQPath(..) => true, ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => { @@ -60,7 +60,7 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &ast::Pat) -> bool { pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { - ast::PatIdent(_, _, None) | ast::PatEnum(..) => { + ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => { match dm.borrow().get(&pat.id).map(|d| d.full_def()) { Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true, _ => false @@ -70,6 +70,22 @@ pub fn pat_is_const(dm: &DefMap, pat: &ast::Pat) -> bool { } } +// Same as above, except that partially-resolved defs cause `false` to be +// returned instead of a panic. +pub fn pat_is_resolved_const(dm: &DefMap, pat: &ast::Pat) -> bool { + match pat.node { + ast::PatIdent(_, _, None) | ast::PatEnum(..) | ast::PatQPath(..) => { + match dm.borrow().get(&pat.id) + .and_then(|d| if d.depth == 0 { Some(d.base_def) } + else { None } ) { + Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true, + _ => false + } + } + _ => false + } +} + pub fn pat_is_binding(dm: &DefMap, pat: &ast::Pat) -> bool { match pat.node { ast::PatIdent(..) => { diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 902e9ffca1f64..1d5c5fb86cbd5 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1091,7 +1091,6 @@ impl LintPass for NonUpperCaseGlobals { 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); diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 41a6f4adfe038..61eab4ce9b285 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -41,6 +41,7 @@ use self::TypeParameters::*; use self::RibKind::*; use self::UseLexicalScopeFlag::*; use self::ModulePrefixResult::*; +use self::AssocItemResolveResult::*; use self::NameSearchType::*; use self::BareIdentifierPatternResolution::*; use self::ParentLink::*; @@ -70,7 +71,7 @@ use syntax::ast::{Ident, ImplItem, Item, ItemConst, ItemEnum, ItemExternCrate}; use syntax::ast::{ItemFn, ItemForeignMod, ItemImpl, ItemMac, ItemMod, ItemStatic, ItemDefaultImpl}; use syntax::ast::{ItemStruct, ItemTrait, ItemTy, ItemUse}; use syntax::ast::{Local, MethodImplItem, Name, NodeId}; -use syntax::ast::{Pat, PatEnum, PatIdent, PatLit}; +use syntax::ast::{Pat, PatEnum, PatIdent, PatLit, PatQPath}; use syntax::ast::{PatRange, PatStruct, Path, PrimTy}; use syntax::ast::{TraitRef, Ty, TyBool, TyChar, TyF32}; use syntax::ast::{TyF64, TyFloat, TyIs, TyI8, TyI16, TyI32, TyI64, TyInt}; @@ -331,6 +332,15 @@ enum ModulePrefixResult { PrefixFound(Rc, usize) } +#[derive(Copy, Clone)] +enum AssocItemResolveResult { + /// Syntax such as `::item`, which can't be resolved until type + /// checking. + TypecheckRequired, + /// We should have been able to resolve the associated item. + ResolveAttempt(Option), +} + #[derive(Copy, Clone, PartialEq)] enum NameSearchType { /// We're doing a name search in order to resolve a `use` directive. @@ -2305,31 +2315,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_type(&mut self, ty: &Ty) { match ty.node { - // `::a::b::c` is resolved by typeck alone. - TyPath(Some(ast::QSelf { position: 0, .. }), _) => {} - TyPath(ref maybe_qself, ref path) => { - let max_assoc_types = if let Some(ref qself) = *maybe_qself { - // Make sure the trait is valid. - let _ = self.resolve_trait_reference(ty.id, path, 1); - path.segments.len() - qself.position - } else { - path.segments.len() - }; - - let mut resolution = None; - for depth in 0..max_assoc_types { - self.with_no_errors(|this| { - resolution = this.resolve_path(ty.id, path, depth, TypeNS, true); - }); - if resolution.is_some() { - break; - } - } - if let Some(DefMod(_)) = resolution.map(|r| r.base_def) { - // A module is not a valid type. - resolution = None; - } + let resolution = + match self.resolve_possibly_assoc_item(ty.id, + maybe_qself.as_ref(), + path, + TypeNS, + true) { + // `::a::b::c` is resolved by typeck alone. + TypecheckRequired => { + // Resolve embedded types. + visit::walk_ty(self, ty); + return; + } + ResolveAttempt(resolution) => resolution, + }; // This is a path in the type namespace. Walk through scopes // looking for it. @@ -2489,10 +2489,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { PatEnum(ref path, _) => { // This must be an enum variant, struct or const. - if let Some(path_res) = self.resolve_path(pat_id, path, 0, ValueNS, false) { + let resolution = + match self.resolve_possibly_assoc_item(pat_id, None, + path, ValueNS, + false) { + // The below shouldn't happen because all + // qualified paths should be in PatQPath. + TypecheckRequired => + self.session.span_bug( + path.span, + "resolve_possibly_assoc_item claimed + that a path in PatEnum requires typecheck + to resolve, but qualified paths should be + PatQPath"), + ResolveAttempt(resolution) => resolution, + }; + if let Some(path_res) = resolution { match path_res.base_def { - DefVariant(..) | DefStruct(..) | DefConst(..) | - DefAssociatedConst(..) => { + DefVariant(..) | DefStruct(..) | DefConst(..) => { self.record_def(pattern.id, path_res); } DefStatic(..) => { @@ -2501,19 +2515,70 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { referenced in a pattern, \ use a `const` instead"); } + _ => { + // If anything ends up here entirely resolved, + // it's an error. If anything ends up here + // partially resolved, that's OK, because it may + // be a `T::CONST` that typeck will resolve to + // an inherent impl. + if path_res.depth == 0 { + self.resolve_error( + path.span, + &format!("`{}` is not an enum variant, struct or const", + token::get_ident( + path.segments.last().unwrap().identifier))); + } else { + self.record_def(pattern.id, path_res); + } + } + } + } else { + self.resolve_error(path.span, + &format!("unresolved enum variant, struct or const `{}`", + token::get_ident(path.segments.last().unwrap().identifier))); + } + visit::walk_path(self, path); + } + + PatQPath(ref qself, ref path) => { + // Associated constants only. + let resolution = + match self.resolve_possibly_assoc_item(pat_id, Some(qself), + path, ValueNS, + false) { + TypecheckRequired => { + // All `::CONST` should end up here, and will + // require use of the trait map to resolve + // during typechecking. + let const_name = path.segments.last().unwrap() + .identifier.name; + let traits = self.get_traits_containing_item(const_name); + self.trait_map.insert(pattern.id, traits); + visit::walk_pat(self, pattern); + return true; + } + ResolveAttempt(resolution) => resolution, + }; + if let Some(path_res) = resolution { + match path_res.base_def { + // All `::CONST` should end up here, and + // have the trait already selected. + DefAssociatedConst(..) => { + self.record_def(pattern.id, path_res); + } _ => { self.resolve_error(path.span, - &format!("`{}` is not an enum variant, struct or const", + &format!("`{}` is not an associated const", token::get_ident( path.segments.last().unwrap().identifier))); } } } else { self.resolve_error(path.span, - &format!("unresolved enum variant, struct or const `{}`", + &format!("unresolved associated const `{}`", token::get_ident(path.segments.last().unwrap().identifier))); } - visit::walk_path(self, path); + visit::walk_pat(self, pattern); } PatStruct(ref path, _, _) => { @@ -2605,6 +2670,47 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } + /// Handles paths that may refer to associated items + fn resolve_possibly_assoc_item(&mut self, + id: NodeId, + maybe_qself: Option<&ast::QSelf>, + path: &Path, + namespace: Namespace, + check_ribs: bool) + -> AssocItemResolveResult + { + match maybe_qself { + Some(&ast::QSelf { position: 0, .. }) => + return TypecheckRequired, + _ => {} + } + let max_assoc_types = if let Some(qself) = maybe_qself { + // Make sure the trait is valid. + let _ = self.resolve_trait_reference(id, path, 1); + path.segments.len() - qself.position + } else { + path.segments.len() + }; + + let mut resolution = self.with_no_errors(|this| { + this.resolve_path(id, path, 0, namespace, check_ribs) + }); + for depth in 1..max_assoc_types { + if resolution.is_some() { + break; + } + self.with_no_errors(|this| { + resolution = this.resolve_path(id, path, depth, + TypeNS, true); + }); + } + if let Some(DefMod(_)) = resolution.map(|r| r.base_def) { + // A module is not a valid type or value. + resolution = None; + } + ResolveAttempt(resolution) + } + /// If `check_ribs` is true, checks the local definitions first; i.e. /// doesn't skip straight to the containing module. /// Skips `path_depth` trailing segments, which is also reflected in the @@ -3119,38 +3225,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Next, resolve the node. match expr.node { - // `::a::b::c` is resolved by typeck alone. - ExprPath(Some(ast::QSelf { position: 0, .. }), ref path) => { - let method_name = path.segments.last().unwrap().identifier.name; - let traits = self.search_for_traits_containing_method(method_name); - self.trait_map.insert(expr.id, traits); - visit::walk_expr(self, expr); - } - ExprPath(ref maybe_qself, ref path) => { - let max_assoc_types = if let Some(ref qself) = *maybe_qself { - // Make sure the trait is valid. - let _ = self.resolve_trait_reference(expr.id, path, 1); - path.segments.len() - qself.position - } else { - path.segments.len() - }; - - let mut resolution = self.with_no_errors(|this| { - this.resolve_path(expr.id, path, 0, ValueNS, true) - }); - for depth in 1..max_assoc_types { - if resolution.is_some() { - break; - } - self.with_no_errors(|this| { - resolution = this.resolve_path(expr.id, path, depth, TypeNS, true); - }); - } - if let Some(DefMod(_)) = resolution.map(|r| r.base_def) { - // A module is not a valid type or value. - resolution = None; - } + let resolution = + match self.resolve_possibly_assoc_item(expr.id, + maybe_qself.as_ref(), + path, + ValueNS, + true) { + // `::a::b::c` is resolved by typeck alone. + TypecheckRequired => { + let method_name = path.segments.last().unwrap().identifier.name; + let traits = self.get_traits_containing_item(method_name); + self.trait_map.insert(expr.id, traits); + visit::walk_expr(self, expr); + return; + } + ResolveAttempt(resolution) => resolution, + }; // This is a local path in the value namespace. Walk through // scopes looking for it. @@ -3181,7 +3272,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // so they can be completed during typeck. if path_res.depth != 0 { let method_name = path.segments.last().unwrap().identifier.name; - let traits = self.search_for_traits_containing_method(method_name); + let traits = self.get_traits_containing_item(method_name); self.trait_map.insert(expr.id, traits); } @@ -3339,14 +3430,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // field, we need to add any trait methods we find that match // the field name so that we can do some nice error reporting // later on in typeck. - let traits = self.search_for_traits_containing_method(ident.node.name); + let traits = self.get_traits_containing_item(ident.node.name); self.trait_map.insert(expr.id, traits); } ExprMethodCall(ident, _, _) => { debug!("(recording candidate traits for expr) recording \ traits for {}", expr.id); - let traits = self.search_for_traits_containing_method(ident.node.name); + let traits = self.get_traits_containing_item(ident.node.name); self.trait_map.insert(expr.id, traits); } _ => { @@ -3355,8 +3446,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - fn search_for_traits_containing_method(&mut self, name: Name) -> Vec { - debug!("(searching for traits containing method) looking for '{}'", + fn get_traits_containing_item(&mut self, name: Name) -> Vec { + debug!("(getting traits containing item) looking for '{}'", token::get_name(name)); fn add_trait_info(found_traits: &mut Vec, diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index dc14ef3696f5f..39cfac42011ab 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -1044,7 +1044,8 @@ impl <'l, 'tcx> DxrVisitor<'l, 'tcx> { } } } - ast::PatEnum(ref path, _) => { + ast::PatEnum(ref path, _) | + ast::PatQPath(_, ref path) => { self.collected_paths.push((p.id, path.clone(), false, recorder::VarRef)); visit::walk_pat(self, p); } diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 744ec5a616841..b93068c88c8be 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -1809,7 +1809,8 @@ fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ast::PatMac(..) => { bcx.sess().span_bug(pat.span, "unexpanded macro"); } - ast::PatWild(_) | ast::PatLit(_) | ast::PatRange(_, _) => () + ast::PatQPath(..) | ast::PatWild(_) | ast::PatLit(_) | + ast::PatRange(_, _) => () } return bcx; } diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 69cd57d1bab70..516ff443dacb9 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -3437,6 +3437,10 @@ fn create_scope_map(cx: &CrateContext, } } + ast::PatQPath(..) => { + scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); + } + ast::PatStruct(_, ref field_pats, _) => { scope_map.insert(pat.id, scope_stack.last().unwrap().scope_metadata); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 0959f9d1b9154..1f4d6cc2fd471 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -11,12 +11,14 @@ use middle::const_eval; use middle::def; use middle::infer; -use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding, pat_is_const}; +use middle::pat_util::{PatIdMap, pat_id_map, pat_is_binding}; +use middle::pat_util::pat_is_resolved_const; +use middle::privacy::{AllPublic, LastMod}; use middle::subst::Substs; use middle::ty::{self, Ty}; use check::{check_expr, check_expr_has_type, check_expr_with_expectation}; use check::{check_expr_coercable_to_type, demand, FnCtxt, Expectation}; -use check::{instantiate_path, structurally_resolved_type}; +use check::{instantiate_path, resolve_ty_and_def_ufcs, structurally_resolved_type}; use require_same_types; use util::nodemap::FnvHashMap; use util::ppaux::Repr; @@ -118,7 +120,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // subtyping doesn't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); } - ast::PatEnum(..) | ast::PatIdent(..) if pat_is_const(&tcx.def_map, pat) => { + ast::PatEnum(..) | ast::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => { let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id(); let const_scheme = ty::lookup_item_type(tcx, const_did); assert!(const_scheme.generics.is_empty()); @@ -181,6 +183,37 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let subpats = subpats.as_ref().map(|v| &v[..]); check_pat_enum(pcx, pat, path, subpats, expected); } + ast::PatQPath(ref qself, ref path) => { + let self_ty = fcx.to_ty(&qself.ty); + let path_res = if let Some(&d) = tcx.def_map.borrow().get(&pat.id) { + d + } else if qself.position == 0 { + def::PathResolution { + // This is just a sentinel for finish_resolving_def_to_ty. + base_def: def::DefMod(ast_util::local_def(ast::CRATE_NODE_ID)), + last_private: LastMod(AllPublic), + depth: path.segments.len() + } + } else { + tcx.sess.span_bug(pat.span, + &format!("unbound path {}", pat.repr(tcx))) + }; + if let Some((opt_ty, segments, def)) = + resolve_ty_and_def_ufcs(fcx, path_res, Some(self_ty), + path, pat.span, pat.id) { + if check_assoc_item_is_const(pcx, def, pat.span) { + let scheme = ty::lookup_item_type(tcx, def.def_id()); + let predicates = ty::lookup_predicates(tcx, def.def_id()); + instantiate_path(fcx, segments, + scheme, &predicates, + opt_ty, def, pat.span, pat.id); + let const_ty = fcx.node_ty(pat.id); + demand::suptype(fcx, pat.span, expected, const_ty); + } else { + fcx.write_error(pat.id) + } + } + } ast::PatStruct(ref path, ref fields, etc) => { check_pat_struct(pcx, pat, path, fields, etc, expected); } @@ -331,6 +364,21 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // subtyping. } +fn check_assoc_item_is_const(pcx: &pat_ctxt, def: def::Def, span: Span) -> bool { + match def { + def::DefAssociatedConst(..) => true, + def::DefMethod(..) => { + span_err!(pcx.fcx.ccx.tcx.sess, span, E0327, + "associated items in match patterns must be constants"); + false + } + _ => { + pcx.fcx.ccx.tcx.sess.span_bug(span, "non-associated item in + check_assoc_item_is_const"); + } + } +} + pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, span: Span, expected: Ty<'tcx>, inner: &ast::Pat) -> bool { @@ -532,7 +580,24 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - let def = tcx.def_map.borrow().get(&pat.id).unwrap().full_def(); + let path_res = *tcx.def_map.borrow().get(&pat.id).unwrap(); + + let (opt_ty, segments, def) = match resolve_ty_and_def_ufcs(fcx, path_res, + None, path, + pat.span, pat.id) { + Some(resolution) => resolution, + // Error handling done inside resolve_ty_and_def_ufcs, so if + // resolution fails just return. + None => {return;} + }; + + // Items that were partially resolved before should have been resolved to + // associated constants (i.e. not methods). + if path_res.depth != 0 && !check_assoc_item_is_const(pcx, def, pat.span) { + fcx.write_error(pat.id); + return; + } + let enum_def = def.variant_def_ids() .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def); @@ -547,13 +612,23 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, } else { ctor_scheme }; - instantiate_path(pcx.fcx, &path.segments, + instantiate_path(pcx.fcx, segments, path_scheme, &ctor_predicates, - None, def, pat.span, pat.id); + opt_ty, def, pat.span, pat.id); + + // If we didn't have a fully resolved path to start with, we had an + // associated const, and we should quit now, since the rest of this + // function uses checks specific to structs and enums. + if path_res.depth != 0 { + let pat_ty = fcx.node_ty(pat.id); + demand::suptype(fcx, pat.span, expected, pat_ty); + return; + } let pat_ty = fcx.node_ty(pat.id); demand::eqtype(fcx, pat.span, expected, pat_ty); + let real_path_ty = fcx.node_ty(pat.id); let (arg_tys, kind_name): (Vec<_>, &'static str) = match real_path_ty.sty { ty::ty_enum(enum_def_id, expected_substs) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d04205666f2ea..6ba341f62f58e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3230,53 +3230,20 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, &format!("unbound path {}", expr.repr(tcx))) }; - let def = path_res.base_def; - if path_res.depth == 0 { + if let Some((opt_ty, segments, def)) = + resolve_ty_and_def_ufcs(fcx, path_res, opt_self_ty, path, + expr.span, expr.id) { let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, def); instantiate_path(fcx, - &path.segments, + segments, scheme, &predicates, - opt_self_ty, + opt_ty, def, expr.span, id); - } else { - let ty_segments = path.segments.init(); - let base_ty_end = path.segments.len() - path_res.depth; - let ty = astconv::finish_resolving_def_to_ty(fcx, - fcx, - expr.span, - PathParamMode::Optional, - &def, - opt_self_ty, - &ty_segments[..base_ty_end], - &ty_segments[base_ty_end..]); - let method_segment = path.segments.last().unwrap(); - let method_name = method_segment.identifier.name; - match method::resolve_ufcs(fcx, expr.span, method_name, ty, id) { - Ok((def, lp)) => { - // Write back the new resolution. - tcx.def_map.borrow_mut().insert(id, def::PathResolution { - base_def: def, - last_private: path_res.last_private.or(lp), - depth: 0 - }); - - let (scheme, predicates) = - type_scheme_and_predicates_for_def(fcx, expr.span, def); - instantiate_path(fcx, slice::ref_slice(method_segment), - scheme, &predicates, - Some(ty), def, expr.span, id); - } - Err(error) => { - method::report_error(fcx, expr.span, ty, - method_name, None, error); - fcx.write_error(id); - } - } } // We always require that the type provided as the value for @@ -3738,6 +3705,52 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, unifier(); } +pub fn resolve_ty_and_def_ufcs<'a, 'b, 'tcx>(fcx: &FnCtxt<'b, 'tcx>, + path_res: def::PathResolution, + opt_self_ty: Option>, + path: &'a ast::Path, + span: Span, + node_id: ast::NodeId) + -> Option<(Option>, + &'a [ast::PathSegment], + def::Def)> +{ + // If fully resolved already, we don't have to do anything. + if path_res.depth == 0 { + Some((opt_self_ty, &path.segments, path_res.base_def)) + } else { + let mut def = path_res.base_def; + let ty_segments = path.segments.init(); + let base_ty_end = path.segments.len() - path_res.depth; + let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, span, + PathParamMode::Optional, + &mut def, + opt_self_ty, + &ty_segments[..base_ty_end], + &ty_segments[base_ty_end..]); + let item_segment = path.segments.last().unwrap(); + let item_name = item_segment.identifier.name; + match method::resolve_ufcs(fcx, span, item_name, ty, node_id) { + Ok((def, lp)) => { + // Write back the new resolution. + fcx.ccx.tcx.def_map.borrow_mut() + .insert(node_id, def::PathResolution { + base_def: def, + last_private: path_res.last_private.or(lp), + depth: 0 + }); + Some((Some(ty), slice::ref_slice(item_segment), def)) + } + Err(error) => { + method::report_error(fcx, span, ty, + item_name, None, error); + fcx.write_error(node_id); + None + } + } + } +} + fn constrain_path_type_parameters(fcx: &FnCtxt, expr: &ast::Expr) { diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index a4814b36fe5b1..46cc4628e2eeb 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -180,6 +180,7 @@ register_diagnostics! { 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 + E0327, // referred to method instead of constant in match pattern E0366, // dropck forbid specialization to concrete type or region E0367, // dropck forbid specialization to predicate not in struct/enum E0368, // binary operation `=` cannot be applied to types diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 73fbfe29224ee..1e6e9a7562a7c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2522,6 +2522,8 @@ fn name_from_pat(p: &ast::Pat) -> String { PatWild(PatWildMulti) => "..".to_string(), PatIdent(_, ref p, _) => token::get_ident(p.node).to_string(), PatEnum(ref p, _) => path_to_string(p), + PatQPath(..) => panic!("tried to get argument name from PatQPath, \ + which is not allowed in function arguments"), PatStruct(ref name, ref fields, etc) => { format!("{} {{ {}{} }}", path_to_string(name), fields.iter().map(|&Spanned { node: ref fp, .. }| diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 3f2e7c765a5e4..4307abe417453 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -599,6 +599,12 @@ pub enum Pat_ { /// "None" means a * pattern where we don't bind the fields to names. PatEnum(Path, Option>>), + /// An associated const named using the qualified path `::CONST` or + /// `::CONST`. Associated consts from inherent impls can be + /// refered to as simply `T::CONST`, in which case they will end up as + /// PatEnum, and the resolver will have to sort that out. + PatQPath(QSelf, Path), + /// Destructuring of a struct, e.g. `Foo {x, y, ..}` /// The `bool` is `true` in the presence of a `..` PatStruct(Path, Vec>, bool), diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 78f06ce5fd5d0..fc4d73210ea98 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -579,7 +579,7 @@ pub fn walk_pat(pat: &Pat, mut it: F) -> bool where F: FnMut(&Pat) -> bool { } PatMac(_) => panic!("attempted to analyze unexpanded pattern"), PatWild(_) | PatLit(_) | PatRange(_, _) | PatIdent(_, _, _) | - PatEnum(_, _) => { + PatEnum(_, _) | PatQPath(_, _) => { true } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 22bc3a198e231..8898dc7e3597e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1134,6 +1134,10 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { PatEnum(folder.fold_path(pth), pats.map(|pats| pats.move_map(|x| folder.fold_pat(x)))) } + PatQPath(qself, pth) => { + let qself = QSelf {ty: folder.fold_ty(qself.ty), .. qself}; + PatQPath(qself, folder.fold_path(pth)) + } PatStruct(pth, fields, etc) => { let pth = folder.fold_path(pth); let fs = fields.move_map(|f| { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 9a1c963b8eb0b..abeee2a1c7489 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -40,8 +40,9 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource}; use ast::{MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; -use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion}; -use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle}; +use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange}; +use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti}; +use ast::PatWildSingle; use ast::{PolyTraitRef, QSelf}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; @@ -109,6 +110,15 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } +/// How to parse a qualified path, whether to allow trailing parameters. +#[derive(Copy, Clone, PartialEq)] +pub enum QPathParsingMode { + /// No trailing parameters, e.g. `::Item` + NoParameters, + /// Optional parameters, e.g. `::item::<'a, U>` + MaybeParameters, +} + /// How to parse a bound, whether to allow bound modifiers such as `?`. #[derive(Copy, Clone, PartialEq)] pub enum BoundParsingMode { @@ -1345,36 +1355,9 @@ impl<'a> Parser<'a> { try!(self.expect(&token::CloseDelim(token::Paren))); TyTypeof(e) } else if try!(self.eat_lt()) { - // QUALIFIED PATH `::item` - let self_type = try!(self.parse_ty_sum()); - - let mut path = if try!(self.eat_keyword(keywords::As) ){ - try!(self.parse_path(LifetimeAndTypesWithoutColons)) - } else { - ast::Path { - span: self.span, - global: false, - segments: vec![] - } - }; - let qself = QSelf { - ty: self_type, - position: path.segments.len() - }; - - try!(self.expect(&token::Gt)); - try!(self.expect(&token::ModSep)); - - path.segments.push(ast::PathSegment { - identifier: try!(self.parse_ident()), - parameters: ast::PathParameters::none() - }); - - if path.segments.len() == 1 { - path.span.lo = self.last_span.lo; - } - path.span.hi = self.last_span.hi; + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); TyPath(Some(qself), path) } else if self.check(&token::ModSep) || @@ -1591,6 +1574,61 @@ impl<'a> Parser<'a> { } } + // QUALIFIED PATH `::IDENT[::]` + // Assumes that the leading `<` has been parsed already. + pub fn parse_qualified_path(&mut self, mode: QPathParsingMode) + -> PResult<(QSelf, ast::Path)> { + let self_type = try!(self.parse_ty_sum()); + let mut path = if try!(self.eat_keyword(keywords::As)) { + try!(self.parse_path(LifetimeAndTypesWithoutColons)) + } else { + ast::Path { + span: self.span, + global: false, + segments: vec![] + } + }; + + let qself = QSelf { + ty: self_type, + position: path.segments.len() + }; + + try!(self.expect(&token::Gt)); + try!(self.expect(&token::ModSep)); + + let item_name = try!(self.parse_ident()); + let parameters = match mode { + QPathParsingMode::NoParameters => ast::PathParameters::none(), + QPathParsingMode::MaybeParameters => { + if try!(self.eat(&token::ModSep)) { + try!(self.expect_lt()); + // Consumed `item::<`, go look for types + let (lifetimes, types, bindings) = + try!(self.parse_generic_values_after_lt()); + ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), + bindings: OwnedSlice::from_vec(bindings), + }) + } else { + ast::PathParameters::none() + } + } + }; + path.segments.push(ast::PathSegment { + identifier: item_name, + parameters: parameters + }); + + if path.segments.len() == 1 { + path.span.lo = self.last_span.lo; + } + path.span.hi = self.last_span.hi; + + Ok((qself, path)) + } + /// Parses a path and optional type parameter bounds, depending on the /// mode. The `mode` parameter determines whether lifetimes, types, and/or /// bounds are permitted and whether `::` must precede type parameter @@ -2054,49 +2092,10 @@ impl<'a> Parser<'a> { } _ => { if try!(self.eat_lt()){ - // QUALIFIED PATH `::item::<'a, T>` - let self_type = try!(self.parse_ty_sum()); - let mut path = if try!(self.eat_keyword(keywords::As) ){ - try!(self.parse_path(LifetimeAndTypesWithoutColons)) - } else { - ast::Path { - span: self.span, - global: false, - segments: vec![] - } - }; - let qself = QSelf { - ty: self_type, - position: path.segments.len() - }; - try!(self.expect(&token::Gt)); - try!(self.expect(&token::ModSep)); - - let item_name = try!(self.parse_ident()); - let parameters = if try!(self.eat(&token::ModSep) ){ - try!(self.expect_lt()); - // Consumed `item::<`, go look for types - let (lifetimes, types, bindings) = - try!(self.parse_generic_values_after_lt()); - ast::AngleBracketedParameters(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), - }) - } else { - ast::PathParameters::none() - }; - path.segments.push(ast::PathSegment { - identifier: item_name, - parameters: parameters - }); - if path.segments.len() == 1 { - path.span.lo = self.last_span.lo; - } - path.span.hi = self.last_span.hi; + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters)); - let hi = self.span.hi; return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path))); } if try!(self.eat_keyword(keywords::Move) ){ @@ -3167,16 +3166,25 @@ impl<'a> Parser<'a> { fn parse_pat_range_end(&mut self) -> PResult> { if self.is_path_start() { let lo = self.span.lo; - let path = try!(self.parse_path(LifetimeAndTypesWithColons)); + let (qself, path) = if try!(self.eat_lt()) { + // Parse a qualified path + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + (Some(qself), path) + } else { + // Parse an unqualified path + (None, try!(self.parse_path(LifetimeAndTypesWithColons))) + }; let hi = self.last_span.hi; - Ok(self.mk_expr(lo, hi, ExprPath(None, path))) + Ok(self.mk_expr(lo, hi, ExprPath(qself, path))) } else { self.parse_literal_maybe_minus() } } fn is_path_start(&self) -> bool { - (self.token == token::ModSep || self.token.is_ident() || self.token.is_path()) + (self.token == token::Lt || self.token == token::ModSep + || self.token.is_ident() || self.token.is_path()) && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False) } @@ -3252,25 +3260,44 @@ impl<'a> Parser<'a> { pat = try!(self.parse_pat_ident(BindByValue(MutImmutable))); } } else { - // Parse as a general path - let path = try!(self.parse_path(LifetimeAndTypesWithColons)); + let (qself, path) = if try!(self.eat_lt()) { + // Parse a qualified path + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + (Some(qself), path) + } else { + // Parse an unqualified path + (None, try!(self.parse_path(LifetimeAndTypesWithColons))) + }; match self.token { token::DotDotDot => { // Parse range let hi = self.last_span.hi; - let begin = self.mk_expr(lo, hi, ExprPath(None, path)); + let begin = self.mk_expr(lo, hi, ExprPath(qself, path)); try!(self.bump()); let end = try!(self.parse_pat_range_end()); pat = PatRange(begin, end); } token::OpenDelim(token::Brace) => { - // Parse struct pattern + if qself.is_some() { + let span = self.span; + self.span_err(span, + "unexpected `{` after qualified path"); + self.abort_if_errors(); + } + // Parse struct pattern try!(self.bump()); let (fields, etc) = try!(self.parse_pat_fields()); try!(self.bump()); pat = PatStruct(path, fields, etc); } token::OpenDelim(token::Paren) => { + if qself.is_some() { + let span = self.span; + self.span_err(span, + "unexpected `(` after qualified path"); + self.abort_if_errors(); + } // Parse tuple struct or enum pattern if self.look_ahead(1, |t| *t == token::DotDot) { // This is a "top constructor only" pat @@ -3287,6 +3314,10 @@ impl<'a> Parser<'a> { pat = PatEnum(path, Some(args)); } } + _ if qself.is_some() => { + // Parse qualified path + pat = PatQPath(qself.unwrap(), path); + } _ => { // Parse nullary enum pat = PatEnum(path, Some(vec![])); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4cfb9e4147a95..27682bc6fec6a 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2220,6 +2220,9 @@ impl<'a> State<'a> { } } } + ast::PatQPath(ref qself, ref path) => { + try!(self.print_qpath(path, qself, false)); + } ast::PatStruct(ref path, ref fields, etc) => { try!(self.print_path(path, true, 0)); try!(self.nbsp()); diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 2ab353676251e..6cf791b10be67 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -464,6 +464,10 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { } } } + PatQPath(ref qself, ref path) => { + visitor.visit_ty(&qself.ty); + visitor.visit_path(path, pattern.id) + } PatStruct(ref path, ref fields, _) => { visitor.visit_path(path, pattern.id); for field in fields { diff --git a/src/test/compile-fail/method-path-in-pattern.rs b/src/test/compile-fail/method-path-in-pattern.rs new file mode 100644 index 0000000000000..1d83f901cdb62 --- /dev/null +++ b/src/test/compile-fail/method-path-in-pattern.rs @@ -0,0 +1,35 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::MarkerTrait; + +struct Foo; + +impl Foo { + fn bar(&self) {} +} + +trait MyTrait: MarkerTrait { + fn trait_bar() {} +} + +impl MyTrait for Foo {} + +fn main() { + match 0u32 { + Foo::bar => {} //~ ERROR E0327 + } + match 0u32 { + ::bar => {} //~ ERROR E0327 + } + match 0u32 { + ::trait_bar => {} //~ ERROR E0327 + } +} diff --git a/src/test/compile-fail/method-resolvable-path-in-pattern.rs b/src/test/compile-fail/method-resolvable-path-in-pattern.rs new file mode 100644 index 0000000000000..f3e93537203b3 --- /dev/null +++ b/src/test/compile-fail/method-resolvable-path-in-pattern.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::MarkerTrait; + +struct Foo; + +trait MyTrait: MarkerTrait { + fn trait_bar() {} +} + +impl MyTrait for Foo {} + +fn main() { + match 0u32 { + ::trait_bar => {} + //~^ ERROR `trait_bar` is not an associated const + } +} diff --git a/src/test/parse-fail/brace-after-qualified-path-in-match.rs b/src/test/parse-fail/brace-after-qualified-path-in-match.rs new file mode 100644 index 0000000000000..66f462df05ac9 --- /dev/null +++ b/src/test/parse-fail/brace-after-qualified-path-in-match.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() { + match x { + ::Type{key: value} => (), + //~^ ERROR unexpected `{` after qualified path + _ => (), + } +} diff --git a/src/test/parse-fail/paren-after-qualified-path-in-match.rs b/src/test/parse-fail/paren-after-qualified-path-in-match.rs new file mode 100644 index 0000000000000..d06fd2bb4e704 --- /dev/null +++ b/src/test/parse-fail/paren-after-qualified-path-in-match.rs @@ -0,0 +1,17 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +fn foo() { + match x { + ::Type(2) => (), + //~^ ERROR unexpected `(` after qualified path + _ => (), + } +} diff --git a/src/test/run-pass/associated-const-match-patterns.rs b/src/test/run-pass/associated-const-match-patterns.rs new file mode 100644 index 0000000000000..0085f89822edf --- /dev/null +++ b/src/test/run-pass/associated-const-match-patterns.rs @@ -0,0 +1,52 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::MarkerTrait; + +struct Foo; + +enum Bar { + Var1, + Var2, +} + +// Use inherent and trait impls to test UFCS syntax. +impl Foo { + const MYBAR: Bar = Bar::Var2; +} + +trait HasBar: MarkerTrait { + const THEBAR: Bar; +} + +impl HasBar for Foo { + const THEBAR: Bar = Bar::Var1; +} + +fn main() { + // Inherent impl + assert!(match Bar::Var2 { + Foo::MYBAR => true, + _ => false, + }); + assert!(match Bar::Var2 { + ::MYBAR => true, + _ => false, + }); + // Trait impl + assert!(match Bar::Var1 { + ::THEBAR => true, + _ => false, + }); + assert!(match Bar::Var1 { + ::THEBAR => true, + _ => false, + }); +} From b1db4ec3d0a96a1e83d74fbc7f99dc3be054f4d8 Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Thu, 26 Mar 2015 13:06:26 -0600 Subject: [PATCH 7/8] Feature-gate associated constants. --- src/doc/reference.md | 5 +++- src/libsyntax/feature_gate.rs | 28 +++++++++++++++++++ src/test/auxiliary/associated-const-cc-lib.rs | 2 ++ .../associated-const-dead-code.rs | 1 + .../associated-const-impl-wrong-type.rs | 2 ++ .../associated-const-private-impl.rs | 2 ++ .../associated-const-upper-case-lint.rs | 1 + .../compile-fail/gated-associated_consts.rs | 25 +++++++++++++++++ .../compile-fail/impl-wrong-item-for-trait.rs | 2 ++ .../associated-const-cross-crate-defaults.rs | 2 ++ .../run-pass/associated-const-cross-crate.rs | 2 ++ .../associated-const-in-global-const.rs | 2 ++ .../associated-const-inherent-impl.rs | 2 ++ .../associated-const-marks-live-code.rs | 2 ++ .../associated-const-match-patterns.rs | 2 ++ .../associated-const-overwrite-default.rs | 2 ++ .../run-pass/associated-const-public-impl.rs | 2 ++ .../associated-const-resolution-order.rs | 2 ++ .../run-pass/associated-const-self-type.rs | 2 ++ .../associated-const-ufcs-infer-trait.rs | 2 ++ .../run-pass/associated-const-use-default.rs | 2 ++ ...associated-const-use-impl-of-same-trait.rs | 2 ++ src/test/run-pass/associated-const.rs | 2 ++ 23 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/gated-associated_consts.rs diff --git a/src/doc/reference.md b/src/doc/reference.md index d918a320e63a9..2acd491c65787 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -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. diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index d0975c76e9351..495bbd412ab72 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -155,6 +155,10 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ // Allows use of unary negate on unsigned integers, e.g. -e for e: u8 ("negate_unsigned", "1.0.0", Active), + + // Allows the definition of associated constants in `trait` or `impl` + // blocks. + ("associated_consts", "1.0.0", Active), ]; // (changing above list without updating src/doc/reference.md makes @cmr sad) @@ -659,6 +663,30 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { } visit::walk_fn(self, fn_kind, fn_decl, block, span); } + + fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) { + match ti.node { + ast::ConstTraitItem(..) => { + self.gate_feature("associated_consts", + ti.span, + "associated constants are experimental") + } + _ => {} + } + visit::walk_trait_item(self, ti); + } + + fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) { + match ii.node { + ast::ConstImplItem(..) => { + self.gate_feature("associated_consts", + ii.span, + "associated constants are experimental") + } + _ => {} + } + visit::walk_impl_item(self, ii); + } } fn check_crate_inner(cm: &CodeMap, span_handler: &SpanHandler, diff --git a/src/test/auxiliary/associated-const-cc-lib.rs b/src/test/auxiliary/associated-const-cc-lib.rs index 9735c6cb54d2b..3508fcd54af03 100644 --- a/src/test/auxiliary/associated-const-cc-lib.rs +++ b/src/test/auxiliary/associated-const-cc-lib.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + #![crate_type="lib"] use std::marker::MarkerTrait; diff --git a/src/test/compile-fail/associated-const-dead-code.rs b/src/test/compile-fail/associated-const-dead-code.rs index 42db13f4f3bd4..1ed156d45f550 100644 --- a/src/test/compile-fail/associated-const-dead-code.rs +++ b/src/test/compile-fail/associated-const-dead-code.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] #![deny(dead_code)] struct MyFoo; diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs index a7b2abc99e5f9..d76147de3db2c 100644 --- a/src/test/compile-fail/associated-const-impl-wrong-type.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; trait Foo: MarkerTrait { diff --git a/src/test/compile-fail/associated-const-private-impl.rs b/src/test/compile-fail/associated-const-private-impl.rs index 1d74873a5d50b..4dfe7ea78c59e 100644 --- a/src/test/compile-fail/associated-const-private-impl.rs +++ b/src/test/compile-fail/associated-const-private-impl.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; mod bar1 { diff --git a/src/test/compile-fail/associated-const-upper-case-lint.rs b/src/test/compile-fail/associated-const-upper-case-lint.rs index 497ff426b2fae..752691fa1c550 100644 --- a/src/test/compile-fail/associated-const-upper-case-lint.rs +++ b/src/test/compile-fail/associated-const-upper-case-lint.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] #![deny(non_upper_case_globals)] #![allow(dead_code)] diff --git a/src/test/compile-fail/gated-associated_consts.rs b/src/test/compile-fail/gated-associated_consts.rs new file mode 100644 index 0000000000000..d508016357c86 --- /dev/null +++ b/src/test/compile-fail/gated-associated_consts.rs @@ -0,0 +1,25 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::marker::MarkerTrait; + +trait MyTrait: MarkerTrait { + const C: bool; + //~^ associated constants are experimental + //~| add #![feature(associated_consts)] to the crate attributes to enable +} + +struct Foo; + +impl Foo { + const C: bool = true; + //~^ associated constants are experimental + //~| add #![feature(associated_consts)] to the crate attributes to enable +} diff --git a/src/test/compile-fail/impl-wrong-item-for-trait.rs b/src/test/compile-fail/impl-wrong-item-for-trait.rs index 3757005b91fdd..9b3e28cbc01ee 100644 --- a/src/test/compile-fail/impl-wrong-item-for-trait.rs +++ b/src/test/compile-fail/impl-wrong-item-for-trait.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + trait Foo { fn bar(&self); const MY_CONST: u32; diff --git a/src/test/run-pass/associated-const-cross-crate-defaults.rs b/src/test/run-pass/associated-const-cross-crate-defaults.rs index 944466f359da0..92d2aae61c8e5 100644 --- a/src/test/run-pass/associated-const-cross-crate-defaults.rs +++ b/src/test/run-pass/associated-const-cross-crate-defaults.rs @@ -10,6 +10,8 @@ // aux-build:associated-const-cc-lib.rs +#![feature(associated_consts)] + extern crate associated_const_cc_lib as foolib; pub struct LocalFooUseDefault; diff --git a/src/test/run-pass/associated-const-cross-crate.rs b/src/test/run-pass/associated-const-cross-crate.rs index c18cda018d87a..73d5dc5df96f6 100644 --- a/src/test/run-pass/associated-const-cross-crate.rs +++ b/src/test/run-pass/associated-const-cross-crate.rs @@ -10,6 +10,8 @@ // aux-build:associated-const-cc-lib.rs +#![feature(associated_consts)] + extern crate associated_const_cc_lib as foolib; pub struct LocalFoo; diff --git a/src/test/run-pass/associated-const-in-global-const.rs b/src/test/run-pass/associated-const-in-global-const.rs index b9fb067d4fa87..e3a1e29d20f54 100644 --- a/src/test/run-pass/associated-const-in-global-const.rs +++ b/src/test/run-pass/associated-const-in-global-const.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + struct Foo; impl Foo { diff --git a/src/test/run-pass/associated-const-inherent-impl.rs b/src/test/run-pass/associated-const-inherent-impl.rs index 71f7a925d55d9..5c9abf982b158 100644 --- a/src/test/run-pass/associated-const-inherent-impl.rs +++ b/src/test/run-pass/associated-const-inherent-impl.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + struct Foo; impl Foo { diff --git a/src/test/run-pass/associated-const-marks-live-code.rs b/src/test/run-pass/associated-const-marks-live-code.rs index e86ff0199a12d..ea91a95312983 100644 --- a/src/test/run-pass/associated-const-marks-live-code.rs +++ b/src/test/run-pass/associated-const-marks-live-code.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + #![deny(dead_code)] const GLOBAL_BAR: u32 = 1; diff --git a/src/test/run-pass/associated-const-match-patterns.rs b/src/test/run-pass/associated-const-match-patterns.rs index 0085f89822edf..63f77b351704b 100644 --- a/src/test/run-pass/associated-const-match-patterns.rs +++ b/src/test/run-pass/associated-const-match-patterns.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; struct Foo; diff --git a/src/test/run-pass/associated-const-overwrite-default.rs b/src/test/run-pass/associated-const-overwrite-default.rs index 26ece859e143d..5134ad3565956 100644 --- a/src/test/run-pass/associated-const-overwrite-default.rs +++ b/src/test/run-pass/associated-const-overwrite-default.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; trait Foo: MarkerTrait { diff --git a/src/test/run-pass/associated-const-public-impl.rs b/src/test/run-pass/associated-const-public-impl.rs index 08676425a514d..686ac19dad155 100644 --- a/src/test/run-pass/associated-const-public-impl.rs +++ b/src/test/run-pass/associated-const-public-impl.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; mod bar1 { diff --git a/src/test/run-pass/associated-const-resolution-order.rs b/src/test/run-pass/associated-const-resolution-order.rs index e42dd25022b61..ad20c084ff458 100644 --- a/src/test/run-pass/associated-const-resolution-order.rs +++ b/src/test/run-pass/associated-const-resolution-order.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; struct MyType; diff --git a/src/test/run-pass/associated-const-self-type.rs b/src/test/run-pass/associated-const-self-type.rs index b4fb452e02003..dc8b1307f7607 100644 --- a/src/test/run-pass/associated-const-self-type.rs +++ b/src/test/run-pass/associated-const-self-type.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; trait MyInt: MarkerTrait { diff --git a/src/test/run-pass/associated-const-ufcs-infer-trait.rs b/src/test/run-pass/associated-const-ufcs-infer-trait.rs index 21e1159366d5a..4cee76eb5aa42 100644 --- a/src/test/run-pass/associated-const-ufcs-infer-trait.rs +++ b/src/test/run-pass/associated-const-ufcs-infer-trait.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; trait Foo: MarkerTrait { diff --git a/src/test/run-pass/associated-const-use-default.rs b/src/test/run-pass/associated-const-use-default.rs index 59c83e267dbe1..59df2fc41ed3a 100644 --- a/src/test/run-pass/associated-const-use-default.rs +++ b/src/test/run-pass/associated-const-use-default.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; trait Foo: MarkerTrait { diff --git a/src/test/run-pass/associated-const-use-impl-of-same-trait.rs b/src/test/run-pass/associated-const-use-impl-of-same-trait.rs index 2f95d4275c561..6c9c6767cbd2c 100644 --- a/src/test/run-pass/associated-const-use-impl-of-same-trait.rs +++ b/src/test/run-pass/associated-const-use-impl-of-same-trait.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; // The main purpose of this test is to ensure that different impls of the same diff --git a/src/test/run-pass/associated-const.rs b/src/test/run-pass/associated-const.rs index 5e7cc12cf485b..9214467275f5f 100644 --- a/src/test/run-pass/associated-const.rs +++ b/src/test/run-pass/associated-const.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(associated_consts)] + use std::marker::MarkerTrait; trait Foo: MarkerTrait { From 4c0ac6d5ef8aed2cbe0cc687d5e7f8a8c04961a3 Mon Sep 17 00:00:00 2001 From: Sean Patrick Santos Date: Fri, 24 Apr 2015 22:58:40 -0600 Subject: [PATCH 8/8] Remove obsolete "MarkerTrait" from tests. --- src/test/auxiliary/associated-const-cc-lib.rs | 6 ++---- src/test/compile-fail/associated-const-impl-wrong-type.rs | 4 +--- src/test/compile-fail/associated-const-private-impl.rs | 2 -- src/test/compile-fail/gated-associated_consts.rs | 4 +--- src/test/compile-fail/method-path-in-pattern.rs | 4 +--- src/test/compile-fail/method-resolvable-path-in-pattern.rs | 4 +--- src/test/run-pass/associated-const-match-patterns.rs | 4 +--- src/test/run-pass/associated-const-overwrite-default.rs | 4 +--- src/test/run-pass/associated-const-public-impl.rs | 2 -- src/test/run-pass/associated-const-resolution-order.rs | 4 +--- src/test/run-pass/associated-const-self-type.rs | 4 +--- src/test/run-pass/associated-const-ufcs-infer-trait.rs | 4 +--- src/test/run-pass/associated-const-use-default.rs | 4 +--- .../run-pass/associated-const-use-impl-of-same-trait.rs | 4 +--- src/test/run-pass/associated-const.rs | 4 +--- 15 files changed, 14 insertions(+), 44 deletions(-) diff --git a/src/test/auxiliary/associated-const-cc-lib.rs b/src/test/auxiliary/associated-const-cc-lib.rs index 3508fcd54af03..1fd8fee0117c5 100644 --- a/src/test/auxiliary/associated-const-cc-lib.rs +++ b/src/test/auxiliary/associated-const-cc-lib.rs @@ -12,10 +12,8 @@ #![crate_type="lib"] -use std::marker::MarkerTrait; - // These items are for testing that associated consts work cross-crate. -pub trait Foo: MarkerTrait { +pub trait Foo { const BAR: usize; } @@ -26,7 +24,7 @@ impl Foo for FooNoDefault { } // These test that defaults and default resolution work cross-crate. -pub trait FooDefault: MarkerTrait { +pub trait FooDefault { const BAR: usize = 1; } diff --git a/src/test/compile-fail/associated-const-impl-wrong-type.rs b/src/test/compile-fail/associated-const-impl-wrong-type.rs index d76147de3db2c..4f20d9e78ebd0 100644 --- a/src/test/compile-fail/associated-const-impl-wrong-type.rs +++ b/src/test/compile-fail/associated-const-impl-wrong-type.rs @@ -10,9 +10,7 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - -trait Foo: MarkerTrait { +trait Foo { const BAR: u32; } diff --git a/src/test/compile-fail/associated-const-private-impl.rs b/src/test/compile-fail/associated-const-private-impl.rs index 4dfe7ea78c59e..be949db0281d2 100644 --- a/src/test/compile-fail/associated-const-private-impl.rs +++ b/src/test/compile-fail/associated-const-private-impl.rs @@ -10,8 +10,6 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - mod bar1 { pub use self::bar2::Foo; mod bar2 { diff --git a/src/test/compile-fail/gated-associated_consts.rs b/src/test/compile-fail/gated-associated_consts.rs index d508016357c86..21672b18bde44 100644 --- a/src/test/compile-fail/gated-associated_consts.rs +++ b/src/test/compile-fail/gated-associated_consts.rs @@ -8,9 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - -trait MyTrait: MarkerTrait { +trait MyTrait { const C: bool; //~^ associated constants are experimental //~| add #![feature(associated_consts)] to the crate attributes to enable diff --git a/src/test/compile-fail/method-path-in-pattern.rs b/src/test/compile-fail/method-path-in-pattern.rs index 1d83f901cdb62..faf6d255c9afc 100644 --- a/src/test/compile-fail/method-path-in-pattern.rs +++ b/src/test/compile-fail/method-path-in-pattern.rs @@ -8,15 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - struct Foo; impl Foo { fn bar(&self) {} } -trait MyTrait: MarkerTrait { +trait MyTrait { fn trait_bar() {} } diff --git a/src/test/compile-fail/method-resolvable-path-in-pattern.rs b/src/test/compile-fail/method-resolvable-path-in-pattern.rs index f3e93537203b3..0df824e7f535b 100644 --- a/src/test/compile-fail/method-resolvable-path-in-pattern.rs +++ b/src/test/compile-fail/method-resolvable-path-in-pattern.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::marker::MarkerTrait; - struct Foo; -trait MyTrait: MarkerTrait { +trait MyTrait { fn trait_bar() {} } diff --git a/src/test/run-pass/associated-const-match-patterns.rs b/src/test/run-pass/associated-const-match-patterns.rs index 63f77b351704b..eeaacbf9dcc78 100644 --- a/src/test/run-pass/associated-const-match-patterns.rs +++ b/src/test/run-pass/associated-const-match-patterns.rs @@ -10,8 +10,6 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - struct Foo; enum Bar { @@ -24,7 +22,7 @@ impl Foo { const MYBAR: Bar = Bar::Var2; } -trait HasBar: MarkerTrait { +trait HasBar { const THEBAR: Bar; } diff --git a/src/test/run-pass/associated-const-overwrite-default.rs b/src/test/run-pass/associated-const-overwrite-default.rs index 5134ad3565956..0846ad9a571b3 100644 --- a/src/test/run-pass/associated-const-overwrite-default.rs +++ b/src/test/run-pass/associated-const-overwrite-default.rs @@ -10,9 +10,7 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - -trait Foo: MarkerTrait { +trait Foo { const ID: i32 = 2; } diff --git a/src/test/run-pass/associated-const-public-impl.rs b/src/test/run-pass/associated-const-public-impl.rs index 686ac19dad155..b1d071799e1a8 100644 --- a/src/test/run-pass/associated-const-public-impl.rs +++ b/src/test/run-pass/associated-const-public-impl.rs @@ -10,8 +10,6 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - mod bar1 { pub use self::bar2::Foo; mod bar2 { diff --git a/src/test/run-pass/associated-const-resolution-order.rs b/src/test/run-pass/associated-const-resolution-order.rs index ad20c084ff458..98b7164ab74ad 100644 --- a/src/test/run-pass/associated-const-resolution-order.rs +++ b/src/test/run-pass/associated-const-resolution-order.rs @@ -10,15 +10,13 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - struct MyType; impl MyType { const IMPL_IS_INHERENT: bool = true; } -trait MyTrait: MarkerTrait { +trait MyTrait { const IMPL_IS_INHERENT: bool; const IMPL_IS_ON_TRAIT: bool; } diff --git a/src/test/run-pass/associated-const-self-type.rs b/src/test/run-pass/associated-const-self-type.rs index dc8b1307f7607..d3add976b5af8 100644 --- a/src/test/run-pass/associated-const-self-type.rs +++ b/src/test/run-pass/associated-const-self-type.rs @@ -10,9 +10,7 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - -trait MyInt: MarkerTrait { +trait MyInt { const ONE: Self; } diff --git a/src/test/run-pass/associated-const-ufcs-infer-trait.rs b/src/test/run-pass/associated-const-ufcs-infer-trait.rs index 4cee76eb5aa42..aa3e14a939784 100644 --- a/src/test/run-pass/associated-const-ufcs-infer-trait.rs +++ b/src/test/run-pass/associated-const-ufcs-infer-trait.rs @@ -10,9 +10,7 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - -trait Foo: MarkerTrait { +trait Foo { const ID: i32; } diff --git a/src/test/run-pass/associated-const-use-default.rs b/src/test/run-pass/associated-const-use-default.rs index 59df2fc41ed3a..5813d86742532 100644 --- a/src/test/run-pass/associated-const-use-default.rs +++ b/src/test/run-pass/associated-const-use-default.rs @@ -10,9 +10,7 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - -trait Foo: MarkerTrait { +trait Foo { const ID: i32 = 1; } diff --git a/src/test/run-pass/associated-const-use-impl-of-same-trait.rs b/src/test/run-pass/associated-const-use-impl-of-same-trait.rs index 6c9c6767cbd2c..62658470baa52 100644 --- a/src/test/run-pass/associated-const-use-impl-of-same-trait.rs +++ b/src/test/run-pass/associated-const-use-impl-of-same-trait.rs @@ -10,13 +10,11 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - // The main purpose of this test is to ensure that different impls of the same // trait can refer to each other without setting off the static recursion check // (as long as there's no actual recursion). -trait Foo: MarkerTrait { +trait Foo { const BAR: u32; } diff --git a/src/test/run-pass/associated-const.rs b/src/test/run-pass/associated-const.rs index 9214467275f5f..d906544500931 100644 --- a/src/test/run-pass/associated-const.rs +++ b/src/test/run-pass/associated-const.rs @@ -10,9 +10,7 @@ #![feature(associated_consts)] -use std::marker::MarkerTrait; - -trait Foo: MarkerTrait { +trait Foo { const ID: i32; }