make autoderef steps a query
This commit is contained in:
parent
be2bb4fa1d
commit
e25e2e0600
8 changed files with 110 additions and 48 deletions
|
@ -666,6 +666,7 @@ define_dep_nodes!( <'tcx>
|
|||
[] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),
|
||||
|
||||
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
|
||||
[] MethodAutoderefSteps(CanonicalTyGoal<'tcx>),
|
||||
|
||||
[input] TargetFeaturesWhitelist,
|
||||
|
||||
|
|
52
src/librustc/traits/query/method_autoderef.rs
Normal file
52
src/librustc/traits/query/method_autoderef.rs
Normal file
|
@ -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
|
||||
});
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 |
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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>>,
|
||||
|
@ -90,19 +94,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>,
|
||||
|
@ -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>>
|
||||
pub fn provide(providers: &mut ty::query::Providers) {
|
||||
providers.method_autoderef_steps = method_autoderef_steps;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CreateStepsBadTy<'gcx> {
|
||||
reached_raw_pointer: bool,
|
||||
ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>,
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue