Skip to content

Commit 558e3e6

Browse files
committed
process nested obligations in autoderef
This is a hack-fix to rust-lang#53843, but I am worried it might break things because it makes the "inference pollution" problem worse. Fixes rust-lang#53843 (but introduces a bug that someone might notice).
1 parent 8a2dec6 commit 558e3e6

File tree

3 files changed

+80
-17
lines changed

3 files changed

+80
-17
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

+23-14
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

+34
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)