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:
Ariel Ben-Yehuda 2018-09-15 17:14:18 +03:00
parent f4b07e0713
commit 07201249f0
3 changed files with 80 additions and 17 deletions

View File

@ -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,

View File

@ -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))
}

View 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();
}