Skip to content

Commit 0720124

Browse files
committed
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. Fixes #53843 (but introduces a bug that someone might notice).
1 parent f4b07e0 commit 0720124

File tree

3 files changed

+80
-17
lines changed

3 files changed

+80
-17
lines changed

src/librustc/traits/fulfill.rs

Lines changed: 23 additions & 3 deletions
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,

src/librustc_typeck/check/autoderef.rs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use super::method::MethodCallee;
1515

1616
use rustc::infer::InferOk;
1717
use rustc::session::DiagnosticMessageId;
18-
use rustc::traits;
18+
use rustc::traits::{self, TraitEngine};
1919
use rustc::ty::{self, Ty, TraitRef};
2020
use rustc::ty::{ToPredicate, TypeFoldable};
2121
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
@@ -128,19 +128,28 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
128128
return None;
129129
}
130130

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);
131+
let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
132+
let normalized_ty = fulfillcx.normalize_projection_type(
133+
&self.fcx,
134+
self.fcx.param_env,
135+
ty::ProjectionTy::from_ref_and_name(
136+
tcx,
137+
trait_ref,
138+
Ident::from_str("Target"),
139+
),
140+
cause);
141+
if let Err(e) = fulfillcx.select_where_possible(&self.fcx) {
142+
// This shouldn't happen, except for evaluate/fulfill mismatches,
143+
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
144+
// by design).
145+
debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling",
146+
e);
147+
return None;
148+
}
149+
let obligations = fulfillcx.pending_obligations();
150+
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})",
151+
ty, normalized_ty, obligations);
152+
self.obligations.extend(obligations);
144153

145154
Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty))
146155
}

src/test/run-pass/issue-53843.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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 std::ops::Deref;
12+
13+
pub struct Pin<P>(P);
14+
15+
impl<P, T> Deref for Pin<P>
16+
where
17+
P: Deref<Target=T>,
18+
{
19+
type Target = T;
20+
21+
fn deref(&self) -> &T {
22+
&*self.0
23+
}
24+
}
25+
26+
impl<P> Pin<P> {
27+
fn poll(self) {}
28+
}
29+
30+
fn main() {
31+
let mut unit = ();
32+
let pin = Pin(&mut unit);
33+
pin.poll();
34+
}

0 commit comments

Comments
 (0)