about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-12-17 02:31:55 -0800
committerbors <bors@rust-lang.org>2013-12-17 02:31:55 -0800
commitdc65762d7923a9e66e8e5d743cb8b2d2fdd3cde5 (patch)
treed7b3bfe13164b95e88997b369b23686881140750
parent47c9a35747e9a15830e35924429050b820825f5d (diff)
parent4f95dceb597da2ab4af207179e0731a6db104287 (diff)
downloadrust-dc65762d7923a9e66e8e5d743cb8b2d2fdd3cde5.tar.gz
rust-dc65762d7923a9e66e8e5d743cb8b2d2fdd3cde5.zip
auto merge of #10990 : ktt3ja/rust/method-stability, r=huonw
If it's a trait method, this checks the stability attribute of the
method inside the trait definition. Otherwise, it checks the method
implementation itself.

Close #8961.
-rw-r--r--src/librustc/driver/driver.rs2
-rw-r--r--src/librustc/metadata/encoder.rs8
-rw-r--r--src/librustc/middle/lint.rs46
-rw-r--r--src/librustc/middle/ty.rs68
-rw-r--r--src/test/compile-fail/lint-stability.rs100
5 files changed, 171 insertions, 53 deletions
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 6206b4efa32..afc910056eb 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -312,7 +312,7 @@ pub fn phase_3_run_analysis_passes(sess: Session,
                                    &exported_items, reachable_map, crate));
 
     time(time_passes, "lint checking", (), |_|
-         lint::check_crate(ty_cx, &exported_items, crate));
+         lint::check_crate(ty_cx, method_map, &exported_items, crate));
 
     CrateAnalysis {
         exp_map2: exp_map2,
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 1ffadfb6ede..b27aa11651d 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -812,6 +812,10 @@ fn encode_info_for_method(ecx: &EncodeContext,
     encode_bounds_and_type(ebml_w, ecx, &tpt);
 
     encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident));
+    match ast_method_opt {
+        Some(ast_method) => encode_attributes(ebml_w, ast_method.attrs),
+        None => ()
+    }
 
     for ast_method in ast_method_opt.iter() {
         let num_params = tpt.generics.type_param_defs.len();
@@ -1205,11 +1209,13 @@ fn encode_info_for_item(ecx: &EncodeContext,
             }
 
             match ms[i] {
-                required(_) => {
+                required(ref tm) => {
+                    encode_attributes(ebml_w, tm.attrs);
                     encode_method_sort(ebml_w, 'r');
                 }
 
                 provided(m) => {
+                    encode_attributes(ebml_w, m.attrs);
                     // If this is a static method, we've already encoded
                     // this.
                     if method_ty.explicit_self != sty_static {
diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs
index 5128f90a0a5..8f5ae723c54 100644
--- a/src/librustc/middle/lint.rs
+++ b/src/librustc/middle/lint.rs
@@ -37,6 +37,7 @@ use driver::session;
 use middle::privacy;
 use middle::trans::adt; // for `adt::is_ffi_safe`
 use middle::ty;
+use middle::typeck;
 use middle::pat_util;
 use metadata::csearch;
 use util::ppaux::{ty_to_str};
@@ -359,6 +360,9 @@ struct Context<'a> {
     cur: SmallIntMap<(level, LintSource)>,
     // context we're checking in (used to access fields like sess)
     tcx: ty::ctxt,
+    // maps from an expression id that corresponds to a method call to the
+    // details of the method to be invoked
+    method_map: typeck::method_map,
     // Items exported by the crate; used by the missing_doc lint.
     exported_items: &'a privacy::ExportedItems,
     // The id of the current `ast::struct_def` being walked.
@@ -1176,20 +1180,43 @@ fn check_missing_doc_variant(cx: &Context, v: &ast::variant) {
 /// Checks for use of items with #[deprecated], #[experimental] and
 /// #[unstable] (or none of them) attributes.
 fn check_stability(cx: &Context, e: &ast::Expr) {
-    let def = match e.node {
-        ast::ExprMethodCall(..) |
-        ast::ExprPath(..) |
-        ast::ExprStruct(..) => {
+    let id = match e.node {
+        ast::ExprPath(..) | ast::ExprStruct(..) => {
             match cx.tcx.def_map.find(&e.id) {
-                Some(&def) => def,
+                Some(&def) => ast_util::def_id_of_def(def),
+                None => return
+            }
+        }
+        ast::ExprMethodCall(..) => {
+            match cx.method_map.find(&e.id) {
+                Some(&typeck::method_map_entry { origin, .. }) => {
+                    match origin {
+                        typeck::method_static(def_id) => {
+                            // If this implements a trait method, get def_id
+                            // of the method inside trait definition.
+                            // Otherwise, use the current def_id (which refers
+                            // to the method inside impl).
+                            ty::trait_method_of_method(
+                                cx.tcx, def_id).unwrap_or(def_id)
+                        }
+                        typeck::method_param(typeck::method_param {
+                            trait_id: trait_id,
+                            method_num: index,
+                            ..
+                        })
+                        | typeck::method_object(typeck::method_object {
+                            trait_id: trait_id,
+                            method_num: index,
+                            ..
+                        }) => ty::trait_method(cx.tcx, trait_id, index).def_id
+                    }
+                }
                 None => return
             }
         }
         _ => return
     };
 
-    let id = ast_util::def_id_of_def(def);
-
     let stability = if ast_util::is_local(id) {
         // this crate
         match cx.tcx.items.find(&id.node) {
@@ -1208,7 +1235,8 @@ fn check_stability(cx: &Context, e: &ast::Expr) {
                     None => return
                 }
             }
-            _ => cx.tcx.sess.bug(format!("handle_def: {:?} not found", id))
+            _ => cx.tcx.sess.span_bug(e.span,
+                                      format!("handle_def: {:?} not found", id))
         }
     } else {
         // cross-crate
@@ -1395,12 +1423,14 @@ impl<'a> IdVisitingOperation for Context<'a> {
 }
 
 pub fn check_crate(tcx: ty::ctxt,
+                   method_map: typeck::method_map,
                    exported_items: &privacy::ExportedItems,
                    crate: &ast::Crate) {
     let mut cx = Context {
         dict: @get_lint_dict(),
         cur: SmallIntMap::new(),
         tcx: tcx,
+        method_map: method_map,
         exported_items: exported_items,
         cur_struct_def_id: -1,
         is_doc_hidden: false,
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 86a7250d6b9..1bdd88a3b7a 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -4540,29 +4540,67 @@ pub fn populate_implementations_for_trait_if_necessary(
     tcx.populated_external_traits.insert(trait_id);
 }
 
-/// If the given def ID describes a trait method, returns the ID of the trait
-/// that the method belongs to. Otherwise, returns `None`.
+/// Given the def_id of an impl, return the def_id of the trait it implements.
+/// If it implements no trait, return `None`.
+pub fn trait_id_of_impl(tcx: ctxt,
+                        def_id: ast::DefId) -> Option<ast::DefId> {
+    let node = match tcx.items.find(&def_id.node) {
+        Some(node) => node,
+        None => return None
+    };
+    match node {
+        &ast_map::node_item(item, _) => {
+            match item.node {
+                ast::item_impl(_, Some(ref trait_ref), _, _) => {
+                    Some(node_id_to_trait_ref(tcx, trait_ref.ref_id).def_id)
+                }
+                _ => None
+            }
+        }
+        _ => None
+    }
+}
+
+/// If the given def ID describes a method belonging to a trait (either a
+/// default method or an implementation of a trait method), return the ID of
+/// the trait that the method belongs to. Otherwise, return `None`.
 pub fn trait_of_method(tcx: ctxt, def_id: ast::DefId)
                        -> Option<ast::DefId> {
+    if def_id.crate != LOCAL_CRATE {
+        return csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
+    }
     match tcx.methods.find(&def_id) {
-        Some(method_descriptor) => {
-            match method_descriptor.container {
-                TraitContainer(id) => return Some(id),
-                _ => {}
+        Some(method) => {
+            match method.container {
+                TraitContainer(def_id) => Some(def_id),
+                ImplContainer(def_id) => trait_id_of_impl(tcx, def_id),
             }
         }
-        None => {}
+        None => None
     }
+}
 
-    // If the method was in the local crate, then if we got here we know the
-    // answer is negative.
-    if def_id.crate == LOCAL_CRATE {
-        return None
+/// If the given def ID describes a method belonging to a trait, (either a
+/// default method or an implementation of a trait method), return the ID of
+/// the method inside trait definition (this means that if the given def ID
+/// is already that of the original trait method, then the return value is
+/// the same).
+/// Otherwise, return `None`.
+pub fn trait_method_of_method(tcx: ctxt,
+                              def_id: ast::DefId) -> Option<ast::DefId> {
+    let name = match tcx.methods.find(&def_id) {
+        Some(method) => method.ident.name,
+        None => return None
+    };
+    match trait_of_method(tcx, def_id) {
+        Some(trait_did) => {
+            let trait_methods = ty::trait_methods(tcx, trait_did);
+            trait_methods.iter()
+                .position(|m| m.ident.name == name)
+                .map(|idx| ty::trait_method(tcx, trait_did, idx).def_id)
+        }
+        None => None
     }
-
-    let result = csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
-
-    result
 }
 
 /// Creates a hash of the type `t` which will be the same no matter what crate
diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs
index 9cc06cc5395..ceec1ae3d8a 100644
--- a/src/test/compile-fail/lint-stability.rs
+++ b/src/test/compile-fail/lint-stability.rs
@@ -26,32 +26,32 @@ mod cross_crate {
         let foo = MethodTester;
 
         deprecated(); //~ ERROR use of deprecated item
-        foo.method_deprecated(); // ~ ERROR use of deprecated item
-        foo.trait_deprecated(); // ~ ERROR use of deprecated item
+        foo.method_deprecated(); //~ ERROR use of deprecated item
+        foo.trait_deprecated(); //~ ERROR use of deprecated item
 
         deprecated_text(); //~ ERROR use of deprecated item: text
-        foo.method_deprecated_text(); // ~ ERROR use of deprecated item: text
-        foo.trait_deprecated_text(); // ~ ERROR use of deprecated item: text
+        foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
+        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
 
         experimental(); //~ ERROR use of experimental item
-        foo.method_experimental(); // ~ ERROR use of experimental item
-        foo.trait_experimental(); // ~ ERROR use of experimental item
+        foo.method_experimental(); //~ ERROR use of experimental item
+        foo.trait_experimental(); //~ ERROR use of experimental item
 
         experimental_text(); //~ ERROR use of experimental item: text
-        foo.method_experimental_text(); // ~ ERROR use of experimental item: text
-        foo.trait_experimental_text(); // ~ ERROR use of experimental item: text
+        foo.method_experimental_text(); //~ ERROR use of experimental item: text
+        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
 
         unstable(); //~ ERROR use of unstable item
-        foo.method_unstable(); // ~ ERROR use of unstable item
-        foo.trait_unstable(); // ~ ERROR use of unstable item
+        foo.method_unstable(); //~ ERROR use of unstable item
+        foo.trait_unstable(); //~ ERROR use of unstable item
 
         unstable_text(); //~ ERROR use of unstable item: text
-        foo.method_unstable_text(); // ~ ERROR use of unstable item: text
-        foo.trait_unstable_text(); // ~ ERROR use of unstable item: text
+        foo.method_unstable_text(); //~ ERROR use of unstable item: text
+        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
 
         unmarked(); //~ ERROR use of unmarked item
-        foo.method_unmarked(); // ~ ERROR use of unmarked item
-        foo.trait_unmarked(); // ~ ERROR use of unmarked item
+        foo.method_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_unmarked(); //~ ERROR use of unmarked item
 
         stable();
         foo.method_stable();
@@ -102,6 +102,28 @@ mod cross_crate {
         let _ = FrozenVariant;
         let _ = LockedVariant;
     }
+
+    fn test_method_param<F: Trait>(foo: F) {
+        foo.trait_deprecated(); //~ ERROR use of deprecated item
+        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+        foo.trait_experimental(); //~ ERROR use of experimental item
+        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
+        foo.trait_unstable(); //~ ERROR use of unstable item
+        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
+        foo.trait_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_stable();
+    }
+
+    fn test_method_object(foo: &Trait) {
+        foo.trait_deprecated(); //~ ERROR use of deprecated item
+        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+        foo.trait_experimental(); //~ ERROR use of experimental item
+        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
+        foo.trait_unstable(); //~ ERROR use of unstable item
+        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
+        foo.trait_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_stable();
+    }
 }
 
 mod this_crate {
@@ -259,32 +281,32 @@ mod this_crate {
         let foo = MethodTester;
 
         deprecated(); //~ ERROR use of deprecated item
-        foo.method_deprecated(); // ~ ERROR use of deprecated item
-        foo.trait_deprecated(); // ~ ERROR use of deprecated item
+        foo.method_deprecated(); //~ ERROR use of deprecated item
+        foo.trait_deprecated(); //~ ERROR use of deprecated item
 
         deprecated_text(); //~ ERROR use of deprecated item: text
-        foo.method_deprecated_text(); // ~ ERROR use of deprecated item: text
-        foo.trait_deprecated_text(); // ~ ERROR use of deprecated item: text
+        foo.method_deprecated_text(); //~ ERROR use of deprecated item: text
+        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
 
         experimental(); //~ ERROR use of experimental item
-        foo.method_experimental(); // ~ ERROR use of experimental item
-        foo.trait_experimental(); // ~ ERROR use of experimental item
+        foo.method_experimental(); //~ ERROR use of experimental item
+        foo.trait_experimental(); //~ ERROR use of experimental item
 
         experimental_text(); //~ ERROR use of experimental item: text
-        foo.method_experimental_text(); // ~ ERROR use of experimental item: text
-        foo.trait_experimental_text(); // ~ ERROR use of experimental item: text
+        foo.method_experimental_text(); //~ ERROR use of experimental item: text
+        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
 
         unstable(); //~ ERROR use of unstable item
-        foo.method_unstable(); // ~ ERROR use of unstable item
-        foo.trait_unstable(); // ~ ERROR use of unstable item
+        foo.method_unstable(); //~ ERROR use of unstable item
+        foo.trait_unstable(); //~ ERROR use of unstable item
 
         unstable_text(); //~ ERROR use of unstable item: text
-        foo.method_unstable_text(); // ~ ERROR use of unstable item: text
-        foo.trait_unstable_text(); // ~ ERROR use of unstable item: text
+        foo.method_unstable_text(); //~ ERROR use of unstable item: text
+        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
 
         unmarked(); //~ ERROR use of unmarked item
-        foo.method_unmarked(); // ~ ERROR use of unmarked item
-        foo.trait_unmarked(); // ~ ERROR use of unmarked item
+        foo.method_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_unmarked(); //~ ERROR use of unmarked item
 
         stable();
         foo.method_stable();
@@ -335,6 +357,28 @@ mod this_crate {
         let _ = FrozenVariant;
         let _ = LockedVariant;
     }
+
+    fn test_method_param<F: Trait>(foo: F) {
+        foo.trait_deprecated(); //~ ERROR use of deprecated item
+        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+        foo.trait_experimental(); //~ ERROR use of experimental item
+        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
+        foo.trait_unstable(); //~ ERROR use of unstable item
+        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
+        foo.trait_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_stable();
+    }
+
+    fn test_method_object(foo: &Trait) {
+        foo.trait_deprecated(); //~ ERROR use of deprecated item
+        foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
+        foo.trait_experimental(); //~ ERROR use of experimental item
+        foo.trait_experimental_text(); //~ ERROR use of experimental item: text
+        foo.trait_unstable(); //~ ERROR use of unstable item
+        foo.trait_unstable_text(); //~ ERROR use of unstable item: text
+        foo.trait_unmarked(); //~ ERROR use of unmarked item
+        foo.trait_stable();
+    }
 }
 
 fn main() {}