Skip to content

Commit 0b9d15f

Browse files
committed
Auto merge of #54252 - arielb1:deref-query, r=<try>
process nested obligations in autoderef This is a hack-fix to #53843, but I am worried it might break things because it makes the "inference pollution" problem worse. I need to do the "autoderef querification" thing somehow to solve t. Fixes #53843 (but introduces a bug that someone might notice). r? @nikomatsakis
2 parents 2287a7a + 88f7e57 commit 0b9d15f

File tree

10 files changed

+334
-162
lines changed

10 files changed

+334
-162
lines changed

src/librustc/traits/fulfill.rs

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

6878
#[derive(Clone, Debug)]
@@ -76,14 +86,24 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
7686
pub fn new() -> FulfillmentContext<'tcx> {
7787
FulfillmentContext {
7888
predicates: ObligationForest::new(),
79-
register_region_obligations: true
89+
register_region_obligations: true,
90+
usable_in_snapshot: false,
91+
}
92+
}
93+
94+
pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
95+
FulfillmentContext {
96+
predicates: ObligationForest::new(),
97+
register_region_obligations: true,
98+
usable_in_snapshot: true,
8099
}
81100
}
82101

83102
pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
84103
FulfillmentContext {
85104
predicates: ObligationForest::new(),
86-
register_region_obligations: false
105+
register_region_obligations: false,
106+
usable_in_snapshot: false
87107
}
88108
}
89109

@@ -197,7 +217,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
197217

198218
debug!("register_predicate_obligation(obligation={:?})", obligation);
199219

200-
assert!(!infcx.is_in_snapshot());
220+
assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
201221

202222
self.predicates.register_obligation(PendingPredicateObligation {
203223
obligation,

src/librustc_typeck/check/autoderef.rs

+64-44
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,18 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
use astconv::AstConv;
12-
1311
use super::{FnCtxt, PlaceOp, Needs};
1412
use super::method::MethodCallee;
1513

16-
use rustc::infer::InferOk;
14+
use rustc::infer::{InferCtxt, InferOk};
1715
use rustc::session::DiagnosticMessageId;
18-
use rustc::traits;
16+
use rustc::traits::{self, TraitEngine};
1917
use rustc::ty::{self, Ty, TraitRef};
2018
use rustc::ty::{ToPredicate, TypeFoldable};
2119
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
2220

2321
use syntax_pos::Span;
24-
use syntax::ast::Ident;
22+
use syntax::ast::{self, Ident};
2523

2624
use std::iter;
2725

@@ -32,7 +30,9 @@ enum AutoderefKind {
3230
}
3331

3432
pub struct Autoderef<'a, 'gcx: 'tcx, 'tcx: 'a> {
35-
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
33+
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
34+
body_id: ast::NodeId,
35+
param_env: ty::ParamEnv<'tcx>,
3636
steps: Vec<(Ty<'tcx>, AutoderefKind)>,
3737
cur_ty: Ty<'tcx>,
3838
obligations: Vec<traits::PredicateObligation<'tcx>>,
@@ -45,7 +45,7 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
4545
type Item = (Ty<'tcx>, usize);
4646

4747
fn next(&mut self) -> Option<Self::Item> {
48-
let tcx = self.fcx.tcx;
48+
let tcx = self.infcx.tcx;
4949

5050
debug!("autoderef: steps={:?}, cur_ty={:?}",
5151
self.steps,
@@ -107,74 +107,103 @@ impl<'a, 'gcx, 'tcx> Iterator for Autoderef<'a, 'gcx, 'tcx> {
107107
}
108108

109109
impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
110+
pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
111+
param_env: ty::ParamEnv<'tcx>,
112+
body_id: ast::NodeId,
113+
span: Span,
114+
base_ty: Ty<'tcx>)
115+
-> Autoderef<'a, 'gcx, 'tcx>
116+
{
117+
Autoderef {
118+
infcx,
119+
body_id,
120+
param_env,
121+
steps: vec![],
122+
cur_ty: infcx.resolve_type_vars_if_possible(&base_ty),
123+
obligations: vec![],
124+
at_start: true,
125+
include_raw_pointers: false,
126+
span,
127+
}
128+
}
129+
110130
fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
111131
debug!("overloaded_deref_ty({:?})", ty);
112132

113-
let tcx = self.fcx.tcx();
133+
let tcx = self.infcx.tcx;
114134

115135
// <cur_ty as Deref>
116136
let trait_ref = TraitRef {
117137
def_id: tcx.lang_items().deref_trait()?,
118138
substs: tcx.mk_substs_trait(self.cur_ty, &[]),
119139
};
120140

121-
let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
141+
let cause = traits::ObligationCause::misc(self.span, self.body_id);
122142

123143
let obligation = traits::Obligation::new(cause.clone(),
124-
self.fcx.param_env,
144+
self.param_env,
125145
trait_ref.to_predicate());
126-
if !self.fcx.predicate_may_hold(&obligation) {
146+
if !self.infcx.predicate_may_hold(&obligation) {
127147
debug!("overloaded_deref_ty: cannot match obligation");
128148
return None;
129149
}
130150

131-
let mut selcx = traits::SelectionContext::new(self.fcx);
132-
let normalized_ty = traits::normalize_projection_type(&mut selcx,
133-
self.fcx.param_env,
134-
ty::ProjectionTy::from_ref_and_name(
135-
tcx,
136-
trait_ref,
137-
Ident::from_str("Target"),
138-
),
139-
cause,
140-
0,
141-
&mut self.obligations);
142-
143-
debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty);
144-
145-
Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty))
151+
let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
152+
let normalized_ty = fulfillcx.normalize_projection_type(
153+
&self.infcx,
154+
self.param_env,
155+
ty::ProjectionTy::from_ref_and_name(
156+
tcx,
157+
trait_ref,
158+
Ident::from_str("Target"),
159+
),
160+
cause);
161+
if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
162+
// This shouldn't happen, except for evaluate/fulfill mismatches,
163+
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
164+
// by design).
165+
debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling",
166+
e);
167+
return None;
168+
}
169+
let obligations = fulfillcx.pending_obligations();
170+
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})",
171+
ty, normalized_ty, obligations);
172+
self.obligations.extend(obligations);
173+
174+
Some(self.infcx.resolve_type_vars_if_possible(&normalized_ty))
146175
}
147176

148177
/// Returns the final type, generating an error if it is an
149178
/// unresolved inference variable.
150-
pub fn unambiguous_final_ty(&self) -> Ty<'tcx> {
151-
self.fcx.structurally_resolved_type(self.span, self.cur_ty)
179+
pub fn unambiguous_final_ty(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
180+
fcx.structurally_resolved_type(self.span, self.cur_ty)
152181
}
153182

154183
/// Returns the final type we ended up with, which may well be an
155184
/// inference variable (we will resolve it first, if possible).
156185
pub fn maybe_ambiguous_final_ty(&self) -> Ty<'tcx> {
157-
self.fcx.resolve_type_vars_if_possible(&self.cur_ty)
186+
self.infcx.resolve_type_vars_if_possible(&self.cur_ty)
158187
}
159188

160189
pub fn step_count(&self) -> usize {
161190
self.steps.len()
162191
}
163192

164193
/// Returns the adjustment steps.
165-
pub fn adjust_steps(&self, needs: Needs)
194+
pub fn adjust_steps(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs)
166195
-> Vec<Adjustment<'tcx>> {
167-
self.fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(needs))
196+
fcx.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(fcx, needs))
168197
}
169198

170-
pub fn adjust_steps_as_infer_ok(&self, needs: Needs)
199+
pub fn adjust_steps_as_infer_ok(&self, fcx: &FnCtxt<'a, 'gcx, 'tcx>, needs: Needs)
171200
-> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
172201
let mut obligations = vec![];
173202
let targets = self.steps.iter().skip(1).map(|&(ty, _)| ty)
174203
.chain(iter::once(self.cur_ty));
175204
let steps: Vec<_> = self.steps.iter().map(|&(source, kind)| {
176205
if let AutoderefKind::Overloaded = kind {
177-
self.fcx.try_overloaded_deref(self.span, source, needs)
206+
fcx.try_overloaded_deref(self.span, source, needs)
178207
.and_then(|InferOk { value: method, obligations: o }| {
179208
obligations.extend(o);
180209
if let ty::Ref(region, _, mutbl) = method.sig.output().sty {
@@ -211,8 +240,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
211240
self
212241
}
213242

214-
pub fn finalize(self) {
215-
let fcx = self.fcx;
243+
pub fn finalize(self, fcx: &FnCtxt<'a, 'gcx, 'tcx>) {
216244
fcx.register_predicates(self.into_obligations());
217245
}
218246

@@ -223,15 +251,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
223251

224252
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
225253
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'gcx, 'tcx> {
226-
Autoderef {
227-
fcx: self,
228-
steps: vec![],
229-
cur_ty: self.resolve_type_vars_if_possible(&base_ty),
230-
obligations: vec![],
231-
at_start: true,
232-
include_raw_pointers: false,
233-
span,
234-
}
254+
Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
235255
}
236256

237257
pub fn try_overloaded_deref(&self,

src/librustc_typeck/check/callee.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
5757
while result.is_none() && autoderef.next().is_some() {
5858
result = self.try_overloaded_call_step(call_expr, callee_expr, &autoderef);
5959
}
60-
autoderef.finalize();
60+
autoderef.finalize(self);
6161

6262
let output = match result {
6363
None => {
@@ -89,15 +89,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
8989
callee_expr: &'gcx hir::Expr,
9090
autoderef: &Autoderef<'a, 'gcx, 'tcx>)
9191
-> Option<CallStep<'tcx>> {
92-
let adjusted_ty = autoderef.unambiguous_final_ty();
92+
let adjusted_ty = autoderef.unambiguous_final_ty(self);
9393
debug!("try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
9494
call_expr,
9595
adjusted_ty);
9696

9797
// If the callee is a bare function or a closure, then we're all set.
9898
match adjusted_ty.sty {
9999
ty::FnDef(..) | ty::FnPtr(_) => {
100-
let adjustments = autoderef.adjust_steps(Needs::None);
100+
let adjustments = autoderef.adjust_steps(self, Needs::None);
101101
self.apply_adjustments(callee_expr, adjustments);
102102
return Some(CallStep::Builtin(adjusted_ty));
103103
}
@@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
114114
infer::FnCall,
115115
&closure_ty)
116116
.0;
117-
let adjustments = autoderef.adjust_steps(Needs::None);
117+
let adjustments = autoderef.adjust_steps(self, Needs::None);
118118
self.record_deferred_call_resolution(def_id, DeferredCallResolution {
119119
call_expr,
120120
callee_expr,
@@ -144,7 +144,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
144144
}
145145

146146
self.try_overloaded_call_traits(call_expr, adjusted_ty).map(|(autoref, method)| {
147-
let mut adjustments = autoderef.adjust_steps(Needs::None);
147+
let mut adjustments = autoderef.adjust_steps(self, Needs::None);
148148
adjustments.extend(autoref);
149149
self.apply_adjustments(callee_expr, adjustments);
150150
CallStep::Overloaded(method)

src/librustc_typeck/check/coercion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
422422

423423
let needs = Needs::maybe_mut_place(mt_b.mutbl);
424424
let InferOk { value: mut adjustments, obligations: o }
425-
= autoderef.adjust_steps_as_infer_ok(needs);
425+
= autoderef.adjust_steps_as_infer_ok(self, needs);
426426
obligations.extend(o);
427427
obligations.extend(autoderef.into_obligations());
428428

src/librustc_typeck/check/method/confirm.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
161161
let (_, n) = autoderef.nth(pick.autoderefs).unwrap();
162162
assert_eq!(n, pick.autoderefs);
163163

164-
let mut adjustments = autoderef.adjust_steps(Needs::None);
164+
let mut adjustments = autoderef.adjust_steps(self, Needs::None);
165165

166-
let mut target = autoderef.unambiguous_final_ty();
166+
let mut target = autoderef.unambiguous_final_ty(self);
167167

168168
if let Some(mutbl) = pick.autoref {
169169
let region = self.next_region_var(infer::Autoref(self.span));
@@ -202,7 +202,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
202202
assert!(pick.unsize.is_none());
203203
}
204204

205-
autoderef.finalize();
205+
autoderef.finalize(self);
206206

207207
// Write out the final adjustments.
208208
self.apply_adjustments(self.self_expr, adjustments);

0 commit comments

Comments
 (0)