ergonomic improvements to the methods in infcx

This commit is contained in:
Niko Matsakis 2017-05-24 09:43:20 -04:00
parent c1e895d92c
commit c7a2e32c10
18 changed files with 434 additions and 297 deletions

310
src/librustc/infer/at.rs Normal file
View File

@ -0,0 +1,310 @@
// Copyright 2012-2014 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.
//! A nice interface for working with the infcx. The basic idea is to
//! do `infcx.at(cause, param_env)`, which sets the "cause" of the
//! operation as well as the surrounding parameter environment. Then
//! you can do something like `.sub(a, b)` or `.eq(a, b)` to create a
//! subtype or equality relationship respectively. The first argument
//! is always the "expected" output from the POV of diagnostics.
//!
//! Examples:
//!
//! infcx.at(cause, param_env).sub(a, b)
//! // requires that `a <: b`, with `a` considered the "expected" type
//!
//! infcx.at(cause, param_env).sup(a, b)
//! // requires that `b <: a`, with `a` considered the "expected" type
//!
//! infcx.at(cause, param_env).eq(a, b)
//! // requires that `a == b`, with `a` considered the "expected" type
//!
//! For finer-grained control, you can also do use `trace`:
//!
//! infcx.at(...).trace(a, b).sub(&c, &d)
//!
//! This will set `a` and `b` as the "root" values for
//! error-reporting, but actually operate on `c` and `d`. This is
//! sometimes useful when the types of `c` and `d` are not traceable
//! things. (That system should probably be refactored.)
use super::*;
use ty::relate::{Relate, TypeRelation};
pub struct At<'a, 'gcx: 'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
}
pub struct Trace<'a, 'gcx: 'tcx, 'tcx: 'a> {
at: At<'a, 'gcx, 'tcx>,
a_is_expected: bool,
trace: TypeTrace<'tcx>,
}
impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn at(&'a self,
cause: &'a ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>)
-> At<'a, 'gcx, 'tcx>
{
At { infcx: self, cause, param_env }
}
}
pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>;
}
impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> {
/// Hacky routine for equating two impl headers in coherence.
pub fn eq_impl_headers(self,
expected: &ty::ImplHeader<'tcx>,
actual: &ty::ImplHeader<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("eq_impl_header({:?} = {:?})", expected, actual);
match (expected.trait_ref, actual.trait_ref) {
(Some(a_ref), Some(b_ref)) =>
self.eq(a_ref, b_ref),
(None, None) =>
self.eq(expected.self_ty, actual.self_ty),
_ =>
bug!("mk_eq_impl_headers given mismatched impl kinds"),
}
}
/// Make `a <: b` where `a` may or may not be expected
pub fn sub_exp<T>(self,
a_is_expected: bool,
a: T,
b: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.trace_exp(a_is_expected, a, b).sub(&a, &b)
}
/// Make `actual <: expected`. For example, if type-checking a
/// call like `foo(x)`, where `foo: fn(i32)`, you might have
/// `sup(i32, x)`, since the "expected" type is the type that
/// appears in the signature.
pub fn sup<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.sub_exp(false, actual, expected)
}
/// Make `expected <: actual`
pub fn sub<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.sub_exp(true, expected, actual)
}
/// Make `expected <: actual`
pub fn eq_exp<T>(self,
a_is_expected: bool,
a: T,
b: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.trace_exp(a_is_expected, a, b).eq(&a, &b)
}
/// Make `expected <: actual`
pub fn eq<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, ()>
where T: ToTrace<'tcx>
{
self.trace(expected, actual).eq(&expected, &actual)
}
/// Compute the least-upper-bound, or mutual supertype, of two
/// values. The order of the arguments doesn't matter, but since
/// this can result in an error (e.g., if asked to compute LUB of
/// u32 and i32), it is meaningful to call one of them the
/// "expected type".
pub fn lub<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, T>
where T: ToTrace<'tcx>
{
self.trace(expected, actual).lub(&expected, &actual)
}
/// Compute the greatest-lower-bound, or mutual subtype, of two
/// values. As with `lub` order doesn't matter, except for error
/// cases.
pub fn glb<T>(self,
expected: T,
actual: T)
-> InferResult<'tcx, T>
where T: ToTrace<'tcx>
{
self.trace(expected, actual).glb(&expected, &actual)
}
/// Sets the "trace" values that will be used for
/// error-repporting, but doesn't actually perform any operation
/// yet (this is useful when you want to set the trace using
/// distinct values from those you wish to operate upon).
pub fn trace<T>(self,
expected: T,
actual: T)
-> Trace<'a, 'gcx, 'tcx>
where T: ToTrace<'tcx>
{
self.trace_exp(true, expected, actual)
}
/// Like `trace`, but the expected value is determined by the
/// boolean argument (if true, then the first argument `a` is the
/// "expected" value).
pub fn trace_exp<T>(self,
a_is_expected: bool,
a: T,
b: T)
-> Trace<'a, 'gcx, 'tcx>
where T: ToTrace<'tcx>
{
let trace = ToTrace::to_trace(self.cause, a_is_expected, a, b);
Trace { at: self, trace: trace, a_is_expected }
}
}
impl<'a, 'gcx, 'tcx> Trace<'a, 'gcx, 'tcx> {
/// Make `a <: b` where `a` may or may not be expected (if
/// `a_is_expected` is true, then `a` is expected).
/// Make `expected <: actual`
pub fn sub<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, ()>
where T: Relate<'tcx>
{
debug!("sub({:?} <: {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.sub(a_is_expected)
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
})
}
/// Make `a == b`; the expectation is set by the call to
/// `trace()`.
pub fn eq<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, ()>
where T: Relate<'tcx>
{
debug!("eq({:?} == {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.equate(a_is_expected)
.relate(a, b)
.map(move |_| InferOk { value: (), obligations: fields.obligations })
})
}
pub fn lub<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
debug!("lub({:?} \\/ {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.lub(a_is_expected)
.relate(a, b)
.map(move |t| InferOk { value: t, obligations: fields.obligations })
})
}
pub fn glb<T>(self,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
debug!("glb({:?} /\\ {:?})", a, b);
let Trace { at, trace, a_is_expected } = self;
at.infcx.commit_if_ok(|_| {
let mut fields = at.infcx.combine_fields(trace, at.param_env);
fields.glb(a_is_expected)
.relate(a, b)
.map(move |t| InferOk { value: t, obligations: fields.obligations })
})
}
}
impl<'tcx> ToTrace<'tcx> for Ty<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>
{
TypeTrace {
cause: cause.clone(),
values: Types(ExpectedFound::new(a_is_expected, a, b))
}
}
}
impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>
{
TypeTrace {
cause: cause.clone(),
values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
}
}
}
impl<'tcx> ToTrace<'tcx> for ty::PolyTraitRef<'tcx> {
fn to_trace(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Self,
b: Self)
-> TypeTrace<'tcx>
{
TypeTrace {
cause: cause.clone(),
values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
}
}
}

View File

@ -31,7 +31,7 @@ use ty::{TyVid, IntVid, FloatVid};
use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::relate::{Relate, RelateResult, TypeRelation};
use ty::relate::RelateResult;
use traits::{self, ObligationCause, PredicateObligations, Reveal};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{Cell, RefCell, Ref, RefMut};
@ -49,6 +49,7 @@ use self::region_inference::{RegionVarBindings, RegionSnapshot};
use self::type_variable::TypeVariableOrigin;
use self::unify_key::ToType;
pub mod at;
mod combine;
mod equate;
pub mod error_reporting;
@ -802,62 +803,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn equate<T>(&'a self,
a_is_expected: bool,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace, param_env);
let result = fields.equate(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn sub<T>(&'a self,
a_is_expected: bool,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace, param_env);
let result = fields.sub(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn lub<T>(&'a self,
a_is_expected: bool,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace, param_env);
let result = fields.lub(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
pub fn glb<T>(&'a self,
a_is_expected: bool,
trace: TypeTrace<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: &T,
b: &T)
-> InferResult<'tcx, T>
where T: Relate<'tcx>
{
let mut fields = self.combine_fields(trace, param_env);
let result = fields.glb(a_is_expected).relate(a, b);
result.map(move |t| InferOk { value: t, obligations: fields.obligations })
}
// Clear the "currently in a snapshot" flag, invoke the closure,
// then restore the flag to its original value. This flag is a
// debugging measure designed to detect cases where we start a
@ -1017,102 +962,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.region_vars.add_given(sub, sup);
}
pub fn sub_types(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("sub_types({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace::types(cause, a_is_expected, a, b);
self.sub(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit())
})
}
pub fn can_sub_types(&self,
param_env: ty::ParamEnv<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> UnitResult<'tcx>
pub fn can_sub<T>(&self,
param_env: ty::ParamEnv<'tcx>,
a: T,
b: T)
-> UnitResult<'tcx>
where T: at::ToTrace<'tcx>
{
let origin = &ObligationCause::dummy();
self.probe(|_| {
let origin = &ObligationCause::dummy();
let trace = TypeTrace::types(origin, true, a, b);
self.sub(true, trace, param_env, &a, &b).map(|InferOk { obligations: _, .. }| {
self.at(origin, param_env).sub(a, b).map(|InferOk { obligations: _, .. }| {
// Ignore obligations, since we are unrolling
// everything anyway.
})
})
}
pub fn eq_types(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> InferResult<'tcx, ()>
pub fn can_eq<T>(&self,
param_env: ty::ParamEnv<'tcx>,
a: T,
b: T)
-> UnitResult<'tcx>
where T: at::ToTrace<'tcx>
{
self.commit_if_ok(|_| {
let trace = TypeTrace::types(cause, a_is_expected, a, b);
self.equate(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit())
})
}
pub fn eq_trait_refs(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("eq_trait_refs({:?} = {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
cause: cause.clone(),
values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
};
self.equate(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit())
})
}
pub fn eq_impl_headers(&self,
a_is_expected: bool,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: &ty::ImplHeader<'tcx>,
b: &ty::ImplHeader<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("eq_impl_header({:?} = {:?})", a, b);
match (a.trait_ref, b.trait_ref) {
(Some(a_ref), Some(b_ref)) =>
self.eq_trait_refs(a_is_expected, cause, param_env, a_ref, b_ref),
(None, None) =>
self.eq_types(a_is_expected, cause, param_env, a.self_ty, b.self_ty),
_ => bug!("mk_eq_impl_headers given mismatched impl kinds"),
}
}
pub fn sub_poly_trait_refs(&self,
a_is_expected: bool,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("sub_poly_trait_refs({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
cause: cause,
values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
};
self.sub(a_is_expected, trace, param_env, &a, &b).map(|ok| ok.unit())
let origin = &ObligationCause::dummy();
self.probe(|_| {
self.at(origin, param_env).eq(a, b).map(|InferOk { obligations: _, .. }| {
// Ignore obligations, since we are unrolling
// everything anyway.
})
})
}
@ -1134,7 +1012,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let (ty::EquatePredicate(a, b), skol_map) =
self.skolemize_late_bound_regions(predicate, snapshot);
let cause_span = cause.span;
let eqty_ok = self.eq_types(false, cause, param_env, a, b)?;
let eqty_ok = self.at(cause, param_env).eq(b, a)?;
self.leak_check(false, cause_span, &skol_map, snapshot)?;
self.pop_skolemized(skol_map, snapshot);
Ok(eqty_ok.unit())
@ -1172,7 +1050,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.skolemize_late_bound_regions(predicate, snapshot);
let cause_span = cause.span;
let ok = self.sub_types(a_is_expected, cause, param_env, a, b)?;
let ok = self.at(cause, param_env).sub_exp(a_is_expected, a, b)?;
self.leak_check(false, cause_span, &skol_map, snapshot)?;
self.pop_skolemized(skol_map, snapshot);
Ok(ok.unit())
@ -1606,27 +1484,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
self.region_vars.verify_generic_bound(origin, kind, a, bound);
}
pub fn can_equate<T>(&self, param_env: ty::ParamEnv<'tcx>, a: &T, b: &T) -> UnitResult<'tcx>
where T: Relate<'tcx> + fmt::Debug
{
debug!("can_equate({:?}, {:?})", a, b);
self.probe(|_| {
// Gin up a dummy trace, since this won't be committed
// anyhow. We should make this typetrace stuff more
// generic so we don't have to do anything quite this
// terrible.
let trace = TypeTrace::dummy(self.tcx);
self.equate(true, trace, param_env, a, b).map(|InferOk { obligations: _, .. }| {
// We can intentionally ignore obligations here, since
// this is part of a simple test for general
// "equatability". However, it's not entirely clear
// that we *ought* to be, perhaps a better thing would
// be to use a mini-fulfillment context or something
// like that.
})
})
}
pub fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
let ty = self.node_type(id);
self.resolve_type_vars_or_error(&ty)

View File

@ -84,12 +84,9 @@ fn overlap<'cx, 'gcx, 'tcx>(selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
debug!("overlap: b_impl_header={:?}", b_impl_header);
// Do `a` and `b` unify? If not, no overlap.
let obligations = match selcx.infcx().eq_impl_headers(true,
&ObligationCause::dummy(),
param_env,
&a_impl_header,
&b_impl_header) {
Ok(InferOk { obligations, .. }) => {
let obligations = match selcx.infcx().at(&ObligationCause::dummy(), param_env)
.eq_impl_headers(&a_impl_header, &b_impl_header) {
Ok(InferOk { obligations, value: () }) => {
obligations
}
Err(_) => return None

View File

@ -184,10 +184,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
obligation.cause.clone(),
0
);
if let Err(error) = self.eq_types(
false, &obligation.cause, obligation.param_env,
data.ty, normalized.value
) {
if let Err(error) = self.at(&obligation.cause, obligation.param_env)
.eq(normalized.value, data.ty) {
values = Some(infer::ValuePairs::Types(ExpectedFound {
expected: normalized.value,
found: data.ty,
@ -269,7 +267,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
let impl_self_ty = impl_trait_ref.self_ty();
if let Ok(..) = self.can_equate(param_env, &trait_self_ty, &impl_self_ty) {
if let Ok(..) = self.can_eq(param_env, trait_self_ty, impl_self_ty) {
self_match_impls.push(def_id);
if trait_ref.substs.types().skip(1)

View File

@ -181,11 +181,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
obligations);
let infcx = selcx.infcx();
match infcx.eq_types(true,
&obligation.cause,
obligation.param_env,
normalized_ty,
obligation.predicate.ty) {
match infcx.at(&obligation.cause, obligation.param_env)
.eq(normalized_ty, obligation.predicate.ty) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
Ok(Some(obligations))
@ -840,16 +837,13 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
data.to_poly_trait_ref();
let obligation_poly_trait_ref =
obligation_trait_ref.to_poly_trait_ref();
infcx.sub_poly_trait_refs(false,
obligation.cause.clone(),
obligation.param_env,
data_poly_trait_ref,
obligation_poly_trait_ref)
.map(|InferOk { obligations: _, value: () }| {
// FIXME(#32730) -- do we need to take obligations
// into account in any way? At the moment, no.
})
.is_ok()
infcx.at(&obligation.cause, obligation.param_env)
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
.map(|InferOk { obligations: _, value: () }| {
// FIXME(#32730) -- do we need to take obligations
// into account in any way? At the moment, no.
})
.is_ok()
});
debug!("assemble_candidates_from_predicates: candidate={:?} \
@ -1110,11 +1104,9 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
let data_poly_trait_ref = data.to_poly_trait_ref();
let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
selcx.infcx().probe(|_| {
selcx.infcx().sub_poly_trait_refs(false,
obligation.cause.clone(),
obligation.param_env,
data_poly_trait_ref,
obligation_poly_trait_ref).is_ok()
selcx.infcx().at(&obligation.cause, obligation.param_env)
.sup(obligation_poly_trait_ref, data_poly_trait_ref)
.is_ok()
})
});

View File

@ -1269,12 +1269,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
-> bool
{
assert!(!skol_trait_ref.has_escaping_regions());
let cause = obligation.cause.clone();
match self.infcx.sub_poly_trait_refs(false,
cause,
obligation.param_env,
trait_bound.clone(),
ty::Binder(skol_trait_ref.clone())) {
match self.infcx.at(&obligation.cause, obligation.param_env)
.sup(ty::Binder(skol_trait_ref), trait_bound) {
Ok(InferOk { obligations, .. }) => {
self.inferred_obligations.extend(obligations);
}
@ -2436,11 +2432,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
-> Result<(), SelectionError<'tcx>>
{
let obligation_trait_ref = obligation_trait_ref.clone();
self.infcx.sub_poly_trait_refs(false,
obligation_cause.clone(),
obligation_param_env,
expected_trait_ref.clone(),
obligation_trait_ref.clone())
self.infcx
.at(&obligation_cause, obligation_param_env)
.sup(obligation_trait_ref, expected_trait_ref)
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
}
@ -2475,12 +2469,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
let new_trait = tcx.mk_dynamic(
ty::Binder(tcx.mk_existential_predicates(iter)), r_b);
let InferOk { obligations, .. } =
self.infcx.eq_types(false,
&obligation.cause,
obligation.param_env,
new_trait,
target)
.map_err(|_| Unimplemented)?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(target, new_trait)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
// Register one obligation for 'a: 'b.
@ -2540,8 +2531,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// [T; n] -> [T].
(&ty::TyArray(a, _), &ty::TySlice(b)) => {
let InferOk { obligations, .. } =
self.infcx.eq_types(false, &obligation.cause, obligation.param_env, a, b)
.map_err(|_| Unimplemented)?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(b, a)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
}
@ -2603,12 +2595,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
});
let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
let InferOk { obligations, .. } =
self.infcx.eq_types(false,
&obligation.cause,
obligation.param_env,
new_struct,
target)
.map_err(|_| Unimplemented)?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(target, new_struct)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
// Construct the nested Field<T>: Unsize<Field<U>> predicate.
@ -2696,15 +2685,12 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
skol_obligation_trait_ref);
let InferOk { obligations, .. } =
self.infcx.eq_trait_refs(false,
&obligation.cause,
obligation.param_env,
impl_trait_ref.value.clone(),
skol_obligation_trait_ref)
.map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e);
()
})?;
self.infcx.at(&obligation.cause, obligation.param_env)
.eq(skol_obligation_trait_ref, impl_trait_ref.value)
.map_err(|e| {
debug!("match_impl: failed eq_trait_refs due to `{}`", e);
()
})?;
self.inferred_obligations.extend(obligations);
if let Err(e) = self.infcx.leak_check(false,
@ -2770,13 +2756,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
obligation,
poly_trait_ref);
self.infcx.sub_poly_trait_refs(false,
obligation.cause.clone(),
obligation.param_env,
poly_trait_ref,
obligation.predicate.to_poly_trait_ref())
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
.map_err(|_| ())
self.infcx.at(&obligation.cause, obligation.param_env)
.sup(obligation.predicate.to_poly_trait_ref(), poly_trait_ref)
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
.map_err(|_| ())
}
///////////////////////////////////////////////////////////////////////////

View File

@ -228,11 +228,8 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
target_substs);
// do the impls unify? If not, no specialization.
match infcx.eq_trait_refs(true,
&ObligationCause::dummy(),
param_env,
source_trait_ref,
target_trait_ref) {
match infcx.at(&ObligationCause::dummy(), param_env)
.eq(source_trait_ref, target_trait_ref) {
Ok(InferOk { obligations: o, .. }) => {
obligations.extend(o);
}

View File

@ -353,18 +353,20 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
infer_ok.value
}
fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>)
fn sub_types(&mut self, sub: Ty<'tcx>, sup: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
self.infcx.sub_types(false, &self.misc(self.last_span), self.param_env, sup, sub)
.map(|ok| self.register_infer_ok_obligations(ok))
self.infcx.at(&self.misc(self.last_span), self.param_env)
.sup(sup, sub)
.map(|ok| self.register_infer_ok_obligations(ok))
}
fn eq_types(&mut self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
self.infcx.eq_types(false, &self.misc(span), self.param_env, a, b)
.map(|ok| self.register_infer_ok_obligations(ok))
self.infcx.at(&self.misc(span), self.param_env)
.eq(b, a)
.map(|ok| self.register_infer_ok_obligations(ok))
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {

View File

@ -64,7 +64,7 @@ use check::{Diverges, FnCtxt};
use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer::{Coercion, InferResult, InferOk, TypeTrace};
use rustc::infer::{Coercion, InferResult, InferOk};
use rustc::infer::type_variable::TypeVariableOrigin;
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
@ -135,11 +135,13 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
self.commit_if_ok(|_| {
let trace = TypeTrace::types(&self.cause, false, a, b);
if self.use_lub {
self.lub(false, trace, self.fcx.param_env, &a, &b)
self.at(&self.cause, self.fcx.param_env)
.lub(b, a)
} else {
self.sub(false, trace, self.fcx.param_env, &a, &b)
self.at(&self.cause, self.fcx.param_env)
.sup(b, a)
.map(|InferOk { value: (), obligations }| InferOk { value: a, obligations })
}
})
}
@ -771,20 +773,22 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
return Ok(prev_ty);
}
let trace = TypeTrace::types(cause, true, prev_ty, new_ty);
// Special-case that coercion alone cannot handle:
// Two function item types of differing IDs or Substs.
match (&prev_ty.sty, &new_ty.sty) {
(&ty::TyFnDef(a_def_id, a_substs, a_fty), &ty::TyFnDef(b_def_id, b_substs, b_fty)) => {
// The signature must always match.
let fty = self.lub(true, trace.clone(), self.param_env, &a_fty, &b_fty)
let fty = self.at(cause, self.param_env)
.trace(prev_ty, new_ty)
.lub(&a_fty, &b_fty)
.map(|ok| self.register_infer_ok_obligations(ok))?;
if a_def_id == b_def_id {
// Same function, maybe the parameters match.
let substs = self.commit_if_ok(|_| {
self.lub(true, trace.clone(), self.param_env, &a_substs, &b_substs)
self.at(cause, self.param_env)
.trace(prev_ty, new_ty)
.lub(&a_substs, &b_substs)
.map(|ok| self.register_infer_ok_obligations(ok))
});
@ -853,7 +857,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if !noop {
return self.commit_if_ok(|_| {
self.lub(true, trace.clone(), self.param_env, &prev_ty, &new_ty)
self.at(cause, self.param_env)
.lub(prev_ty, new_ty)
.map(|ok| self.register_infer_ok_obligations(ok))
});
}
@ -866,7 +871,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
Err(e)
} else {
self.commit_if_ok(|_| {
self.lub(true, trace, self.param_env, &prev_ty, &new_ty)
self.at(cause, self.param_env)
.lub(prev_ty, new_ty)
.map(|ok| self.register_infer_ok_obligations(ok))
})
}
@ -1109,7 +1115,8 @@ impl<'gcx, 'tcx, 'exprs, E> CoerceMany<'gcx, 'tcx, 'exprs, E>
// Another example is `break` with no argument expression.
assert!(expression_ty.is_nil());
assert!(expression_ty.is_nil(), "if let hack without unit type");
fcx.eq_types(label_expression_as_expected, cause, fcx.param_env, expression_ty, self.merged_ty())
fcx.at(cause, fcx.param_env)
.eq_exp(label_expression_as_expected, expression_ty, self.merged_ty())
.map(|infer_ok| {
fcx.register_infer_ok_obligations(infer_ok);
expression_ty

View File

@ -289,7 +289,8 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
let sub_result = infcx.sub_types(false, &cause, param_env, impl_fty, trait_fty)
let sub_result = infcx.at(&cause, param_env)
.sup(trait_fty, impl_fty)
.map(|InferOk { obligations, .. }| {
inh.register_predicates(obligations);
});
@ -460,28 +461,23 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
impl_iter.zip(trait_iter)
.zip(impl_m_iter)
.zip(trait_m_iter)
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
match infcx.sub_types(true,
&cause,
param_env,
trait_arg_ty,
impl_arg_ty) {
.filter_map(|(((&impl_arg_ty, &trait_arg_ty), impl_arg), trait_arg)| {
match infcx.at(&cause, param_env).sub(trait_arg_ty, impl_arg_ty) {
Ok(_) => None,
Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
}
})
.next()
.unwrap_or_else(|| {
if infcx.sub_types(false,
&cause,
param_env,
impl_sig.output(),
trait_sig.output())
.is_err() {
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
}
if
infcx.at(&cause, param_env)
.sup(trait_sig.output(), impl_sig.output())
.is_err()
{
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
}
})
} else {
(cause.span, tcx.hir.span_if_local(trait_m.def_id))
@ -760,8 +756,9 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
let err = infcx.sub_types(false, &cause, param_env, impl_ty, trait_ty)
.map(|ok| inh.register_infer_ok_obligations(ok));
let err = infcx.at(&cause, param_env)
.sup(trait_ty, impl_ty)
.map(|ok| inh.register_infer_ok_obligations(ok));
if let Err(terr) = err {
debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}",

View File

@ -26,8 +26,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// Requires that the two types unify, and prints an error message if
// they don't.
pub fn demand_suptype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
let cause = self.misc(sp);
match self.sub_types(false, &cause, self.param_env, actual, expected) {
let cause = &self.misc(sp);
match self.at(cause, self.param_env).sup(expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
},
@ -54,7 +54,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>) -> Option<DiagnosticBuilder<'tcx>> {
match self.eq_types(false, cause, self.param_env, actual, expected) {
match self.at(cause, self.param_env).eq(expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
None

View File

@ -92,7 +92,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
match infcx.eq_types(true, cause, impl_param_env, named_type, fresh_impl_self_ty) {
match infcx.at(cause, impl_param_env).eq(named_type, fresh_impl_self_ty) {
Ok(InferOk { obligations, .. }) => {
fulfillment_cx.register_predicate_obligations(infcx, obligations);
}

View File

@ -340,7 +340,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
}
fn unify_receivers(&mut self, self_ty: Ty<'tcx>, method_self_ty: Ty<'tcx>) {
match self.sub_types(false, &self.misc(self.span), self.param_env, self_ty, method_self_ty) {
match self.at(&self.misc(self.span), self.param_env).sup(method_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}

View File

@ -679,7 +679,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
let output = fty.output().subst(self.tcx, substs);
let (output, _) = self.replace_late_bound_regions_with_fresh_var(
self.span, infer::FnCall, &output);
self.can_sub_types(self.param_env, output, expected).is_ok()
self.can_sub(self.param_env, output, expected).is_ok()
})
}
_ => false,
@ -885,7 +885,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
substs,
bound);
if self.can_equate(self.param_env, &step.self_ty, &bound.self_ty()).is_ok() {
if self.can_eq(self.param_env, step.self_ty, bound.self_ty()).is_ok() {
let xform_self_ty = self.xform_self_ty(&item, bound.self_ty(), bound.substs);
debug!("assemble_projection_candidates: bound={:?} xform_self_ty={:?}",
@ -1143,11 +1143,8 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
self.probe(|_| {
// First check that the self type can be related.
let sub_obligations = match self.sub_types(false,
&ObligationCause::dummy(),
self.param_env,
self_ty,
probe.xform_self_ty) {
let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env)
.sup(probe.xform_self_ty, self_ty) {
Ok(InferOk { obligations, value: () }) => obligations,
Err(_) => {
debug!("--> cannot relate self-types");

View File

@ -2723,7 +2723,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = self.misc(call_span);
let ures = self.sub_types(false, &origin, self.param_env, formal_ret, ret_ty);
let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
// FIXME(#15760) can't use try! here, FromError doesn't default
// to identity so the resulting type is not constrained.
@ -4218,7 +4218,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => return,
};
let last_expr_ty = self.expr_ty(last_expr);
if self.can_sub_types(self.param_env, last_expr_ty, expected_ty).is_err() {
if self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() {
return;
}
let original_span = original_sp(last_stmt.span, blk.span);
@ -4478,7 +4478,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let ty = self.tcx.type_of(impl_def_id);
let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
match self.sub_types(false, &self.misc(span), self.param_env, self_ty, impl_ty) {
match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
span_bug!(span,

View File

@ -1660,7 +1660,7 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
// check whether this predicate applies to our current projection
let cause = self.fcx.misc(span);
match self.eq_types(false, &cause, self.fcx.param_env, ty, outlives.0) {
match self.at(&cause, self.fcx.param_env).eq(outlives.0, ty) {
Ok(ok) => {
self.register_infer_ok_obligations(ok);
Ok(outlives.1)

View File

@ -308,7 +308,7 @@ pub fn coerce_unsized_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
// we may have to evaluate constraint
// expressions in the course of execution.)
// See e.g. #41936.
if let Ok(ok) = infcx.eq_types(false, &cause, param_env, b, a) {
if let Ok(ok) = infcx.at(&cause, param_env).eq(a, b) {
if ok.obligations.is_empty() {
return None;
}

View File

@ -158,7 +158,7 @@ fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tcx.infer_ctxt(()).enter(|ref infcx| {
let param_env = ty::ParamEnv::empty(Reveal::UserFacing);
let mut fulfill_cx = FulfillmentContext::new();
match infcx.eq_types(false, &cause, param_env, expected, actual) {
match infcx.at(&cause, param_env).eq(expected, actual) {
Ok(InferOk { obligations, .. }) => {
fulfill_cx.register_predicate_obligations(infcx, obligations);
}