Skip to content

Commit daa8792

Browse files
committed
Auto merge of #54252 - arielb1:deref-query, r=nikomatsakis
process nested obligations in autoderef Fixes #53843. r? @nikomatsakis
2 parents 790f4c5 + b4db387 commit daa8792

File tree

18 files changed

+488
-192
lines changed

18 files changed

+488
-192
lines changed

src/librustc/dep_graph/dep_node.rs

+1
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ define_dep_nodes!( <'tcx>
669669
[] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>),
670670

671671
[] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
672+
[] MethodAutoderefSteps(CanonicalTyGoal<'tcx>),
672673

673674
[input] TargetFeaturesWhitelist,
674675

src/librustc/infer/canonical/query_response.rs

+25
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,31 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> {
117117
Ok(Lrc::new(canonical_result))
118118
}
119119

120+
/// A version of `make_canonicalized_query_response` that does
121+
/// not pack in obligations, for contexts that want to drop
122+
/// pending obligations instead of treating them as an ambiguity (e.g.
123+
/// typeck "probing" contexts).
124+
///
125+
/// If you DO want to keep track of pending obligations (which
126+
/// include all region obligations, so this includes all cases
127+
/// that care about regions) with this function, you have to
128+
/// do it yourself, by e.g. having them be a part of the answer.
129+
pub fn make_query_response_ignoring_pending_obligations<T>(
130+
&self,
131+
inference_vars: CanonicalVarValues<'tcx>,
132+
answer: T
133+
) -> Canonical<'gcx, QueryResponse<'gcx, <T as Lift<'gcx>>::Lifted>>
134+
where
135+
T: Debug + Lift<'gcx> + TypeFoldable<'tcx>,
136+
{
137+
self.canonicalize_response(&QueryResponse {
138+
var_values: inference_vars,
139+
region_constraints: vec![],
140+
certainty: Certainty::Proven, // Ambiguities are OK!
141+
value: answer,
142+
})
143+
}
144+
120145
/// Helper for `make_canonicalized_query_response` that does
121146
/// everything up until the final canonicalization.
122147
fn make_query_response<T>(

src/librustc/traits/fulfill.rs

+23-3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ pub struct FulfillmentContext<'tcx> {
6161
// type-lives-for-region constraints, and because the type
6262
// is well-formed, the constraints should hold.
6363
register_region_obligations: bool,
64+
// Is it OK to register obligations into this infcx inside
65+
// an infcx snapshot?
66+
//
67+
// The "primary fulfillment" in many cases in typeck lives
68+
// outside of any snapshot, so any use of it inside a snapshot
69+
// will lead to trouble and therefore is checked against, but
70+
// other fulfillment contexts sometimes do live inside of
71+
// a snapshot (they don't *straddle* a snapshot, so there
72+
// is no trouble there).
73+
usable_in_snapshot: bool
6474
}
6575

6676
#[derive(Clone, Debug)]
@@ -74,14 +84,24 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
7484
pub fn new() -> FulfillmentContext<'tcx> {
7585
FulfillmentContext {
7686
predicates: ObligationForest::new(),
77-
register_region_obligations: true
87+
register_region_obligations: true,
88+
usable_in_snapshot: false,
89+
}
90+
}
91+
92+
pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
93+
FulfillmentContext {
94+
predicates: ObligationForest::new(),
95+
register_region_obligations: true,
96+
usable_in_snapshot: true,
7897
}
7998
}
8099

81100
pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
82101
FulfillmentContext {
83102
predicates: ObligationForest::new(),
84-
register_region_obligations: false
103+
register_region_obligations: false,
104+
usable_in_snapshot: false
85105
}
86106
}
87107

@@ -195,7 +215,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
195215

196216
debug!("register_predicate_obligation(obligation={:?})", obligation);
197217

198-
assert!(!infcx.is_in_snapshot());
218+
assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
199219

200220
self.predicates.register_obligation(PendingPredicateObligation {
201221
obligation,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
/// If `true`, `steps` has been truncated due to reaching the
35+
/// recursion limit.
36+
pub reached_recursion_limit: bool,
37+
}
38+
39+
#[derive(Debug)]
40+
pub struct MethodAutoderefBadTy<'tcx> {
41+
pub reached_raw_pointer: bool,
42+
pub ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>,
43+
}
44+
45+
impl_stable_hash_for!(struct MethodAutoderefBadTy<'tcx> {
46+
reached_raw_pointer, ty
47+
});
48+
49+
impl_stable_hash_for!(struct MethodAutoderefStepsResult<'tcx> {
50+
reached_recursion_limit, steps, opt_bad_ty
51+
});
52+
53+
impl_stable_hash_for!(struct CandidateStep<'tcx> {
54+
self_ty, autoderefs, from_unsafe_deref, unsize
55+
});

src/librustc/traits/query/mod.rs

+1
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

+6
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

+5
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

+1
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
11161116
DepKind::TypeOpNormalizePolyFnSig |
11171117
DepKind::TypeOpNormalizeFnSig |
11181118
DepKind::SubstituteNormalizeAndTestPredicates |
1119+
DepKind::MethodAutoderefSteps |
11191120
DepKind::InstanceDefSizeEstimate |
11201121
DepKind::ProgramClausesForEnv |
11211122

0 commit comments

Comments
 (0)