Skip to content

Commit e25e2e0

Browse files
committed
make autoderef steps a query
1 parent be2bb4f commit e25e2e0

File tree

8 files changed

+110
-48
lines changed

8 files changed

+110
-48
lines changed

src/librustc/dep_graph/dep_node.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,7 @@ define_dep_nodes!( <'tcx>
666666
[] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),
667667

668668
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
669+
[] MethodAutoderefSteps(CanonicalTyGoal<'tcx>),
669670

670671
[input] TargetFeaturesWhitelist,
671672

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc_data_structures::sync::Lrc;
12+
use infer::canonical::{Canonical, QueryResponse};
13+
use ty::Ty;
14+
15+
#[derive(Debug)]
16+
pub struct CandidateStep<'tcx> {
17+
pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
18+
pub autoderefs: usize,
19+
// true if the type results from a dereference of a raw pointer.
20+
// when assembling candidates, we include these steps, but not when
21+
// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
22+
// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
23+
// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
24+
pub from_unsafe_deref: bool,
25+
pub unsize: bool,
26+
}
27+
28+
#[derive(Clone, Debug)]
29+
pub struct MethodAutoderefStepsResult<'tcx> {
30+
/// The valid autoderef steps that could be find.
31+
pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
32+
/// If Some(T), a type autoderef reported an error on.
33+
pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>
34+
}
35+
36+
#[derive(Debug)]
37+
pub struct MethodAutoderefBadTy<'tcx> {
38+
pub reached_raw_pointer: bool,
39+
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
40+
}
41+
42+
impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
43+
reached_raw_pointer, ty
44+
});
45+
46+
impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
47+
steps, opt_bad_ty
48+
});
49+
50+
impl_stable_hash_for!(struct CandidateStep<'tcx> {
51+
self_ty, autoderefs, from_unsafe_deref, unsize
52+
});

src/librustc/traits/query/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use ty::{self, Ty};
2121

2222
pub mod dropck_outlives;
2323
pub mod evaluate_obligation;
24+
pub mod method_autoderef;
2425
pub mod normalize;
2526
pub mod normalize_erasing_regions;
2627
pub mod outlives_bounds;

src/librustc/ty/query/config.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::substitute_normalize_and_test_pre
827827
}
828828
}
829829

830+
impl<'tcx> QueryDescription<'tcx> for queries::method_autoderef_steps<'tcx> {
831+
fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTyGoal<'tcx>) -> Cow<'static, str> {
832+
format!("computing autoderef types for `{:?}`", goal).into()
833+
}
834+
}
835+
830836
impl<'tcx> QueryDescription<'tcx> for queries::target_features_whitelist<'tcx> {
831837
fn describe(_tcx: TyCtxt<'_, '_, '_>, _: CrateNum) -> Cow<'static, str> {
832838
"looking up the whitelist of target features".into()

src/librustc/ty/query/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use traits::query::{
4040
CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal,
4141
CanonicalTypeOpNormalizeGoal, NoSolution,
4242
};
43+
use traits::query::method_autoderef::MethodAutoderefStepsResult;
4344
use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult};
4445
use traits::query::normalize::NormalizationResult;
4546
use traits::query::outlives_bounds::OutlivesBound;
@@ -668,6 +669,10 @@ define_queries! { <'tcx>
668669

669670
[] fn substitute_normalize_and_test_predicates:
670671
substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool,
672+
673+
[] fn method_autoderef_steps: MethodAutoderefSteps(
674+
CanonicalTyGoal<'tcx>
675+
) -> MethodAutoderefStepsResult<'tcx>,
671676
},
672677

673678
Other {

src/librustc/ty/query/plumbing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
10891089
DepKind::TypeOpNormalizePolyFnSig |
10901090
DepKind::TypeOpNormalizeFnSig |
10911091
DepKind::SubstituteNormalizeAndTestPredicates |
1092+
DepKind::MethodAutoderefSteps |
10921093
DepKind::InstanceDefSizeEstimate |
10931094
DepKind::ProgramClausesForEnv |
10941095

src/librustc_typeck/check/method/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ use self::probe::{IsSuggestion, ProbeScope};
3939

4040
pub fn provide(providers: &mut ty::query::Providers) {
4141
suggest::provide(providers);
42+
probe::provide(providers);
4243
}
4344

4445
#[derive(Clone, Copy, Debug)]

src/librustc_typeck/check/method/probe.rs

Lines changed: 43 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@ use hir::def_id::DefId;
1919
use hir::def::Def;
2020
use namespace::Namespace;
2121

22+
use rustc_data_structures::sync::Lrc;
2223
use rustc::hir;
2324
use rustc::lint;
2425
use rustc::session::config::nightly_options;
2526
use rustc::ty::subst::{Subst, Substs};
2627
use rustc::traits::{self, ObligationCause};
27-
use rustc::ty::{self, ParamEnv, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
28+
use rustc::traits::query::{CanonicalTyGoal};
29+
use rustc::traits::query::method_autoderef::{CandidateStep, MethodAutoderefStepsResult};
30+
use rustc::traits::query::method_autoderef::{MethodAutoderefBadTy};
31+
use rustc::ty::{self, ParamEnvAnd, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TraitRef, TypeFoldable};
2832
use rustc::ty::GenericParamDefKind;
2933
use rustc::infer::type_variable::TypeVariableOrigin;
3034
use rustc::util::nodemap::FxHashSet;
@@ -34,7 +38,7 @@ use rustc::infer::canonical::{OriginalQueryValues};
3438
use rustc::middle::stability;
3539
use syntax::ast;
3640
use syntax::util::lev_distance::{lev_distance, find_best_match_for_name};
37-
use syntax_pos::{Span, symbol::Symbol};
41+
use syntax_pos::{DUMMY_SP, Span, symbol::Symbol};
3842
use std::iter;
3943
use std::mem;
4044
use std::ops::Deref;
@@ -59,7 +63,7 @@ struct ProbeContext<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
5963
/// This is the OriginalQueryValues for the steps queries
6064
/// that are answered in steps.
6165
orig_steps_var_values: OriginalQueryValues<'tcx>,
62-
steps: Rc<Vec<CandidateStep<'gcx>>>,
66+
steps: Lrc<Vec<CandidateStep<'gcx>>>,
6367

6468
inherent_candidates: Vec<Candidate<'tcx>>,
6569
extension_candidates: Vec<Candidate<'tcx>>,
@@ -90,19 +94,6 @@ impl<'a, 'gcx, 'tcx> Deref for ProbeContext<'a, 'gcx, 'tcx> {
9094
}
9195
}
9296

93-
#[derive(Debug)]
94-
struct CandidateStep<'gcx> {
95-
self_ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>,
96-
autoderefs: usize,
97-
// true if the type results from a dereference of a raw pointer.
98-
// when assembling candidates, we include these steps, but not when
99-
// picking methods. This so that if we have `foo: *const Foo` and `Foo` has methods
100-
// `fn by_raw_ptr(self: *const Self)` and `fn by_ref(&self)`, then
101-
// `foo.by_raw_ptr()` will work and `foo.by_ref()` won't.
102-
from_unsafe_deref: bool,
103-
unsize: bool,
104-
}
105-
10697
#[derive(Debug)]
10798
struct Candidate<'tcx> {
10899
xform_self_ty: Ty<'tcx>,
@@ -260,11 +251,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
260251
{
261252
let mut orig_values = OriginalQueryValues::default();
262253
let param_env_and_self_ty =
263-
self.infcx.canonicalize_query(&(self.param_env, self_ty), &mut orig_values);
254+
self.infcx.canonicalize_query(
255+
&ParamEnvAnd {
256+
param_env: self.param_env,
257+
value: self_ty
258+
}, &mut orig_values);
264259

265-
// FIXME: consider caching this "whole op" here.
266260
let steps = if mode == Mode::MethodCall {
267-
create_steps_inner(self.tcx.global_tcx(), span, param_env_and_self_ty)
261+
self.tcx.method_autoderef_steps(param_env_and_self_ty)
268262
} else {
269263
self.infcx.probe(|_| {
270264
// Mode::Path - the deref steps is "trivial". This turns
@@ -273,30 +267,35 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
273267
// special handling for this "trivial case" is a good idea.
274268

275269
let infcx = &self.infcx;
276-
let ((_, self_ty), canonical_inference_vars) =
270+
let (ParamEnvAnd {
271+
param_env: _,
272+
value: self_ty
273+
}, canonical_inference_vars) =
277274
infcx.instantiate_canonical_with_fresh_inference_vars(
278275
span, &param_env_and_self_ty);
279-
debug!("param_env_and_self_ty={:?} self_ty={:?}", param_env_and_self_ty, self_ty);
280-
CreateStepsResult {
281-
steps: vec![CandidateStep {
276+
debug!("probe_op: Mode::Path, param_env_and_self_ty={:?} self_ty={:?}",
277+
param_env_and_self_ty, self_ty);
278+
MethodAutoderefStepsResult {
279+
steps: Lrc::new(vec![CandidateStep {
282280
self_ty: self.make_query_response_with_obligations_pending(
283281
canonical_inference_vars, self_ty),
284282
autoderefs: 0,
285283
from_unsafe_deref: false,
286284
unsize: false,
287-
}],
285+
}]),
288286
opt_bad_ty: None
289287
}
290288
})
291289
};
292290

293291
// If we encountered an `_` type or an error type during autoderef, this is
294292
// ambiguous.
295-
if let Some(CreateStepsBadTy { reached_raw_pointer, ty }) = &steps.opt_bad_ty {
293+
if let Some(autoderef_bad_ty) = &steps.opt_bad_ty {
294+
let MethodAutoderefBadTy { reached_raw_pointer, ref ty } = **autoderef_bad_ty;
296295
if is_suggestion.0 {
297296
// Ambiguity was encountered during a suggestion. Just keep going.
298297
debug!("ProbeContext: encountered ambiguity in suggestion");
299-
} else if *reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
298+
} else if reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
300299
// this case used to be allowed by the compiler,
301300
// so we do a future-compat lint here for the 2015 edition
302301
// (see https://github.com/rust-lang/rust/issues/46906)
@@ -337,7 +336,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
337336
self.probe(|_| {
338337
let mut probe_cx = ProbeContext::new(
339338
self, span, mode, method_name, return_type, orig_values,
340-
Rc::new(steps.steps), is_suggestion,
339+
steps.steps, is_suggestion,
341340
);
342341

343342
probe_cx.assemble_inherent_candidates();
@@ -352,27 +351,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
352351
}
353352
}
354353

355-
#[derive(Debug)]
356-
struct CreateStepsResult<'gcx> {
357-
steps: Vec<CandidateStep<'gcx>>,
358-
opt_bad_ty: Option<CreateStepsBadTy<'gcx>>
359-
}
360-
361-
#[derive(Debug)]
362-
struct CreateStepsBadTy<'gcx> {
363-
reached_raw_pointer: bool,
364-
ty: Canonical<'gcx, QueryResponse<'gcx, Ty<'gcx>>>,
354+
pub fn provide(providers: &mut ty::query::Providers) {
355+
providers.method_autoderef_steps = method_autoderef_steps;
365356
}
366357

367-
fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
368-
span: Span,
369-
pe_and_self_ty: Canonical<'gcx, (ParamEnv<'gcx>, Ty<'gcx>)>)
370-
-> CreateStepsResult<'gcx>
358+
fn method_autoderef_steps<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
359+
goal: CanonicalTyGoal<'tcx>)
360+
-> MethodAutoderefStepsResult<'gcx>
371361
{
372-
tcx.infer_ctxt().enter(|ref infcx| {
373-
let ((param_env, self_ty), inference_vars) =
374-
infcx.instantiate_canonical_with_fresh_inference_vars(span, &pe_and_self_ty);
375-
let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, span, self_ty)
362+
debug!("method_autoderef_steps({:?})", goal);
363+
364+
tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| {
365+
let ParamEnvAnd { param_env, value: self_ty } = goal;
366+
367+
let mut autoderef = Autoderef::new(infcx, param_env, ast::DUMMY_NODE_ID, DUMMY_SP, self_ty)
376368
.include_raw_pointers();
377369
let mut reached_raw_pointer = false;
378370
let mut steps: Vec<_> = autoderef.by_ref()
@@ -396,7 +388,7 @@ fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
396388
let opt_bad_ty = match final_ty.sty {
397389
ty::Infer(ty::TyVar(_)) |
398390
ty::Error => {
399-
Some(CreateStepsBadTy {
391+
Some(MethodAutoderefBadTy {
400392
reached_raw_pointer,
401393
ty: infcx.make_query_response_with_obligations_pending(
402394
inference_vars, final_ty)
@@ -420,9 +412,12 @@ fn create_steps_inner<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
420412
_ => None
421413
};
422414

423-
debug!("create_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
415+
debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
424416

425-
CreateStepsResult { steps, opt_bad_ty }
417+
MethodAutoderefStepsResult {
418+
steps: Lrc::new(steps),
419+
opt_bad_ty: opt_bad_ty.map(Lrc::new)
420+
}
426421
})
427422
}
428423

0 commit comments

Comments
 (0)