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).
This commit is contained in:
parent
f4b07e0713
commit
07201249f0
@ -61,6 +61,16 @@ pub struct FulfillmentContext<'tcx> {
|
||||
// type-lives-for-region constraints, and because the type
|
||||
// is well-formed, the constraints should hold.
|
||||
register_region_obligations: bool,
|
||||
// Is it OK to register obligations into this infcx inside
|
||||
// an infcx snapshot?
|
||||
//
|
||||
// The "primary fulfillment" in many cases in typeck lives
|
||||
// outside of any snapshot, so any use of it inside a snapshot
|
||||
// will lead to trouble and therefore is checked against, but
|
||||
// other fulfillment contexts sometimes do live inside of
|
||||
// a snapshot (they don't *straddle* a snapshot, so there
|
||||
// is no trouble there).
|
||||
usable_in_snapshot: bool
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -74,14 +84,24 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
|
||||
pub fn new() -> FulfillmentContext<'tcx> {
|
||||
FulfillmentContext {
|
||||
predicates: ObligationForest::new(),
|
||||
register_region_obligations: true
|
||||
register_region_obligations: true,
|
||||
usable_in_snapshot: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_in_snapshot() -> FulfillmentContext<'tcx> {
|
||||
FulfillmentContext {
|
||||
predicates: ObligationForest::new(),
|
||||
register_region_obligations: true,
|
||||
usable_in_snapshot: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_ignoring_regions() -> FulfillmentContext<'tcx> {
|
||||
FulfillmentContext {
|
||||
predicates: ObligationForest::new(),
|
||||
register_region_obligations: false
|
||||
register_region_obligations: false,
|
||||
usable_in_snapshot: false
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,7 +215,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
||||
|
||||
debug!("register_predicate_obligation(obligation={:?})", obligation);
|
||||
|
||||
assert!(!infcx.is_in_snapshot());
|
||||
assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot);
|
||||
|
||||
self.predicates.register_obligation(PendingPredicateObligation {
|
||||
obligation,
|
||||
|
@ -15,7 +15,7 @@ use super::method::MethodCallee;
|
||||
|
||||
use rustc::infer::InferOk;
|
||||
use rustc::session::DiagnosticMessageId;
|
||||
use rustc::traits;
|
||||
use rustc::traits::{self, TraitEngine};
|
||||
use rustc::ty::{self, Ty, TraitRef};
|
||||
use rustc::ty::{ToPredicate, TypeFoldable};
|
||||
use rustc::ty::adjustment::{Adjustment, Adjust, OverloadedDeref};
|
||||
@ -128,19 +128,28 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut selcx = traits::SelectionContext::new(self.fcx);
|
||||
let normalized_ty = traits::normalize_projection_type(&mut selcx,
|
||||
self.fcx.param_env,
|
||||
ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
Ident::from_str("Target"),
|
||||
),
|
||||
cause,
|
||||
0,
|
||||
&mut self.obligations);
|
||||
|
||||
debug!("overloaded_deref_ty({:?}) = {:?}", ty, normalized_ty);
|
||||
let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
|
||||
let normalized_ty = fulfillcx.normalize_projection_type(
|
||||
&self.fcx,
|
||||
self.fcx.param_env,
|
||||
ty::ProjectionTy::from_ref_and_name(
|
||||
tcx,
|
||||
trait_ref,
|
||||
Ident::from_str("Target"),
|
||||
),
|
||||
cause);
|
||||
if let Err(e) = fulfillcx.select_where_possible(&self.fcx) {
|
||||
// This shouldn't happen, except for evaluate/fulfill mismatches,
|
||||
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
|
||||
// by design).
|
||||
debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling",
|
||||
e);
|
||||
return None;
|
||||
}
|
||||
let obligations = fulfillcx.pending_obligations();
|
||||
debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})",
|
||||
ty, normalized_ty, obligations);
|
||||
self.obligations.extend(obligations);
|
||||
|
||||
Some(self.fcx.resolve_type_vars_if_possible(&normalized_ty))
|
||||
}
|
||||
|
34
src/test/run-pass/issue-53843.rs
Normal file
34
src/test/run-pass/issue-53843.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::ops::Deref;
|
||||
|
||||
pub struct Pin<P>(P);
|
||||
|
||||
impl<P, T> Deref for Pin<P>
|
||||
where
|
||||
P: Deref<Target=T>,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
&*self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> Pin<P> {
|
||||
fn poll(self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut unit = ();
|
||||
let pin = Pin(&mut unit);
|
||||
pin.poll();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user