Skip to content

Commit

Permalink
process nested obligations in autoderef
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
arielb1 committed Sep 16, 2018
1 parent 8a2dec6 commit 558e3e6
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 17 deletions.
26 changes: 23 additions & 3 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,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)]
Expand All @@ -76,14 +86,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
}
}

Expand Down Expand Up @@ -197,7 +217,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,
Expand Down
37 changes: 23 additions & 14 deletions src/librustc_typeck/check/autoderef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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))
}
Expand Down
34 changes: 34 additions & 0 deletions src/test/run-pass/issue-53843.rs
Original file line number Diff line number Diff line change
@@ -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();
}

0 comments on commit 558e3e6

Please sign in to comment.