Skip to content

Plumb obligations through librustc/infer #32596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 5, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/librustc/infer/combine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
use super::{InferCtxt};
use super::InferCtxt;
use super::{MiscVariable, TypeTrace};
use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf};

Expand All @@ -46,6 +46,7 @@ use ty::{self, Ty, TyCtxt};
use ty::error::TypeError;
use ty::fold::{TypeFolder, TypeFoldable};
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::PredicateObligations;

use syntax::ast;
use syntax::codemap::Span;
Expand All @@ -56,6 +57,7 @@ pub struct CombineFields<'a, 'tcx: 'a> {
pub a_is_expected: bool,
pub trace: TypeTrace<'tcx>,
pub cause: Option<ty::relate::Cause>,
pub obligations: PredicateObligations<'tcx>,
}

pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>,
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/infer/equate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::type_variable::{EqTo};
use ty::{self, Ty, TyCtxt};
use ty::TyVar;
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::PredicateObligations;

/// Ensures `a` is made equal to `b`. Returns `a` on success.
pub struct Equate<'a, 'tcx: 'a> {
Expand All @@ -26,6 +27,10 @@ impl<'a, 'tcx> Equate<'a, 'tcx> {
pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> {
Equate { fields: fields }
}

pub fn obligations(self) -> PredicateObligations<'tcx> {
self.fields.obligations
}
}

impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> {
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/infer/glb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::Subtype;

use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::PredicateObligations;

/// "Greatest lower bound" (common subtype)
pub struct Glb<'a, 'tcx: 'a> {
Expand All @@ -26,6 +27,10 @@ impl<'a, 'tcx> Glb<'a, 'tcx> {
pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> {
Glb { fields: fields }
}

pub fn obligations(self) -> PredicateObligations<'tcx> {
self.fields.obligations
}
}

impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> {
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/infer/lub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::Subtype;

use ty::{self, Ty, TyCtxt};
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::PredicateObligations;

/// "Least upper bound" (common supertype)
pub struct Lub<'a, 'tcx: 'a> {
Expand All @@ -26,6 +27,10 @@ impl<'a, 'tcx> Lub<'a, 'tcx> {
pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> {
Lub { fields: fields }
}

pub fn obligations(self) -> PredicateObligations<'tcx> {
self.fields.obligations
}
}

impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> {
Expand Down
97 changes: 61 additions & 36 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ use middle::region::CodeExtent;
use ty::subst;
use ty::subst::Substs;
use ty::subst::Subst;
use traits::{self, ProjectionMode};
use ty::adjustment;
use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFolder, TypeFoldable};
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::{self, PredicateObligations, ProjectionMode};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{RefCell, Ref};
use std::fmt;
Expand Down Expand Up @@ -63,6 +63,12 @@ pub mod sub;
pub mod type_variable;
pub mod unify_key;

pub struct InferOk<'tcx, T> {
pub value: T,
pub obligations: PredicateObligations<'tcx>,
}
pub type InferResult<'tcx, T> = Result<InferOk<'tcx, T>, TypeError<'tcx>>;

pub type Bound<T> = Option<T>;
pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result"
pub type FixupResult<T> = Result<T, FixupError>; // "fixup result"
Expand Down Expand Up @@ -391,16 +397,15 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("mk_subty({:?} <: {:?})", a, b);
cx.sub_types(a_is_expected, origin, a, b)
}

pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx> {
pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
-> UnitResult<'tcx>
{
debug!("can_mk_subty({:?} <: {:?})", a, b);
cx.probe(|_| {
let trace = TypeTrace {
Expand All @@ -412,7 +417,7 @@ pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
}

pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>)
-> UnitResult<'tcx>
-> UnitResult<'tcx>
{
cx.can_equate(&a, &b)
}
Expand All @@ -432,7 +437,7 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("mk_eqty({:?} <: {:?})", a, b);
cx.eq_types(a_is_expected, origin, a, b)
Expand All @@ -443,7 +448,7 @@ pub fn mk_eq_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("mk_eq_trait_refs({:?} = {:?})", a, b);
cx.eq_trait_refs(a_is_expected, origin, a, b)
Expand All @@ -454,7 +459,7 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("mk_sub_poly_trait_refs({:?} <: {:?})", a, b);
cx.sub_poly_trait_refs(a_is_expected, origin, a, b)
Expand All @@ -465,7 +470,7 @@ pub fn mk_eq_impl_headers<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>,
origin: TypeOrigin,
a: &ty::ImplHeader<'tcx>,
b: &ty::ImplHeader<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("mk_eq_impl_header({:?} = {:?})", a, b);
match (a.trait_ref, b.trait_ref) {
Expand Down Expand Up @@ -574,6 +579,12 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
Ok(infcx.tcx.erase_regions(&result))
}

impl<'tcx, T> InferOk<'tcx, T> {
fn unit(self) -> InferOk<'tcx, ()> {
InferOk { value: (), obligations: self.obligations }
}
}

impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn projection_mode(&self) -> ProjectionMode {
self.projection_mode
Expand Down Expand Up @@ -661,39 +672,51 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
}

fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>)
-> CombineFields<'a, 'tcx> {
CombineFields {infcx: self,
a_is_expected: a_is_expected,
trace: trace,
cause: None}
-> CombineFields<'a, 'tcx>
{
CombineFields {
infcx: self,
a_is_expected: a_is_expected,
trace: trace,
cause: None,
obligations: PredicateObligations::new(),
}
}

pub fn equate<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
-> InferResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).equate().relate(a, b)
let mut equate = self.combine_fields(a_is_expected, trace).equate();
let result = equate.relate(a, b);
result.map(|t| InferOk { value: t, obligations: equate.obligations() })
}

pub fn sub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
-> InferResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).sub().relate(a, b)
let mut sub = self.combine_fields(a_is_expected, trace).sub();
let result = sub.relate(a, b);
result.map(|t| InferOk { value: t, obligations: sub.obligations() })
}

pub fn lub<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
-> InferResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).lub().relate(a, b)
let mut lub = self.combine_fields(a_is_expected, trace).lub();
let result = lub.relate(a, b);
result.map(|t| InferOk { value: t, obligations: lub.obligations() })
}

pub fn glb<T>(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>, a: &T, b: &T)
-> RelateResult<'tcx, T>
-> InferResult<'tcx, T>
where T: Relate<'a, 'tcx>
{
self.combine_fields(a_is_expected, trace).glb().relate(a, b)
let mut glb = self.combine_fields(a_is_expected, trace).glb();
let result = glb.relate(a, b);
result.map(|t| InferOk { value: t, obligations: glb.obligations() })
}

fn start_snapshot(&self) -> CombinedSnapshot {
Expand Down Expand Up @@ -829,12 +852,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("sub_types({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
self.sub(a_is_expected, trace, &a, &b).map(|_| ())
self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}

Expand All @@ -843,11 +866,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
self.equate(a_is_expected, trace, &a, &b).map(|_| ())
self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}

Expand All @@ -856,7 +879,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("eq_trait_refs({:?} <: {:?})",
a,
Expand All @@ -866,7 +889,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: origin,
values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
self.equate(a_is_expected, trace, &a, &b).map(|_| ())
self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}

Expand All @@ -875,7 +898,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: TypeOrigin,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> UnitResult<'tcx>
-> InferResult<'tcx, ()>
{
debug!("sub_poly_trait_refs({:?} <: {:?})",
a,
Expand All @@ -885,7 +908,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
origin: origin,
values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone()))
};
self.sub(a_is_expected, trace, &a, &b).map(|_| ())
self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}

Expand Down Expand Up @@ -928,20 +951,22 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
pub fn equality_predicate(&self,
span: Span,
predicate: &ty::PolyEquatePredicate<'tcx>)
-> UnitResult<'tcx> {
-> InferResult<'tcx, ()>
{
self.commit_if_ok(|snapshot| {
let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let origin = TypeOrigin::EquatePredicate(span);
let () = mk_eqty(self, false, origin, a, b)?;
self.leak_check(&skol_map, snapshot)
let eqty_ok = mk_eqty(self, false, origin, a, b)?;
self.leak_check(&skol_map, snapshot).map(|_| eqty_ok.unit())
})
}

pub fn region_outlives_predicate(&self,
span: Span,
predicate: &ty::PolyRegionOutlivesPredicate)
-> UnitResult<'tcx> {
-> UnitResult<'tcx>
{
self.commit_if_ok(|snapshot| {
let (ty::OutlivesPredicate(r_a, r_b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
Expand Down
5 changes: 5 additions & 0 deletions src/librustc/infer/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use super::type_variable::{SubtypeOf, SupertypeOf};
use ty::{self, Ty, TyCtxt};
use ty::TyVar;
use ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use traits::PredicateObligations;
use std::mem;

/// Ensures `a` is made a subtype of `b`. Returns `a` on success.
Expand All @@ -27,6 +28,10 @@ impl<'a, 'tcx> Sub<'a, 'tcx> {
pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> {
Sub { fields: f }
}

pub fn obligations(self) -> PredicateObligations<'tcx> {
self.fields.obligations
}
}

impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> {
Expand Down
8 changes: 6 additions & 2 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

use dep_graph::DepGraph;
use infer::InferCtxt;
use infer::{InferCtxt, InferOk};
use ty::{self, Ty, TyCtxt, TypeFoldable, ToPolyTraitRef};
use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
use std::iter;
Expand Down Expand Up @@ -526,7 +526,11 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,

ty::Predicate::Equate(ref binder) => {
match selcx.infcx().equality_predicate(obligation.cause.span, binder) {
Ok(()) => Ok(Some(Vec::new())),
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
Ok(Some(Vec::new()))
},
Err(_) => Err(CodeSelectionError(Unimplemented)),
}
}
Expand Down
Loading