about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2015-07-02 13:33:01 +0300
committerEduard Burtescu <edy.burt@gmail.com>2015-07-04 06:21:00 +0300
commit5620a5879178dab2b929557208e19827eab9bda0 (patch)
tree8aa16016b9163f03148b6e629b3b60ecbfe790eb /src
parenta2fe59afd66f032bea04f55fdb8beb00b53b65d7 (diff)
downloadrust-5620a5879178dab2b929557208e19827eab9bda0.tar.gz
rust-5620a5879178dab2b929557208e19827eab9bda0.zip
rustc_lint: use traits::select for methods in unconditional_recursion.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/astencode.rs69
-rw-r--r--src/librustc/middle/ty.rs8
-rw-r--r--src/librustc_lint/builtin.rs144
-rw-r--r--src/librustc_privacy/lib.rs2
-rw-r--r--src/librustc_trans/save/dump_csv.rs3
-rw-r--r--src/librustc_trans/trans/meth.rs2
-rw-r--r--src/librustc_typeck/check/method/confirm.rs6
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
8 files changed, 92 insertions, 144 deletions
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index 6b476f92196..fa06d502728 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -617,7 +617,7 @@ fn encode_method_callee<'a, 'tcx>(ecx: &e::EncodeContext<'a, 'tcx>,
             Ok(rbml_w.emit_def_id(method.def_id))
         });
         rbml_w.emit_struct_field("origin", 2, |rbml_w| {
-            Ok(rbml_w.emit_method_origin(method.origin))
+            method.origin.encode(rbml_w)
         });
         rbml_w.emit_struct_field("ty", 3, |rbml_w| {
             Ok(rbml_w.emit_ty(ecx, method.ty))
@@ -633,16 +633,14 @@ impl<'a, 'tcx> read_method_callee_helper<'tcx> for reader::Decoder<'a> {
                                   -> (u32, ty::MethodCallee<'tcx>) {
 
         self.read_struct("MethodCallee", 5, |this| {
-            let autoderef = this.read_struct_field("autoderef", 0, |this| {
-                Decodable::decode(this)
-            }).unwrap();
+            let autoderef = this.read_struct_field("autoderef", 0,
+                                                   Decodable::decode).unwrap();
             Ok((autoderef, ty::MethodCallee {
                 def_id: this.read_struct_field("def_id", 1, |this| {
                     Ok(this.read_def_id(dcx))
                 }).unwrap(),
-                origin: this.read_struct_field("origin", 2, |this| {
-                    Ok(this.read_method_origin(dcx))
-                }).unwrap(),
+                origin: this.read_struct_field("origin", 2,
+                                               Decodable::decode).unwrap(),
                 ty: this.read_struct_field("ty", 3, |this| {
                     Ok(this.read_ty(dcx))
                 }).unwrap(),
@@ -713,7 +711,6 @@ impl<'a, 'tcx> get_ty_str_ctxt<'tcx> for e::EncodeContext<'a, 'tcx> {
 trait rbml_writer_helpers<'tcx> {
     fn emit_closure_type<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
                              closure_type: &ty::ClosureTy<'tcx>);
-    fn emit_method_origin(&mut self, method_origin: ty::MethodOrigin);
     fn emit_ty<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, ty: Ty<'tcx>);
     fn emit_tys<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>, tys: &[Ty<'tcx>]);
     fn emit_type_param_def<'a>(&mut self, ecx: &e::EncodeContext<'a, 'tcx>,
@@ -745,37 +742,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
         });
     }
 
-    fn emit_method_origin(&mut self, method_origin: ty::MethodOrigin) {
-        use serialize::Encoder;
-
-        self.emit_enum("MethodOrigin", |this| {
-            match method_origin {
-                ty::MethodOrigin::Inherent => {
-                    this.emit_enum_variant("Inherent", 0, 0, |_| Ok(()))
-                }
-
-                ty::MethodOrigin::Trait(impl_def_id) => {
-                    this.emit_enum_variant("Trait", 1, 1, |this| {
-                        this.emit_option(|this| {
-                            match impl_def_id {
-                                None => this.emit_option_none(),
-                                Some(did) => this.emit_option_some(|this| {
-                                    Ok(this.emit_def_id(did))
-                                })
-                            }
-                        })
-                    })
-                }
-
-                ty::MethodOrigin::Object(vtable_index) => {
-                    this.emit_enum_variant("Object", 2, 1, |this| {
-                        this.emit_uint(vtable_index)
-                    })
-                }
-            }
-        });
-    }
-
     fn emit_ty<'b>(&mut self, ecx: &e::EncodeContext<'b, 'tcx>, ty: Ty<'tcx>) {
         self.emit_opaque(|this| Ok(e::write_type(ecx, this, ty)));
     }
@@ -1118,7 +1084,6 @@ impl<'a> doc_decoder_helpers for rbml::Doc<'a> {
 }
 
 trait rbml_decoder_decoder_helpers<'tcx> {
-    fn read_method_origin(&mut self, dcx: &DecodeContext) -> ty::MethodOrigin;
     fn read_ty<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Ty<'tcx>;
     fn read_tys<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>) -> Vec<Ty<'tcx>>;
     fn read_trait_ref<'a, 'b>(&mut self, dcx: &DecodeContext<'a, 'b, 'tcx>)
@@ -1202,30 +1167,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
         }).unwrap()
     }
 
-    fn read_method_origin(&mut self, dcx: &DecodeContext) -> ty::MethodOrigin {
-        self.read_enum("MethodOrigin", |this| {
-            let variants = &["Inherent", "Trait", "Object"];
-            this.read_enum_variant(variants, |this, i| {
-                match i {
-                    0 => Ok(ty::MethodOrigin::Inherent),
-
-                    1 => this.read_option(|this, b| {
-                        Ok(ty::MethodOrigin::Trait(if b {
-                            Some(this.read_def_id(dcx))
-                        } else {
-                            None
-                        }))
-                    }),
-
-                    2 => this.read_uint().map(|idx| ty::MethodOrigin::Object(idx)),
-
-                    _ => panic!("..")
-                }
-            })
-        }).unwrap()
-    }
-
-
     fn read_ty<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>) -> Ty<'tcx> {
         // Note: regions types embed local node ids.  In principle, we
         // should translate these node ids into the new decode
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 2eb1767c928..29ab8de5e65 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -625,17 +625,13 @@ pub enum CustomCoerceUnsized {
     Struct(usize)
 }
 
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
 pub enum MethodOrigin {
     /// Inherent impl method call.
     Inherent,
 
     /// Statically dispatched trait method call.
-    /// The DefId is the impl for the trait from which the method comes.
-    /// This should only be used for certain linting/heuristic purposes
-    /// since there is no guarantee that this is Some in every situation
-    /// that it could/should be.
-    Trait(Option<ast::DefId>),
+    Trait,
 
     /// Dynamically dispatched trait method call.
     /// The usize is the index into the actual runtime vtable.
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 7d14bde8a92..d92a5c9c76e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -33,8 +33,10 @@
 
 use metadata::{csearch, decoder};
 use middle::def::*;
+use middle::infer;
 use middle::subst::Substs;
 use middle::ty::{self, Ty};
+use middle::traits;
 use middle::{def, pat_util, stability};
 use middle::const_eval::{eval_const_expr_partial, ConstVal};
 use middle::cfg;
@@ -1863,24 +1865,18 @@ impl LintPass for UnconditionalRecursion {
 
     fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl,
                 blk: &ast::Block, sp: Span, id: ast::NodeId) {
-        // FIXME(#23542) Replace with type ascription.
-        #![allow(trivial_casts)]
-
         type F = for<'tcx> fn(&ty::ctxt<'tcx>,
                               ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool;
 
-        let (name, checker) = match fn_kind {
-            visit::FkItemFn(name, _, _, _, _, _) => (name, id_refers_to_this_fn as F),
-            visit::FkMethod(name, _, _) => (name, id_refers_to_this_method as F),
+        let method = match fn_kind {
+            visit::FkItemFn(..) => None,
+            visit::FkMethod(..) => {
+                cx.tcx.impl_or_trait_item(local_def(id)).as_opt_method()
+            }
             // closures can't recur, so they don't matter.
             visit::FkFnBlock => return
         };
 
-        let impl_def_id = cx.tcx.impl_of_method(local_def(id))
-            .unwrap_or(local_def(ast::DUMMY_NODE_ID));
-        assert!(ast_util::is_local(impl_def_id));
-        let impl_node_id = impl_def_id.node;
-
         // Walk through this function (say `f`) looking to see if
         // every possible path references itself, i.e. the function is
         // called recursively unconditionally. This is done by trying
@@ -1931,7 +1927,17 @@ impl LintPass for UnconditionalRecursion {
             let node_id = cfg.graph.node_data(idx).id();
 
             // is this a recursive call?
-            if node_id != ast::DUMMY_NODE_ID && checker(cx.tcx, impl_node_id, id, name, node_id) {
+            let self_recursive = if node_id != ast::DUMMY_NODE_ID {
+                match method {
+                    Some(ref method) => {
+                        expr_refers_to_this_method(cx.tcx, method, node_id)
+                    }
+                    None => expr_refers_to_this_fn(cx.tcx, id, node_id)
+                }
+            } else {
+                false
+            };
+            if self_recursive {
                 self_call_spans.push(cx.tcx.map.span(node_id));
                 // this is a self call, so we shouldn't explore past
                 // this node in the CFG.
@@ -1970,15 +1976,12 @@ impl LintPass for UnconditionalRecursion {
         // all done
         return;
 
-        // Functions for identifying if the given NodeId `id`
-        // represents a call to the function `fn_id`/method
-        // `method_id`.
+        // Functions for identifying if the given Expr NodeId `id`
+        // represents a call to the function `fn_id`/method `method`.
 
-        fn id_refers_to_this_fn<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                      _: ast::NodeId,
-                                      fn_id: ast::NodeId,
-                                      _: ast::Ident,
-                                      id: ast::NodeId) -> bool {
+        fn expr_refers_to_this_fn(tcx: &ty::ctxt,
+                                  fn_id: ast::NodeId,
+                                  id: ast::NodeId) -> bool {
             match tcx.map.get(id) {
                 ast_map::NodeExpr(&ast::Expr { node: ast::ExprCall(ref callee, _), .. }) => {
                     tcx.def_map.borrow().get(&callee.id)
@@ -1988,59 +1991,68 @@ impl LintPass for UnconditionalRecursion {
             }
         }
 
-        // check if the method call `id` refers to method `method_id`
-        // (with name `method_name` contained in impl `impl_id`).
-        fn id_refers_to_this_method<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                          impl_id: ast::NodeId,
-                                          method_id: ast::NodeId,
-                                          method_name: ast::Ident,
-                                          id: ast::NodeId) -> bool {
-            let did = match tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)) {
-                None => return false,
-                Some(m) => match m.origin {
-                    // There's no way to know if a method call via a
-                    // vtable is recursion, so we assume it's not.
-                    ty::MethodOrigin::Object(_) => return false,
-
-                    // This `did` refers directly to the method definition.
-                    ty::MethodOrigin::Inherent => m.def_id,
-
-                    // The `impl ... for ...` of this method call
-                    // isn't known, e.g. it might be a default method
-                    // in a trait, so we get the def-id of the trait
-                    // method instead.
-                    ty::MethodOrigin::Trait(None) => {
-                        let on_self = m.substs.self_ty().map_or(false, |t| t.is_self());
-                        if !on_self {
-                            // we can only be recurring in a default
+        // Check if the method call `id` refers to method `method`.
+        fn expr_refers_to_this_method(tcx: &ty::ctxt,
+                                      method: &ty::Method,
+                                      id: ast::NodeId) -> bool {
+            let tables = tcx.tables.borrow();
+            let callee = match tables.method_map.get(&ty::MethodCall::expr(id)) {
+                Some(m) => m,
+                None => return false
+            };
+            let callee_item = tcx.impl_or_trait_item(callee.def_id);
+
+            match callee_item.container() {
+                // This is an inherent method, so the `def_id` refers
+                // directly to the method definition.
+                ty::ImplContainer(_) => {
+                    callee.def_id == method.def_id
+                }
+
+                // A trait method, from any number of possible sources.
+                // Attempt to select a concrete impl before checking.
+                ty::TraitContainer(trait_def_id) => {
+                    let trait_substs = callee.substs.clone().method_to_trait();
+                    let trait_substs = tcx.mk_substs(trait_substs);
+                    let trait_ref = ty::TraitRef::new(trait_def_id, trait_substs);
+                    let trait_ref = ty::Binder(trait_ref);
+                    let span = tcx.map.span(id);
+                    let obligation =
+                        traits::Obligation::new(traits::ObligationCause::misc(span, id),
+                                                trait_ref.to_poly_trait_predicate());
+
+                    let param_env = ty::ParameterEnvironment::for_item(tcx, method.def_id.node);
+                    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env), false);
+                    let mut selcx = traits::SelectionContext::new(&infcx);
+                    match selcx.select(&obligation) {
+                        // The method comes from a `T: Trait` bound.
+                        // If `T` is `Self`, then this call is inside
+                        // a default method definition.
+                        Ok(Some(traits::VtableParam(_))) => {
+                            let self_ty = callee.substs.self_ty();
+                            let on_self = self_ty.map_or(false, |t| t.is_self());
+                            // We can only be recurring in a default
                             // method if we're being called literally
                             // on the `Self` type.
-                            return false
+                            on_self && callee.def_id == method.def_id
                         }
-                        m.def_id
-                    }
-
 
-                    // The `impl` is known, so we check that with a
-                    // special case:
-                    ty::MethodOrigin::Trait(Some(impl_def_id)) => {
+                        // The `impl` is known, so we check that with a
+                        // special case:
+                        Ok(Some(traits::VtableImpl(vtable_impl))) => {
+                            let container = ty::ImplContainer(vtable_impl.impl_def_id);
+                            // It matches if it comes from the same impl,
+                            // and has the same method name.
+                            container == method.container
+                                && callee_item.name() == method.name
+                        }
 
-                        let name = match tcx.map.expect_expr(id).node {
-                            ast::ExprMethodCall(ref sp_ident, _, _) => sp_ident.node,
-                            _ => tcx.sess.span_bug(
-                                tcx.map.span(id),
-                                "non-method call expr behaving like a method call?")
-                        };
-                        // It matches if it comes from the same impl,
-                        // and has the same method name.
-                        return ast_util::is_local(impl_def_id)
-                            && impl_def_id.node == impl_id
-                            && method_name.name == name.name
+                        // There's no way to know if this call is
+                        // recursive, so we assume it's not.
+                        _ => return false
                     }
                 }
-            };
-
-            ast_util::is_local(did) && did.node == method_id
+            }
         }
     }
 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index cf0a24ed48c..dcbe4c35113 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -852,7 +852,7 @@ impl<'a, 'tcx> PrivacyVisitor<'a, 'tcx> {
             }
             // Trait methods are always all public. The only controlling factor
             // is whether the trait itself is accessible or not.
-            ty::MethodOrigin::Trait(_) | ty::MethodOrigin::Object(_) => {
+            ty::MethodOrigin::Trait | ty::MethodOrigin::Object(_) => {
                 let method = self.tcx.impl_or_trait_item(callee.def_id);
                 self.report_error(self.ensure_public(span, method.container().id(),
                                                      None, "source trait"));
diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs
index 2236eda5527..bac5ea494df 100644
--- a/src/librustc_trans/save/dump_csv.rs
+++ b/src/librustc_trans/save/dump_csv.rs
@@ -892,8 +892,7 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> {
             ty::MethodOrigin::Inherent => {
                 (Some(method_callee.def_id), None)
             }
-            ty::MethodOrigin::Trait(_) |
-            ty::MethodOrigin::Object(_) => {
+            ty::MethodOrigin::Trait | ty::MethodOrigin::Object(_) => {
                 (None, Some(method_callee.def_id))
             }
         };
diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs
index 3d727cf3347..2f415fcf7fd 100644
--- a/src/librustc_trans/trans/meth.rs
+++ b/src/librustc_trans/trans/meth.rs
@@ -128,7 +128,7 @@ pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             }
         }
 
-        ty::MethodOrigin::Trait(_) => {
+        ty::MethodOrigin::Trait => {
             let method_item = bcx.tcx().impl_or_trait_item(method_id);
             let trait_def_id = method_item.container().id();
 
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 5fa167c7929..26868c16bd8 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -255,7 +255,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                         &impl_polytype.substs,
                         &self.tcx().impl_trait_ref(impl_def_id).unwrap());
                 let substs = impl_trait_ref.substs.clone();
-                (substs, ty::MethodOrigin::Trait(Some(impl_def_id)))
+                (substs, ty::MethodOrigin::Trait)
             }
 
             probe::TraitPick => {
@@ -271,7 +271,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                                                                  &trait_def.generics,
                                                                  self.infcx().next_ty_var());
 
-                (substs, ty::MethodOrigin::Trait(None))
+                (substs, ty::MethodOrigin::Trait)
             }
 
             probe::WhereClausePick(ref poly_trait_ref) => {
@@ -279,7 +279,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
                 // those to convert from a poly-trait-ref to a trait-ref.
                 let trait_ref = self.replace_late_bound_regions_with_fresh_var(&*poly_trait_ref);
                 let substs = trait_ref.substs.clone();
-                (substs, ty::MethodOrigin::Trait(None))
+                (substs, ty::MethodOrigin::Trait)
             }
         }
     }
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 95e60a5fbe1..0ba09031724 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -307,7 +307,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     let callee = ty::MethodCallee {
         def_id: method_item.def_id(),
-        origin: ty::MethodOrigin::Trait(None),
+        origin: ty::MethodOrigin::Trait,
         ty: fty,
         substs: trait_ref.substs
     };