diff options
| author | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2018-12-02 00:29:06 +0200 |
|---|---|---|
| committer | Ariel Ben-Yehuda <ariel.byd@gmail.com> | 2018-12-15 00:41:28 +0200 |
| commit | e25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1 (patch) | |
| tree | 765b517e0b97ffd0764602da3fabf378203ed177 | |
| parent | be2bb4fa1d5788ba1d2df757090daf5fa75df4a2 (diff) | |
| download | rust-e25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1.tar.gz rust-e25e2e0600e13022ad30c1f6c7ddfdfd58e9efa1.zip | |
make autoderef steps a query
| -rw-r--r-- | src/librustc/dep_graph/dep_node.rs | 1 | ||||
| -rw-r--r-- | src/librustc/traits/query/method_autoderef.rs | 52 | ||||
| -rw-r--r-- | src/librustc/traits/query/mod.rs | 1 | ||||
| -rw-r--r-- | src/librustc/ty/query/config.rs | 6 | ||||
| -rw-r--r-- | src/librustc/ty/query/mod.rs | 5 | ||||
| -rw-r--r-- | src/librustc/ty/query/plumbing.rs | 1 | ||||
| -rw-r--r-- | src/librustc_typeck/check/method/mod.rs | 1 | ||||
| -rw-r--r-- | src/librustc_typeck/check/method/probe.rs | 91 |
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, ¶m_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) + } }) } |
