about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2018-12-02 00:29:06 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2018-12-15 00:41:28 +0200
commite25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1 (patch)
tree765b517e0b97ffd0764602da3fabf378203ed177
parentbe2bb4fa1d5788ba1d2df757090daf5fa75df4a2 (diff)
downloadrust-e25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1.tar.gz
rust-e25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1.zip
make autoderef steps a query
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/traits/query/method_autoderef.rs52
-rw-r--r--src/librustc/traits/query/mod.rs1
-rw-r--r--src/librustc/ty/query/config.rs6
-rw-r--r--src/librustc/ty/query/mod.rs5
-rw-r--r--src/librustc/ty/query/plumbing.rs1
-rw-r--r--src/librustc_typeck/check/method/mod.rs1
-rw-r--r--src/librustc_typeck/check/method/probe.rs91
8 files changed, 110 insertions, 48 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index f0c6196412a..61efdc82046 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -666,6 +666,7 @@ define_dep_nodes!( <'tcx>
     [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),
 
     [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
+    [] MethodAutoderefSteps(CanonicalTyGoal<'tcx>),
 
     [input] TargetFeaturesWhitelist,
 
diff --git a/src/librustc/traits/query/method_autoderef.rs b/src/librustc/traits/query/method_autoderef.rs
new file mode 100644
index 00000000000..e67497915d7
--- /dev/null
+++ b/src/librustc/traits/query/method_autoderef.rs
@@ -0,0 +1,52 @@
+// Copyright 2018 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc_data_structures::sync::Lrc;
+use infer::canonical::{Canonical, QueryResponse};
+use ty::Ty;
+
+#[derive(Debug)]
+pub struct CandidateStep<'tcx> {
+    pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+    pub autoderefs: usize,
+    // true if the type results from a dereference of a raw pointer.
+    // when assembling candidates, we include these steps, but not when
+    // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
+    // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
+    // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
+    pub from_unsafe_deref: bool,
+    pub unsize: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct MethodAutoderefStepsResult<'tcx> {
+    /// The valid autoderef steps that could be find.
+    pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
+    /// If Some(T), a type autoderef reported an error on.
+    pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>
+}
+
+#[derive(Debug)]
+pub struct MethodAutoderefBadTy<'tcx> {
+    pub reached_raw_pointer: bool,
+    pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
+}
+
+impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
+    reached_raw_pointer, ty
+});
+
+impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
+    steps, opt_bad_ty
+});
+
+impl_stable_hash_for!(struct CandidateStep<'tcx> {
+    self_ty, autoderefs, from_unsafe_deref, unsize
+});
diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs
index 13683d85444..b11cb737764 100644
--- a/src/librustc/traits/query/mod.rs
+++ b/src/librustc/traits/query/mod.rs
@@ -21,6 +21,7 @@ use ty::{self, Ty};
 
 pub mod dropck_outlives;
 pub mod evaluate_obligation;
+pub mod method_autoderef;
 pub mod normalize;
 pub mod normalize_erasing_regions;
 pub mod outlives_bounds;
diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs
index fd9143be679..b320c29dfad 100644
--- a/src/librustc/ty/query/config.rs
+++ b/src/librustc/ty/query/config.rs
@@ -827,6 +827,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_pre
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::method_autoderef_steps<'tcx> {
+    fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> {
+        format!("computing autoderef types for `{:?}`", goal).into()
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> {
     fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
         "looking up the whitelist of target features".into()
diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs
index 5cd06fb8a52..0e6810face5 100644
--- a/src/librustc/ty/query/mod.rs
+++ b/src/librustc/ty/query/mod.rs
@@ -40,6 +40,7 @@ use traits::query::{
     CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
     CanonicalTypeOpNormalizeGoal, NoSolution,
 };
+use traits::query::method_autoderef::MethodAutoderefStepsResult;
 use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
 use traits::query::normalize::NormalizationResult;
 use traits::query::outlives_bounds::OutlivesBound;
@@ -668,6 +669,10 @@ define_queries! { <'tcx>
 
         [] fn substitute_normalize_and_test_predicates:
             substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
+
+        [] fn method_autoderef_steps: MethodAutoderefSteps(
+            CanonicalTyGoal<'tcx>
+        ) -> MethodAutoderefStepsResult<'tcx>,
     },
 
     Other {
diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs
index 5f33d466c4a..3fac2db281b 100644
--- a/src/librustc/ty/query/plumbing.rs
+++ b/src/librustc/ty/query/plumbing.rs
@@ -1089,6 +1089,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::TypeOpNormalizePolyFnSig |
         DepKind::TypeOpNormalizeFnSig |
         DepKind::SubstituteNormalizeAndTestPredicates |
+        DepKind::MethodAutoderefSteps |
         DepKind::InstanceDefSizeEstimate |
         DepKind::ProgramClausesForEnv |
 
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 858d8c742df..5ecbfcd132c 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -39,6 +39,7 @@ use self::probe::{IsSuggestion, ProbeScope};
 
 pub fn provide(providers: &mut ty::query::Providers) {
     suggest::provide(providers);
+    probe::provide(providers);
 }
 
 #[derive(Clone, Copy, Debug)]
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 36aad42e26b..539c33cc14a 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -19,12 +19,16 @@ use hir::def_id::DefId;
 use hir::def::Def;
 use namespace::Namespace;
 
+use rustc_data_structures::sync::Lrc;
 use rustc::hir;
 use rustc::lint;
 use rustc::session::config::nightly_options;
 use rustc::ty::subst::{Subst, Substs};
 use rustc::traits::{self, ObligationCause};
-use rustc::ty::{self, ParamEnv, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
+use rustc::traits::query::{CanonicalTyGoal};
+use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult};
+use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy};
+use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
 use rustc::ty::GenericParamDefKind;
 use rustc::infer::type_variable::TypeVariableOrigin;
 use rustc::util::nodemap::FxHashSet;
@@ -34,7 +38,7 @@ use rustc::infer::canonical::{OriginalQueryValues};
 use rustc::middle::stability;
 use syntax::ast;
 use syntax::util::lev_distance::{lev_distance, find_best_match_for_name};
-use syntax_pos::{Span, symbol::Symbol};
+use syntax_pos::{DUMMY_SP, Span, symbol::Symbol};
 use std::iter;
 use std::mem;
 use std::ops::Deref;
@@ -59,7 +63,7 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
     /// This is the OriginalQueryValues for the steps queries
     /// that are answered in steps.
     orig_steps_var_values: OriginalQueryValues<'tcx>,
-    steps: Rc<Vec<CandidateStep<'gcx>>>,
+    steps: Lrc<Vec<CandidateStep<'gcx>>>,
 
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
@@ -91,19 +95,6 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> {
 }
 
 #[derive(Debug)]
-struct CandidateStep<'gcx> {
-    self_ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>,
-    autoderefs: usize,
-    // true if the type results from a dereference of a raw pointer.
-    // when assembling candidates, we include these steps, but not when
-    // picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
-    // `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
-    // `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
-    from_unsafe_deref: bool,
-    unsize: bool,
-}
-
-#[derive(Debug)]
 struct Candidate<'tcx> {
     xform_self_ty: Ty<'tcx>,
     xform_ret_ty: Option<Ty<'tcx>>,
@@ -260,11 +251,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     {
         let mut orig_values = OriginalQueryValues::default();
         let param_env_and_self_ty =
-            self.infcx.canonicalize_query(&(self.param_env, self_ty), &mut orig_values);
+            self.infcx.canonicalize_query(
+                &ParamEnvAnd {
+                    param_env: self.param_env,
+                    value: self_ty
+                }, &mut orig_values);
 
-        // FIXME: consider caching this "whole op" here.
         let steps = if mode == Mode::MethodCall {
-            create_steps_inner(self.tcx.global_tcx(), span, param_env_and_self_ty)
+            self.tcx.method_autoderef_steps(param_env_and_self_ty)
         } else {
             self.infcx.probe(|_| {
                 // Mode::Path - the deref steps is "trivial". This turns
@@ -273,18 +267,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // special handling for this "trivial case" is a good idea.
 
                 let infcx = &self.infcx;
-                let ((_, self_ty), canonical_inference_vars) =
+                let (ParamEnvAnd {
+                    param_env: _,
+                    value: self_ty
+                }, canonical_inference_vars) =
                     infcx.instantiate_canonical_with_fresh_inference_vars(
                         span, &param_env_and_self_ty);
-                debug!("param_env_and_self_ty={:?} self_ty={:?}", param_env_and_self_ty, self_ty);
-                CreateStepsResult {
-                    steps: vec![CandidateStep {
+                debug!("probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}",
+                       param_env_and_self_ty, self_ty);
+                MethodAutoderefStepsResult {
+                    steps: Lrc::new(vec![CandidateStep {
                         self_ty: self.make_query_response_with_obligations_pending(
                             canonical_inference_vars, self_ty),
                         autoderefs: 0,
                         from_unsafe_deref: false,
                         unsize: false,
-                    }],
+                    }]),
                     opt_bad_ty: None
                 }
             })
@@ -292,11 +290,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
         // If we encountered an `_` type or an error type during autoderef, this is
         // ambiguous.
-        if let Some(CreateStepsBadTy { reached_raw_pointer, ty }) = &steps.opt_bad_ty {
+        if let Some(autoderef_bad_ty) = &steps.opt_bad_ty {
+            let MethodAutoderefBadTy { reached_raw_pointer, ref ty } = **autoderef_bad_ty;
             if is_suggestion.0 {
                 // Ambiguity was encountered during a suggestion. Just keep going.
                 debug!("ProbeContext: encountered ambiguity in suggestion");
-            } else if *reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
+            } else if reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
                 // this case used to be allowed by the compiler,
                 // so we do a future-compat lint here for the 2015 edition
                 // (see https://github.com/rust-lang/rust/issues/46906)
@@ -337,7 +336,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.probe(|_| {
             let mut probe_cx = ProbeContext::new(
                 self, span, mode, method_name, return_type, orig_values,
-                Rc::new(steps.steps), is_suggestion,
+                steps.steps, is_suggestion,
             );
 
             probe_cx.assemble_inherent_candidates();
@@ -352,27 +351,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
     }
 }
 
-#[derive(Debug)]
-struct CreateStepsResult<'gcx> {
-    steps: Vec<CandidateStep<'gcx>>,
-    opt_bad_ty: Option<CreateStepsBadTy<'gcx>>
-}
-
-#[derive(Debug)]
-struct CreateStepsBadTy<'gcx> {
-    reached_raw_pointer: bool,
-    ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>,
+pub fn provide(providers: &mut ty::query::Providers) {
+    providers.method_autoderef_steps = method_autoderef_steps;
 }
 
-fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
-                                      span: Span,
-                                      pe_and_self_ty: Canonical<'gcx, (ParamEnv<'gcx>, Ty<'gcx>)>)
-                                      -> CreateStepsResult<'gcx>
+fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
+                                          goal: CanonicalTyGoal<'tcx>)
+                                          -> MethodAutoderefStepsResult<'gcx>
 {
-    tcx.infer_ctxt().enter(|ref infcx| {
-        let ((param_env, self_ty), inference_vars) =
-            infcx.instantiate_canonical_with_fresh_inference_vars(span, &pe_and_self_ty);
-        let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, span, self_ty)
+    debug!("method_autoderef_steps({:?})", goal);
+
+    tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
+        let ParamEnvAnd { param_env, value: self_ty } = goal;
+
+        let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty)
             .include_raw_pointers();
         let mut reached_raw_pointer = false;
         let mut steps: Vec<_> = autoderef.by_ref()
@@ -396,7 +388,7 @@ fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
         let opt_bad_ty = match final_ty.sty {
             ty::Infer(ty::TyVar(_)) |
             ty::Error => {
-                Some(CreateStepsBadTy {
+                Some(MethodAutoderefBadTy {
                     reached_raw_pointer,
                     ty: infcx.make_query_response_with_obligations_pending(
                         inference_vars, final_ty)
@@ -420,9 +412,12 @@ fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
             _ => None
         };
 
-        debug!("create_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
+        debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
 
-        CreateStepsResult { steps, opt_bad_ty }
+        MethodAutoderefStepsResult {
+            steps: Lrc::new(steps),
+            opt_bad_ty: opt_bad_ty.map(Lrc::new)
+        }
     })
 }