Auto merge of #37717 - nikomatsakis:region-obligations-pre, r=eddyb

Refactoring towards region obligation

Two refactorings towards the intermediate goal of propagating region obligations through the `InferOk` structure (which in turn leads to the possibility of lazy normalization).

1. Remove `TypeOrigin` and add `ObligationCause`
    - as we converge subtyping and obligations and so forth, the ability to keep these types distinct gets harder
2. Propagate obligations from `InferOk` into the surrounding fulfillment context

After these land, I have a separate branch (which still needs a bit of work) that can make the actual change to stop directly adding subregion edges and instead propagate obligations. (This should also make it easier to fix the unsoundness in specialization around lifetimes.)

r? @eddyb
This commit is contained in:
bors 2016-11-17 01:18:51 -08:00 committed by GitHub
commit 29181b3f0c
28 changed files with 472 additions and 467 deletions

View File

@ -274,7 +274,7 @@ impl<'infcx, 'gcx, 'tcx> CombineFields<'infcx, 'gcx, 'tcx> {
{
let mut generalize = Generalizer {
infcx: self.infcx,
span: self.trace.origin.span(),
span: self.trace.cause.span,
for_vid: for_vid,
make_region_vars: make_region_vars,
cycle_detected: false

View File

@ -80,8 +80,9 @@ use hir::print as pprust;
use lint;
use hir::def::Def;
use hir::def_id::DefId;
use infer::{self, TypeOrigin};
use infer;
use middle::region;
use traits::{ObligationCause, ObligationCauseCode};
use ty::{self, TyCtxt, TypeFoldable};
use ty::{Region, ReFree};
use ty::error::TypeError;
@ -524,10 +525,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
fn note_error_origin(&self,
err: &mut DiagnosticBuilder<'tcx>,
origin: &TypeOrigin)
cause: &ObligationCause<'tcx>)
{
match origin {
&TypeOrigin::MatchExpressionArm(_, arm_span, source) => match source {
match cause.code {
ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
hir::MatchSource::IfLetDesugar {..} => {
err.span_note(arm_span, "`if let` arm with an incompatible type");
}
@ -541,7 +542,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn note_type_err(&self,
diag: &mut DiagnosticBuilder<'tcx>,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
secondary_span: Option<(Span, String)>,
values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>)
@ -558,7 +559,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
};
let span = origin.span();
let span = cause.span;
if let Some((expected, found)) = expected_found {
let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
@ -588,7 +589,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
diag.span_label(sp, &msg);
}
self.note_error_origin(diag, &origin);
self.note_error_origin(diag, &cause);
self.check_and_note_conflicting_crates(diag, terr, span);
self.tcx.note_and_explain_type_err(diag, terr, span);
}
@ -598,17 +599,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
terr: &TypeError<'tcx>)
-> DiagnosticBuilder<'tcx>
{
let span = trace.origin.span();
let failure_str = trace.origin.as_failure_str();
let mut diag = match trace.origin {
TypeOrigin::IfExpressionWithNoElse(_) => {
let span = trace.cause.span;
let failure_str = trace.cause.as_failure_str();
let mut diag = match trace.cause.code {
ObligationCauseCode::IfExpressionWithNoElse => {
struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
},
_ => {
struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
},
};
self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr);
self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr);
diag
}
@ -1695,18 +1696,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
if let Some((expected, found)) = self.values_str(&trace.values) {
// FIXME: do we want a "the" here?
err.span_note(
trace.origin.span(),
trace.cause.span,
&format!("...so that {} (expected {}, found {})",
trace.origin.as_requirement_str(), expected, found));
trace.cause.as_requirement_str(), expected, found));
} else {
// FIXME: this really should be handled at some earlier stage. Our
// handling of region checking when type errors are present is
// *terrible*.
err.span_note(
trace.origin.span(),
trace.cause.span,
&format!("...so that {}",
trace.origin.as_requirement_str()));
trace.cause.as_requirement_str()));
}
}
infer::Reborrow(span) => {
@ -1961,3 +1962,45 @@ fn name_to_dummy_lifetime(name: ast::Name) -> hir::Lifetime {
span: syntax_pos::DUMMY_SP,
name: name }
}
impl<'tcx> ObligationCause<'tcx> {
fn as_failure_str(&self) -> &'static str {
use traits::ObligationCauseCode::*;
match self.code {
CompareImplMethodObligation { .. } => "method not compatible with trait",
MatchExpressionArm { source, .. } => match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
_ => "match arms have incompatible types",
},
IfExpression => "if and else have incompatible types",
IfExpressionWithNoElse => "if may be missing an else clause",
EquatePredicate => "equality predicate not satisfied",
MainFunctionType => "main function has wrong type",
StartFunctionType => "start function has wrong type",
IntrinsicType => "intrinsic has wrong type",
MethodReceiver => "mismatched method receiver",
_ => "mismatched types",
}
}
fn as_requirement_str(&self) -> &'static str {
use traits::ObligationCauseCode::*;
match self.code {
CompareImplMethodObligation { .. } => "method type is compatible with trait",
ExprAssignable => "expression is assignable",
MatchExpressionArm { source, .. } => match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types",
_ => "match arms have compatible types",
},
IfExpression => "if and else have compatible types",
IfExpressionWithNoElse => "if missing an else returns ()",
EquatePredicate => "equality where clause is satisfied",
MainFunctionType => "`main` function has the correct type",
StartFunctionType => "`start` function has the correct type",
IntrinsicType => "intrinsic has the correct type",
MethodReceiver => "method receiver has the correct type",
_ => "types are compatible",
}
}
}

View File

@ -58,7 +58,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// Start a snapshot so we can examine "all bindings that were
// created as part of this type comparison".
return self.infcx.commit_if_ok(|snapshot| {
let span = self.trace.origin.span();
let span = self.trace.cause.span;
// First, we instantiate each bound region in the subtype with a fresh
// region variable.
@ -230,7 +230,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// created as part of this type comparison".
return self.infcx.commit_if_ok(|snapshot| {
// Instantiate each bound region with a fresh region variable.
let span = self.trace.origin.span();
let span = self.trace.cause.span;
let (a_with_fresh, a_map) =
self.infcx.replace_late_bound_regions_with_fresh_var(
span, HigherRankedType, a);
@ -247,7 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// Generalize the regions appearing in result0 if possible
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
let span = self.trace.origin.span();
let span = self.trace.cause.span;
let result1 =
fold_regions_in(
self.tcx(),
@ -325,10 +325,10 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// Instantiate each bound region with a fresh region variable.
let (a_with_fresh, a_map) =
self.infcx.replace_late_bound_regions_with_fresh_var(
self.trace.origin.span(), HigherRankedType, a);
self.trace.cause.span, HigherRankedType, a);
let (b_with_fresh, b_map) =
self.infcx.replace_late_bound_regions_with_fresh_var(
self.trace.origin.span(), HigherRankedType, b);
self.trace.cause.span, HigherRankedType, b);
let a_vars = var_ids(self, &a_map);
let b_vars = var_ids(self, &b_map);
@ -341,7 +341,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> {
// Generalize the regions appearing in result0 if possible
let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot);
let span = self.trace.origin.span();
let span = self.trace.cause.span;
let result1 =
fold_regions_in(
self.tcx(),
@ -463,7 +463,7 @@ fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>,
ty::ReVar(r) => { r }
_ => {
span_bug!(
fields.trace.origin.span(),
fields.trace.cause.span,
"found non-region-vid: {:?}",
r);
}

View File

@ -32,7 +32,7 @@ use ty::{self, Ty, TyCtxt};
use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric};
use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
use ty::relate::{Relate, RelateResult, TypeRelation};
use traits::{self, PredicateObligations, Reveal};
use traits::{self, ObligationCause, PredicateObligations, Reveal};
use rustc_data_structures::unify::{self, UnificationTable};
use std::cell::{Cell, RefCell, Ref, RefMut};
use std::fmt;
@ -173,89 +173,6 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
/// region that each late-bound region was replaced with.
pub type SkolemizationMap<'tcx> = FxHashMap<ty::BoundRegion, &'tcx ty::Region>;
/// Why did we require that the two types be related?
///
/// See `error_reporting.rs` for more details
#[derive(Clone, Copy, Debug)]
pub enum TypeOrigin {
// Not yet categorized in a better way
Misc(Span),
// Checking that method of impl is compatible with trait
MethodCompatCheck(Span),
// Checking that this expression can be assigned where it needs to be
ExprAssignable(Span),
// Relating trait type parameters to those found in impl etc
RelateOutputImplTypes(Span),
// Computing common supertype in the arms of a match expression
MatchExpressionArm(Span, Span, hir::MatchSource),
// Computing common supertype in an if expression
IfExpression(Span),
// Computing common supertype of an if expression with no else counter-part
IfExpressionWithNoElse(Span),
// `where a == b`
EquatePredicate(Span),
// `main` has wrong type
MainFunctionType(Span),
// `start` has wrong type
StartFunctionType(Span),
// intrinsic has wrong type
IntrinsicType(Span),
// method receiver
MethodReceiver(Span),
}
impl TypeOrigin {
fn as_failure_str(&self) -> &'static str {
match self {
&TypeOrigin::Misc(_) |
&TypeOrigin::RelateOutputImplTypes(_) |
&TypeOrigin::ExprAssignable(_) => "mismatched types",
&TypeOrigin::MethodCompatCheck(_) => "method not compatible with trait",
&TypeOrigin::MatchExpressionArm(.., source) => match source {
hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
_ => "match arms have incompatible types",
},
&TypeOrigin::IfExpression(_) => "if and else have incompatible types",
&TypeOrigin::IfExpressionWithNoElse(_) => "if may be missing an else clause",
&TypeOrigin::EquatePredicate(_) => "equality predicate not satisfied",
&TypeOrigin::MainFunctionType(_) => "main function has wrong type",
&TypeOrigin::StartFunctionType(_) => "start function has wrong type",
&TypeOrigin::IntrinsicType(_) => "intrinsic has wrong type",
&TypeOrigin::MethodReceiver(_) => "mismatched method receiver",
}
}
fn as_requirement_str(&self) -> &'static str {
match self {
&TypeOrigin::Misc(_) => "types are compatible",
&TypeOrigin::MethodCompatCheck(_) => "method type is compatible with trait",
&TypeOrigin::ExprAssignable(_) => "expression is assignable",
&TypeOrigin::RelateOutputImplTypes(_) => {
"trait type parameters matches those specified on the impl"
}
&TypeOrigin::MatchExpressionArm(..) => "match arms have compatible types",
&TypeOrigin::IfExpression(_) => "if and else have compatible types",
&TypeOrigin::IfExpressionWithNoElse(_) => "if missing an else returns ()",
&TypeOrigin::EquatePredicate(_) => "equality where clause is satisfied",
&TypeOrigin::MainFunctionType(_) => "`main` function has the correct type",
&TypeOrigin::StartFunctionType(_) => "`start` function has the correct type",
&TypeOrigin::IntrinsicType(_) => "intrinsic has the correct type",
&TypeOrigin::MethodReceiver(_) => "method receiver has the correct type",
}
}
}
/// See `error_reporting.rs` for more details
#[derive(Clone, Debug)]
pub enum ValuePairs<'tcx> {
@ -270,7 +187,7 @@ pub enum ValuePairs<'tcx> {
/// See `error_reporting.rs` for more details.
#[derive(Clone)]
pub struct TypeTrace<'tcx> {
origin: TypeOrigin,
cause: ObligationCause<'tcx>,
values: ValuePairs<'tcx>,
}
@ -1006,14 +923,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn sub_types(&self,
a_is_expected: bool,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> InferResult<'tcx, ()>
{
debug!("sub_types({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
let trace = TypeTrace::types(cause, a_is_expected, a, b);
self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}
@ -1024,7 +941,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-> UnitResult<'tcx>
{
self.probe(|_| {
let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP);
let origin = &ObligationCause::dummy();
let trace = TypeTrace::types(origin, true, a, b);
self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| {
// FIXME(#32730) propagate obligations
@ -1035,20 +952,20 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn eq_types(&self,
a_is_expected: bool,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> InferResult<'tcx, ()>
{
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, a_is_expected, a, b);
let trace = TypeTrace::types(cause, a_is_expected, a, b);
self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
})
}
pub fn eq_trait_refs(&self,
a_is_expected: bool,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
a: ty::TraitRef<'tcx>,
b: ty::TraitRef<'tcx>)
-> InferResult<'tcx, ()>
@ -1056,7 +973,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
debug!("eq_trait_refs({:?} = {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
cause: cause.clone(),
values: TraitRefs(ExpectedFound::new(a_is_expected, a, b))
};
self.equate(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
@ -1065,22 +982,22 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
pub fn eq_impl_headers(&self,
a_is_expected: bool,
origin: TypeOrigin,
cause: &ObligationCause<'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, origin, a_ref, b_ref),
(None, None) => self.eq_types(a_is_expected, origin, a.self_ty, b.self_ty),
(Some(a_ref), Some(b_ref)) => self.eq_trait_refs(a_is_expected, cause, a_ref, b_ref),
(None, None) => self.eq_types(a_is_expected, cause, 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,
origin: TypeOrigin,
cause: ObligationCause<'tcx>,
a: ty::PolyTraitRef<'tcx>,
b: ty::PolyTraitRef<'tcx>)
-> InferResult<'tcx, ()>
@ -1088,7 +1005,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
debug!("sub_poly_trait_refs({:?} <: {:?})", a, b);
self.commit_if_ok(|_| {
let trace = TypeTrace {
origin: origin,
cause: cause,
values: PolyTraitRefs(ExpectedFound::new(a_is_expected, a, b))
};
self.sub(a_is_expected, trace, &a, &b).map(|ok| ok.unit())
@ -1104,16 +1021,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
pub fn equality_predicate(&self,
span: Span,
cause: &ObligationCause<'tcx>,
predicate: &ty::PolyEquatePredicate<'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 eqty_ok = self.eq_types(false, origin, a, b)?;
self.leak_check(false, span, &skol_map, snapshot)?;
let cause_span = cause.span;
let eqty_ok = self.eq_types(false, cause, a, b)?;
self.leak_check(false, cause_span, &skol_map, snapshot)?;
self.pop_skolemized(skol_map, snapshot);
Ok(eqty_ok.unit())
})
@ -1443,26 +1360,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
pub fn report_mismatched_types(&self,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>,
err: TypeError<'tcx>) {
let trace = TypeTrace {
origin: origin,
values: Types(ExpectedFound {
expected: expected,
found: actual
})
};
let trace = TypeTrace::types(cause, true, expected, actual);
self.report_and_explain_type_error(trace, &err).emit();
}
pub fn report_conflicting_default_types(&self,
span: Span,
body_id: ast::NodeId,
expected: type_variable::Default<'tcx>,
actual: type_variable::Default<'tcx>) {
let trace = TypeTrace {
origin: TypeOrigin::Misc(span),
cause: ObligationCause::misc(span, body_id),
values: Types(ExpectedFound {
expected: expected.ty,
found: actual.ty
@ -1507,15 +1419,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
/// See `higher_ranked_match` in `higher_ranked/mod.rs` for more
/// details.
pub fn match_poly_projection_predicate(&self,
origin: TypeOrigin,
cause: ObligationCause<'tcx>,
match_a: ty::PolyProjectionPredicate<'tcx>,
match_b: ty::TraitRef<'tcx>)
-> InferResult<'tcx, HrMatchResult<Ty<'tcx>>>
{
let span = origin.span();
let span = cause.span;
let match_trait_ref = match_a.skip_binder().projection_ty.trait_ref;
let trace = TypeTrace {
origin: origin,
cause: cause,
values: TraitRefs(ExpectedFound::new(true, match_trait_ref, match_b))
};
@ -1664,23 +1576,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
pub fn span(&self) -> Span {
self.origin.span()
self.cause.span
}
pub fn types(origin: TypeOrigin,
pub fn types(cause: &ObligationCause<'tcx>,
a_is_expected: bool,
a: Ty<'tcx>,
b: Ty<'tcx>)
-> TypeTrace<'tcx> {
TypeTrace {
origin: origin,
cause: cause.clone(),
values: Types(ExpectedFound::new(a_is_expected, a, b))
}
}
pub fn dummy(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> TypeTrace<'tcx> {
TypeTrace {
origin: TypeOrigin::Misc(syntax_pos::DUMMY_SP),
cause: ObligationCause::dummy(),
values: Types(ExpectedFound {
expected: tcx.types.err,
found: tcx.types.err,
@ -1691,26 +1603,7 @@ impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> {
impl<'tcx> fmt::Debug for TypeTrace<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TypeTrace({:?})", self.origin)
}
}
impl TypeOrigin {
pub fn span(&self) -> Span {
match *self {
TypeOrigin::MethodCompatCheck(span) => span,
TypeOrigin::ExprAssignable(span) => span,
TypeOrigin::Misc(span) => span,
TypeOrigin::RelateOutputImplTypes(span) => span,
TypeOrigin::MatchExpressionArm(match_span, ..) => match_span,
TypeOrigin::IfExpression(span) => span,
TypeOrigin::IfExpressionWithNoElse(span) => span,
TypeOrigin::EquatePredicate(span) => span,
TypeOrigin::MainFunctionType(span) => span,
TypeOrigin::StartFunctionType(span) => span,
TypeOrigin::IntrinsicType(span) => span,
TypeOrigin::MethodReceiver(span) => span,
}
write!(f, "TypeTrace({:?})", self.cause)
}
}
@ -1787,16 +1680,6 @@ impl RegionVariableOrigin {
}
}
impl<'tcx> TypeFoldable<'tcx> for TypeOrigin {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
self.clone()
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
false
}
}
impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
@ -1824,12 +1707,12 @@ impl<'tcx> TypeFoldable<'tcx> for ValuePairs<'tcx> {
impl<'tcx> TypeFoldable<'tcx> for TypeTrace<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
TypeTrace {
origin: self.origin.fold_with(folder),
cause: self.cause.fold_with(folder),
values: self.values.fold_with(folder)
}
}
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.origin.visit_with(visitor) || self.values.visit_with(visitor)
self.cause.visit_with(visitor) || self.values.visit_with(visitor)
}
}

View File

@ -8,8 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use super::combine::CombineFields;
use super::SubregionOrigin;
use super::combine::CombineFields;
use super::type_variable::{SubtypeOf, SupertypeOf};
use ty::{self, Ty, TyCtxt};
@ -111,11 +111,13 @@ impl<'combine, 'infcx, 'gcx, 'tcx> TypeRelation<'infcx, 'gcx, 'tcx>
-> RelateResult<'tcx, &'tcx ty::Region> {
debug!("{}.regions({:?}, {:?}) self.cause={:?}",
self.tag(), a, b, self.fields.cause);
// FIXME -- we have more fine-grained information available
// from the "cause" field, we could perhaps give more tailored
// error messages.
let origin = SubregionOrigin::Subtype(self.fields.trace.clone());
self.fields.infcx.region_vars.make_subregion(origin, a, b);
Ok(a)
}

View File

@ -14,8 +14,8 @@ use super::{SelectionContext, Obligation, ObligationCause};
use hir::def_id::{DefId, LOCAL_CRATE};
use ty::{self, Ty, TyCtxt};
use infer::{InferCtxt, InferOk, TypeOrigin};
use syntax_pos::DUMMY_SP;
use infer::{InferCtxt, InferOk};
#[derive(Copy, Clone)]
struct InferIsLocal(bool);
@ -55,8 +55,10 @@ 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.
match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header,
&b_impl_header) {
match selcx.infcx().eq_impl_headers(true,
&ObligationCause::dummy(),
&a_impl_header,
&b_impl_header) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());

View File

@ -26,7 +26,7 @@ use super::{
use fmt_macros::{Parser, Piece, Position};
use hir::def_id::DefId;
use infer::{self, InferCtxt, TypeOrigin};
use infer::{self, InferCtxt};
use rustc::lint::builtin::EXTRA_REQUIREMENT_IN_IMPL;
use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use ty::error::ExpectedFound;
@ -100,7 +100,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
self.probe(|_| {
let origin = TypeOrigin::Misc(obligation.cause.span);
let err_buf;
let mut err = &error.err;
let mut values = None;
@ -121,9 +120,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
obligation.cause.clone(),
0
);
let origin = TypeOrigin::Misc(obligation.cause.span);
if let Err(error) = self.eq_types(
false, origin,
false, &obligation.cause,
data.ty, normalized.value
) {
values = Some(infer::ValuePairs::Types(ExpectedFound {
@ -136,10 +134,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
}
let mut diag = struct_span_err!(
self.tcx.sess, origin.span(), E0271,
self.tcx.sess, obligation.cause.span, E0271,
"type mismatch resolving `{}`", predicate
);
self.note_type_err(&mut diag, origin, None, values, err);
self.note_type_err(&mut diag, &obligation.cause, None, values, err);
self.note_obligation_cause(&mut diag, obligation);
diag.emit();
});
@ -529,7 +527,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
ty::Predicate::Equate(ref predicate) => {
let predicate = self.resolve_type_vars_if_possible(predicate);
let err = self.equality_predicate(span,
let err = self.equality_predicate(&obligation.cause,
&predicate).err().unwrap();
struct_span_err!(self.tcx.sess, span, E0278,
"the requirement `{}` is not satisfied (`{}`)",
@ -851,7 +849,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
{
let tcx = self.tcx;
match *cause_code {
ObligationCauseCode::MiscObligation => { }
ObligationCauseCode::ExprAssignable |
ObligationCauseCode::MatchExpressionArm { .. } |
ObligationCauseCode::IfExpression |
ObligationCauseCode::IfExpressionWithNoElse |
ObligationCauseCode::EquatePredicate |
ObligationCauseCode::MainFunctionType |
ObligationCauseCode::StartFunctionType |
ObligationCauseCode::IntrinsicType |
ObligationCauseCode::MethodReceiver |
ObligationCauseCode::MiscObligation => {
}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}

View File

@ -519,11 +519,9 @@ fn process_predicate<'a, 'gcx, 'tcx>(
}
ty::Predicate::Equate(ref binder) => {
match selcx.infcx().equality_predicate(obligation.cause.span, binder) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
Ok(Some(Vec::new()))
match selcx.infcx().equality_predicate(&obligation.cause, binder) {
Ok(InferOk { obligations, value: () }) => {
Ok(Some(obligations))
},
Err(_) => Err(CodeSelectionError(Unimplemented)),
}

View File

@ -15,6 +15,7 @@ pub use self::FulfillmentErrorCode::*;
pub use self::Vtable::*;
pub use self::ObligationCauseCode::*;
use hir;
use hir::def_id::DefId;
use middle::free_region::FreeRegionMap;
use ty::subst::Substs;
@ -148,6 +149,35 @@ pub enum ObligationCauseCode<'tcx> {
trait_item_def_id: DefId,
lint_id: Option<ast::NodeId>,
},
// Checking that this expression can be assigned where it needs to be
// FIXME(eddyb) #11161 is the original Expr required?
ExprAssignable,
// Computing common supertype in the arms of a match expression
MatchExpressionArm { arm_span: Span,
source: hir::MatchSource },
// Computing common supertype in an if expression
IfExpression,
// Computing common supertype of an if expression with no else counter-part
IfExpressionWithNoElse,
// `where a == b`
EquatePredicate,
// `main` has wrong type
MainFunctionType,
// `start` has wrong type
StartFunctionType,
// intrinsic has wrong type
IntrinsicType,
// method receiver
MethodReceiver,
}
#[derive(Clone, Debug, PartialEq, Eq)]

View File

@ -24,7 +24,7 @@ use super::VtableImplData;
use super::util;
use hir::def_id::DefId;
use infer::{InferOk, TypeOrigin};
use infer::InferOk;
use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
use syntax::parse::token;
use syntax::ast;
@ -209,11 +209,8 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>(
obligations);
let infcx = selcx.infcx();
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
match infcx.eq_types(true, origin, normalized_ty, obligation.predicate.ty) {
Ok(InferOk { obligations: inferred_obligations, .. }) => {
// FIXME(#32730) once obligations are generated in inference, drop this assertion
assert!(inferred_obligations.is_empty());
match infcx.eq_types(true, &obligation.cause, normalized_ty, obligation.predicate.ty) {
Ok(InferOk { obligations: inferred_obligations, value: () }) => {
obligations.extend(inferred_obligations);
Ok(Some(obligations))
},
@ -840,18 +837,18 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
let same_name = data.item_name() == obligation.predicate.item_name;
let is_match = same_name && infcx.probe(|_| {
let origin = TypeOrigin::Misc(obligation.cause.span);
let data_poly_trait_ref =
data.to_poly_trait_ref();
let obligation_poly_trait_ref =
obligation_trait_ref.to_poly_trait_ref();
infcx.sub_poly_trait_refs(false,
origin,
obligation.cause.clone(),
data_poly_trait_ref,
obligation_poly_trait_ref)
// FIXME(#32730) once obligations are propagated from unification in
// inference, drop this assertion
.map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
.map(|InferOk { obligations: _, value: () }| {
// FIXME(#32730) -- do we need to take obligations
// into account in any way? At the moment, no.
})
.is_ok()
});
@ -1153,12 +1150,11 @@ fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
// select those with a relevant trait-ref
let mut env_predicates = env_predicates.filter(|data| {
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
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,
origin,
obligation.cause.clone(),
data_poly_trait_ref,
obligation_poly_trait_ref).is_ok()
})
@ -1187,12 +1183,10 @@ fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>(
fn_pointer_vtable: VtableFnPointerData<'tcx, PredicateObligation<'tcx>>)
-> Progress<'tcx>
{
// FIXME(#32730) drop this assertion once obligations are propagated from inference (fn pointer
// vtable nested obligations ONLY come from unification in inference)
assert!(fn_pointer_vtable.nested.is_empty());
let fn_type = selcx.infcx().shallow_resolve(fn_pointer_vtable.fn_ty);
let sig = fn_type.fn_sig();
confirm_callable_candidate(selcx, obligation, sig, util::TupleArgumentsFlag::Yes)
.with_addl_obligations(fn_pointer_vtable.nested)
}
fn confirm_closure_candidate<'cx, 'gcx, 'tcx>(
@ -1265,12 +1259,10 @@ fn confirm_param_env_candidate<'cx, 'gcx, 'tcx>(
-> Progress<'tcx>
{
let infcx = selcx.infcx();
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
let cause = obligation.cause.clone();
let trait_ref = obligation.predicate.trait_ref;
match infcx.match_poly_projection_predicate(origin, poly_projection, trait_ref) {
match infcx.match_poly_projection_predicate(cause, poly_projection, trait_ref) {
Ok(InferOk { value: ty_match, obligations }) => {
// FIXME(#32730) once obligations are generated in inference, drop this assertion
assert!(obligations.is_empty());
Progress {
ty: ty_match.value,
obligations: obligations,

View File

@ -35,7 +35,7 @@ use super::util;
use hir::def_id::DefId;
use infer;
use infer::{InferCtxt, InferOk, TypeFreshener, TypeOrigin};
use infer::{InferCtxt, InferOk, TypeFreshener};
use ty::subst::{Kind, Subst, Substs};
use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
use traits;
@ -418,9 +418,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
None => Ok(None),
Some(candidate) => {
let mut candidate = self.confirm_candidate(obligation, candidate)?;
// FIXME(#32730) remove this assertion once inferred obligations are propagated
// from inference
assert!(self.inferred_obligations.len() == 0);
let inferred_obligations = (*self.inferred_obligations).into_iter().cloned();
candidate.nested_obligations_mut().extend(inferred_obligations);
Ok(Some(candidate))
@ -521,7 +518,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
ty::Predicate::Equate(ref p) => {
// does this code ever run?
match self.infcx.equality_predicate(obligation.cause.span, p) {
match self.infcx.equality_predicate(&obligation.cause, p) {
Ok(InferOk { obligations, .. }) => {
self.inferred_obligations.extend(obligations);
EvaluatedToOk
@ -1247,9 +1244,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
-> bool
{
assert!(!skol_trait_ref.has_escaping_regions());
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
let cause = obligation.cause.clone();
match self.infcx.sub_poly_trait_refs(false,
origin,
cause,
trait_bound.clone(),
ty::Binder(skol_trait_ref.clone())) {
Ok(InferOk { obligations, .. }) => {
@ -2439,16 +2436,14 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
/// selection of the impl. Therefore, if there is a mismatch, we
/// report an error to the user.
fn confirm_poly_trait_refs(&mut self,
obligation_cause: ObligationCause,
obligation_cause: ObligationCause<'tcx>,
obligation_trait_ref: ty::PolyTraitRef<'tcx>,
expected_trait_ref: ty::PolyTraitRef<'tcx>)
-> Result<(), SelectionError<'tcx>>
{
let origin = TypeOrigin::RelateOutputImplTypes(obligation_cause.span);
let obligation_trait_ref = obligation_trait_ref.clone();
self.infcx.sub_poly_trait_refs(false,
origin,
obligation_cause.clone(),
expected_trait_ref.clone(),
obligation_trait_ref.clone())
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))
@ -2482,9 +2477,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
builtin_bounds: data_b.builtin_bounds,
projection_bounds: data_a.projection_bounds.clone(),
});
let origin = TypeOrigin::Misc(obligation.cause.span);
let InferOk { obligations, .. } =
self.infcx.sub_types(false, origin, new_trait, target)
self.infcx.sub_types(false, &obligation.cause, new_trait, target)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
@ -2553,9 +2547,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
// [T; n] -> [T].
(&ty::TyArray(a, _), &ty::TySlice(b)) => {
let origin = TypeOrigin::Misc(obligation.cause.span);
let InferOk { obligations, .. } =
self.infcx.sub_types(false, origin, a, b)
self.infcx.sub_types(false, &obligation.cause, a, b)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
}
@ -2617,9 +2610,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
}
});
let new_struct = tcx.mk_adt(def, tcx.mk_substs(params));
let origin = TypeOrigin::Misc(obligation.cause.span);
let InferOk { obligations, .. } =
self.infcx.sub_types(false, origin, new_struct, target)
self.infcx.sub_types(false, &obligation.cause, new_struct, target)
.map_err(|_| Unimplemented)?;
self.inferred_obligations.extend(obligations);
@ -2705,10 +2697,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
impl_trait_ref,
skol_obligation_trait_ref);
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
let InferOk { obligations, .. } =
self.infcx.eq_trait_refs(false,
origin,
&obligation.cause,
impl_trait_ref.value.clone(),
skol_obligation_trait_ref)
.map_err(|e| {
@ -2780,9 +2771,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
obligation,
poly_trait_ref);
let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
self.infcx.sub_poly_trait_refs(false,
origin,
obligation.cause.clone(),
poly_trait_ref,
obligation.predicate.to_poly_trait_ref())
.map(|InferOk { obligations, .. }| self.inferred_obligations.extend(obligations))

View File

@ -22,7 +22,7 @@ use super::util::impl_trait_ref_and_oblig;
use rustc_data_structures::fx::FxHashMap;
use hir::def_id::DefId;
use infer::{InferCtxt, InferOk, TypeOrigin};
use infer::{InferCtxt, InferOk};
use middle::region;
use ty::subst::{Subst, Substs};
use traits::{self, Reveal, ObligationCause};
@ -223,8 +223,10 @@ 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, TypeOrigin::Misc(DUMMY_SP), source_trait_ref,
target_trait_ref) {
match infcx.eq_trait_refs(true,
&ObligationCause::dummy(),
source_trait_ref,
target_trait_ref) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty())

View File

@ -213,6 +213,34 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
lint_id: lint_id,
})
}
super::ExprAssignable => {
Some(super::ExprAssignable)
}
super::MatchExpressionArm { arm_span, source } => {
Some(super::MatchExpressionArm { arm_span: arm_span,
source: source })
}
super::IfExpression => {
Some(super::IfExpression)
}
super::IfExpressionWithNoElse => {
Some(super::IfExpressionWithNoElse)
}
super::EquatePredicate => {
Some(super::EquatePredicate)
}
super::MainFunctionType => {
Some(super::MainFunctionType)
}
super::StartFunctionType => {
Some(super::StartFunctionType)
}
super::IntrinsicType => {
Some(super::IntrinsicType)
}
super::MethodReceiver => {
Some(super::MethodReceiver)
}
}
}
}
@ -461,6 +489,15 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for Normalized<'tcx, T> {
impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
super::ExprAssignable |
super::MatchExpressionArm { arm_span: _, source: _ } |
super::IfExpression |
super::IfExpressionWithNoElse |
super::EquatePredicate |
super::MainFunctionType |
super::StartFunctionType |
super::IntrinsicType |
super::MethodReceiver |
super::MiscObligation |
super::SliceOrArrayElem |
super::TupleElem |
@ -497,6 +534,15 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
super::ExprAssignable |
super::MatchExpressionArm { arm_span: _, source: _ } |
super::IfExpression |
super::IfExpressionWithNoElse |
super::EquatePredicate |
super::MainFunctionType |
super::StartFunctionType |
super::IntrinsicType |
super::MethodReceiver |
super::MiscObligation |
super::SliceOrArrayElem |
super::TupleElem |

View File

@ -21,9 +21,9 @@ use rustc::middle::region::CodeExtentData;
use rustc::middle::resolve_lifetime;
use rustc::middle::stability;
use rustc::ty::subst::{Kind, Subst};
use rustc::traits::Reveal;
use rustc::traits::{ObligationCause, Reveal};
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::infer::{self, InferOk, InferResult, TypeOrigin};
use rustc::infer::{self, InferOk, InferResult};
use rustc_metadata::cstore::CStore;
use rustc::hir::map as hir_map;
use rustc::session::{self, config};
@ -36,7 +36,6 @@ use errors::emitter::Emitter;
use errors::{Level, DiagnosticBuilder};
use syntax::parse::token;
use syntax::feature_gate::UnstableFeatures;
use syntax_pos::DUMMY_SP;
use rustc::hir;
@ -245,7 +244,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
}
pub fn make_subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
match self.infcx.sub_types(true, TypeOrigin::Misc(DUMMY_SP), a, b) {
match self.infcx.sub_types(true, &ObligationCause::dummy(), a, b) {
Ok(_) => true,
Err(ref e) => panic!("Encountered error: {}", e),
}

View File

@ -306,32 +306,43 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
pub struct TypeChecker<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
fulfillment_cx: traits::FulfillmentContext<'tcx>,
last_span: Span
last_span: Span,
body_id: ast::NodeId,
}
impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, body_id: ast::NodeId) -> Self {
TypeChecker {
infcx: infcx,
fulfillment_cx: traits::FulfillmentContext::new(),
last_span: DUMMY_SP
last_span: DUMMY_SP,
body_id: body_id,
}
}
fn sub_types(&self, span: Span, sup: Ty<'tcx>, sub: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
self.infcx.sub_types(false, infer::TypeOrigin::Misc(span), sup, sub)
// FIXME(#32730) propagate obligations
.map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
fn misc(&self, span: Span) -> traits::ObligationCause<'tcx> {
traits::ObligationCause::misc(span, self.body_id)
}
fn eq_types(&self, span: Span, a: Ty<'tcx>, b: Ty<'tcx>)
pub fn register_infer_ok_obligations<T>(&mut self, infer_ok: InferOk<'tcx, T>) -> T {
for obligation in infer_ok.obligations {
self.fulfillment_cx.register_predicate_obligation(self.infcx, obligation);
}
infer_ok.value
}
fn sub_types(&mut self, sup: Ty<'tcx>, sub: Ty<'tcx>)
-> infer::UnitResult<'tcx>
{
self.infcx.sub_types(false, &self.misc(self.last_span), 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, infer::TypeOrigin::Misc(span), a, b)
// FIXME(#32730) propagate obligations
.map(|InferOk { obligations, .. }| assert!(obligations.is_empty()))
self.infcx.eq_types(false, &self.misc(span), a, b)
.map(|ok| self.register_infer_ok_obligations(ok))
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
@ -346,7 +357,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
let lv_ty = lv.ty(mir, tcx).to_ty(tcx);
let rv_ty = rv.ty(mir, tcx);
if let Some(rv_ty) = rv_ty {
if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
span_mirbug!(self, stmt, "bad assignment ({:?} = {:?}): {:?}",
lv_ty, rv_ty, terr);
}
@ -407,7 +418,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
} => {
let lv_ty = location.ty(mir, tcx).to_ty(tcx);
let rv_ty = value.ty(mir, tcx);
if let Err(terr) = self.sub_types(self.last_span, rv_ty, lv_ty) {
if let Err(terr) = self.sub_types(rv_ty, lv_ty) {
span_mirbug!(self, term, "bad DropAndReplace ({:?} = {:?}): {:?}",
lv_ty, rv_ty, terr);
}
@ -424,7 +435,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
TerminatorKind::SwitchInt { ref discr, switch_ty, .. } => {
let discr_ty = discr.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.sub_types(self.last_span, discr_ty, switch_ty) {
if let Err(terr) = self.sub_types(discr_ty, switch_ty) {
span_mirbug!(self, term, "bad SwitchInt ({:?} on {:?}): {:?}",
switch_ty, discr_ty, terr);
}
@ -486,7 +497,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
fn check_call_dest(&self,
fn check_call_dest(&mut self,
mir: &Mir<'tcx>,
term: &Terminator<'tcx>,
sig: &ty::FnSig<'tcx>,
@ -495,7 +506,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
match *destination {
Some((ref dest, _)) => {
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.sub_types(self.last_span, sig.output, dest_ty) {
if let Err(terr) = self.sub_types(sig.output, dest_ty) {
span_mirbug!(self, term,
"call dest mismatch ({:?} <- {:?}): {:?}",
dest_ty, sig.output, terr);
@ -510,7 +521,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
fn check_call_inputs(&self,
fn check_call_inputs(&mut self,
mir: &Mir<'tcx>,
term: &Terminator<'tcx>,
sig: &ty::FnSig<'tcx>,
@ -523,7 +534,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
for (n, (fn_arg, op_arg)) in sig.inputs.iter().zip(args).enumerate() {
let op_arg_ty = op_arg.ty(mir, self.tcx());
if let Err(terr) = self.sub_types(self.last_span, op_arg_ty, fn_arg) {
if let Err(terr) = self.sub_types(op_arg_ty, fn_arg) {
span_mirbug!(self, term, "bad arg #{:?} ({:?} <- {:?}): {:?}",
n, fn_arg, op_arg_ty, terr);
}
@ -541,7 +552,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
}
fn check_box_free_inputs(&self,
fn check_box_free_inputs(&mut self,
mir: &Mir<'tcx>,
term: &Terminator<'tcx>,
sig: &ty::FnSig<'tcx>,
@ -578,7 +589,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
};
if let Err(terr) = self.sub_types(self.last_span, arg_ty, pointee_ty) {
if let Err(terr) = self.sub_types(arg_ty, pointee_ty) {
span_mirbug!(self, term, "bad box_free arg ({:?} <- {:?}): {:?}",
pointee_ty, arg_ty, terr);
}
@ -715,7 +726,7 @@ impl<'tcx> MirPass<'tcx> for TypeckMir {
}
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
tcx.infer_ctxt(None, Some(param_env), Reveal::NotSpecializable).enter(|infcx| {
let mut checker = TypeChecker::new(&infcx);
let mut checker = TypeChecker::new(&infcx, src.item_id());
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
verifier.visit_mir(mir);

View File

@ -11,7 +11,8 @@
use rustc::hir::{self, PatKind};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::infer;
use rustc::traits::ObligationCauseCode;
use rustc::ty::{self, Ty, TypeFoldable, LvaluePreference};
use check::{FnCtxt, Expectation, Diverges};
use util::nodemap::FxHashMap;
@ -450,17 +451,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => false
};
let origin = if is_if_let_fallback {
TypeOrigin::IfExpressionWithNoElse(expr.span)
let cause = if is_if_let_fallback {
self.cause(expr.span, ObligationCauseCode::IfExpressionWithNoElse)
} else {
TypeOrigin::MatchExpressionArm(expr.span, arm.body.span, match_src)
self.cause(expr.span, ObligationCauseCode::MatchExpressionArm {
arm_span: arm.body.span,
source: match_src
})
};
let result = if is_if_let_fallback {
self.eq_types(true, origin, arm_ty, result_ty)
.map(|InferOk { obligations, .. }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
self.eq_types(true, &cause, arm_ty, result_ty)
.map(|infer_ok| {
self.register_infer_ok_obligations(infer_ok);
arm_ty
})
} else if i == 0 {
@ -468,7 +471,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.try_coerce(&arm.body, arm_ty, coerce_first)
} else {
let prev_arms = || arms[..i].iter().map(|arm| &*arm.body);
self.try_find_coercion_lub(origin, prev_arms, result_ty, &arm.body, arm_ty)
self.try_find_coercion_lub(&cause, prev_arms, result_ty, &arm.body, arm_ty)
};
result_ty = match result {
@ -479,7 +482,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} else {
(result_ty, arm_ty)
};
self.report_mismatched_types(origin, expected, found, e);
self.report_mismatched_types(&cause, expected, found, e);
self.tcx.types.err
}
};

View File

@ -63,8 +63,8 @@
use check::FnCtxt;
use rustc::hir;
use rustc::infer::{Coercion, InferOk, TypeOrigin, TypeTrace};
use rustc::traits::{self, ObligationCause};
use rustc::infer::{Coercion, InferOk, TypeTrace};
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
use rustc::ty::fold::TypeFoldable;
@ -78,7 +78,7 @@ use std::ops::Deref;
struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
origin: TypeOrigin,
cause: ObligationCause<'tcx>,
use_lub: bool,
unsizing_obligations: RefCell<Vec<traits::PredicateObligation<'tcx>>>,
}
@ -104,10 +104,10 @@ fn coerce_mutbls<'tcx>(from_mutbl: hir::Mutability,
}
impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, origin: TypeOrigin) -> Self {
fn new(fcx: &'f FnCtxt<'f, 'gcx, 'tcx>, cause: ObligationCause<'tcx>) -> Self {
Coerce {
fcx: fcx,
origin: origin,
cause: cause,
use_lub: false,
unsizing_obligations: RefCell::new(vec![]),
}
@ -115,19 +115,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
self.commit_if_ok(|_| {
let trace = TypeTrace::types(self.origin, false, a, b);
let trace = TypeTrace::types(&self.cause, false, a, b);
if self.use_lub {
self.lub(false, trace, &a, &b)
.map(|InferOk { value, obligations }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
value
})
.map(|ok| self.register_infer_ok_obligations(ok))
} else {
self.sub(false, trace, &a, &b)
.map(|InferOk { value, obligations }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
self.fcx.register_predicates(obligations);
value
})
}
@ -238,7 +233,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
_ => return self.unify_and_identity(a, b),
};
let span = self.origin.span();
let span = self.cause.span;
let mut first_error = None;
let mut r_borrow_var = None;
@ -430,7 +425,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
(&ty::TyRef(_, mt_a), &ty::TyRef(_, mt_b)) => {
coerce_mutbls(mt_a.mutbl, mt_b.mutbl)?;
let coercion = Coercion(self.origin.span());
let coercion = Coercion(self.cause.span);
let r_borrow = self.next_region_var(coercion);
(mt_a.ty, Some(AutoBorrow::Ref(r_borrow, mt_b.mutbl)))
}
@ -449,7 +444,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
let mut leftover_predicates = vec![];
// Create an obligation for `Source: CoerceUnsized<Target>`.
let cause = ObligationCause::misc(self.origin.span(), self.body_id);
let cause = ObligationCause::misc(self.cause.span, self.body_id);
queue.push_back(self.tcx
.predicate_for_trait_def(cause, coerce_unsized_did, 0, source, &[target]));
@ -635,7 +630,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let source = self.resolve_type_vars_with_obligations(expr_ty);
debug!("coercion::try({:?}: {:?} -> {:?})", expr, source, target);
let mut coerce = Coerce::new(self, TypeOrigin::ExprAssignable(expr.span));
let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable);
let mut coerce = Coerce::new(self, cause);
self.commit_if_ok(|_| {
let adjustment = apply(&mut coerce, &|| Some(expr), source, target)?;
if !adjustment.is_identity() {
@ -655,7 +651,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
/// tries to unify the types, potentially inserting coercions on any of the
/// provided expressions and returns their LUB (aka "common supertype").
pub fn try_find_coercion_lub<'b, E, I>(&self,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
exprs: E,
prev_ty: Ty<'tcx>,
new: &'b hir::Expr,
@ -669,7 +665,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let new_ty = self.resolve_type_vars_with_obligations(new_ty);
debug!("coercion::try_find_lub({:?}, {:?})", prev_ty, new_ty);
let trace = TypeTrace::types(origin, true, prev_ty, new_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.
@ -677,21 +673,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
(&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(), &a_fty, &b_fty)
.map(|InferOk { value, obligations }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
value
})?;
.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(), &a_substs, &b_substs)
.map(|InferOk { value, obligations }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
value
})
.map(|ok| self.register_infer_ok_obligations(ok))
});
if let Ok(substs) = substs {
@ -715,7 +703,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
_ => {}
}
let mut coerce = Coerce::new(self, origin);
let mut coerce = Coerce::new(self, cause.clone());
coerce.use_lub = true;
// First try to coerce the new expression to the type of the previous ones,
@ -760,11 +748,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if !noop {
return self.commit_if_ok(|_| {
self.lub(true, trace.clone(), &prev_ty, &new_ty)
.map(|InferOk { value, obligations }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
value
})
.map(|ok| self.register_infer_ok_obligations(ok))
});
}
}
@ -777,11 +761,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
} else {
self.commit_if_ok(|_| {
self.lub(true, trace, &prev_ty, &new_ty)
.map(|InferOk { value, obligations }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
value
})
.map(|ok| self.register_infer_ok_obligations(ok))
})
}
}

View File

@ -9,10 +9,10 @@
// except according to those terms.
use rustc::hir;
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::infer::{self, InferOk};
use rustc::middle::free_region::FreeRegionMap;
use rustc::ty;
use rustc::traits::{self, Reveal};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, Substs};
use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
@ -95,6 +95,17 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let trait_to_impl_substs = impl_trait_ref.substs;
let cause = ObligationCause {
span: impl_m_span,
body_id: impl_m_body_id,
code: ObligationCauseCode::CompareImplMethodObligation {
item_name: impl_m.name,
impl_item_def_id: impl_m.def_id,
trait_item_def_id: trait_m.def_id,
lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None },
},
};
// This code is best explained by example. Consider a trait:
//
// trait Trait<'t,T> {
@ -235,20 +246,9 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let traits::Normalized { value: predicate, .. } =
traits::normalize(&mut selcx, normalize_cause.clone(), &predicate);
let cause = traits::ObligationCause {
span: impl_m_span,
body_id: impl_m_body_id,
code: traits::ObligationCauseCode::CompareImplMethodObligation {
item_name: impl_m.name,
impl_item_def_id: impl_m.def_id,
trait_item_def_id: trait_m.def_id,
lint_id: if !old_broken_mode { Some(impl_m_body_id) } else { None },
},
};
fulfillment_cx.borrow_mut().register_predicate_obligation(
&infcx,
traits::Obligation::new(cause, predicate));
traits::Obligation::new(cause.clone(), predicate));
}
// We now need to check that the signature of the impl method is
@ -266,7 +266,6 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
// Compute skolemized form of impl and trait method tys.
let tcx = infcx.tcx;
let origin = TypeOrigin::MethodCompatCheck(impl_m_span);
let m_fty = |method: &ty::AssociatedItem| {
match tcx.item_type(method.def_id).sty {
@ -315,7 +314,7 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
let sub_result = infcx.sub_types(false, origin, impl_fty, trait_fty)
let sub_result = infcx.sub_types(false, &cause, impl_fty, trait_fty)
.map(|InferOk { obligations, .. }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
@ -328,22 +327,25 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
let (impl_err_span, trait_err_span) = extract_spans_for_error_reporting(&infcx,
&terr,
origin,
&cause,
impl_m,
impl_sig,
trait_m,
trait_sig);
let origin = TypeOrigin::MethodCompatCheck(impl_err_span);
let cause = ObligationCause {
span: impl_err_span,
..cause.clone()
};
let mut diag = struct_span_err!(tcx.sess,
origin.span(),
cause.span,
E0053,
"method `{}` has an incompatible type for trait",
trait_m.name);
infcx.note_type_err(&mut diag,
origin,
&cause,
trait_err_span.map(|sp| (sp, format!("type in trait"))),
Some(infer::ValuePairs::Types(ExpectedFound {
expected: trait_fty,
@ -429,7 +431,7 @@ fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a, 'gcx, 'tcx>,
terr: &TypeError,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
impl_m: &ty::AssociatedItem,
impl_sig: ty::FnSig<'tcx>,
trait_m: &ty::AssociatedItem,
@ -478,9 +480,9 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
}
}
})
.unwrap_or((origin.span(), tcx.map.span_if_local(trait_m.def_id)))
.unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
} else {
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
(cause.span, tcx.map.span_if_local(trait_m.def_id))
}
}
TypeError::Sorts(ExpectedFound { .. }) => {
@ -499,25 +501,25 @@ fn extract_spans_for_error_reporting<'a, 'gcx, 'tcx>(infcx: &infer::InferCtxt<'a
.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, origin, trait_arg_ty, impl_arg_ty) {
match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
Ok(_) => None,
Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
}
})
.next()
.unwrap_or_else(|| {
if infcx.sub_types(false, origin, impl_sig.output, trait_sig.output)
if infcx.sub_types(false, &cause, impl_sig.output, trait_sig.output)
.is_err() {
(impl_m_output.span(), Some(trait_m_output.span()))
} else {
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
(cause.span, tcx.map.span_if_local(trait_m.def_id))
}
})
} else {
(origin.span(), tcx.map.span_if_local(trait_m.def_id))
(cause.span, tcx.map.span_if_local(trait_m.def_id))
}
}
_ => (origin.span(), tcx.map.span_if_local(trait_m.def_id)),
_ => (cause.span, tcx.map.span_if_local(trait_m.def_id)),
}
}
@ -787,7 +789,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
// Compute skolemized form of impl and trait const tys.
let impl_ty = tcx.item_type(impl_c.def_id).subst(tcx, impl_to_skol_substs);
let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs);
let mut origin = TypeOrigin::Misc(impl_c_span);
let mut cause = ObligationCause::misc(impl_c_span, impl_c_node_id);
let err = infcx.commit_if_ok(|_| {
// There is no "body" here, so just pass dummy id.
@ -807,11 +809,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
infcx.sub_types(false, origin, impl_ty, trait_ty)
.map(|InferOk { obligations, .. }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty())
})
infcx.sub_types(false, &cause, impl_ty, trait_ty)
.map(|InferOk { obligations, value: () }| {
for obligation in obligations {
fulfillment_cx.register_predicate_obligation(&infcx, obligation);
}
})
});
if let Err(terr) = err {
@ -821,12 +824,12 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
// Locate the Span containing just the type of the offending impl
match tcx.map.expect_impl_item(impl_c_node_id).node {
ImplItemKind::Const(ref ty, _) => origin = TypeOrigin::Misc(ty.span),
ImplItemKind::Const(ref ty, _) => cause.span = ty.span,
_ => bug!("{:?} is not a impl const", impl_c),
}
let mut diag = struct_span_err!(tcx.sess,
origin.span(),
cause.span,
E0326,
"implemented const `{}` has an incompatible type for \
trait",
@ -840,7 +843,7 @@ pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
};
infcx.note_type_err(&mut diag,
origin,
&cause,
Some((trait_c_span, format!("type in trait"))),
Some(infer::ValuePairs::Types(ExpectedFound {
expected: trait_ty,

View File

@ -11,7 +11,8 @@
use check::FnCtxt;
use rustc::ty::Ty;
use rustc::infer::{InferOk, TypeOrigin};
use rustc::infer::{InferOk};
use rustc::traits::ObligationCause;
use syntax_pos::Span;
use rustc::hir;
@ -20,34 +21,32 @@ 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 origin = TypeOrigin::Misc(sp);
match self.sub_types(false, origin, actual, expected) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
let cause = self.misc(sp);
match self.sub_types(false, &cause, actual, expected) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
},
Err(e) => {
self.report_mismatched_types(origin, expected, actual, e);
self.report_mismatched_types(&cause, expected, actual, e);
}
}
}
pub fn demand_eqtype(&self, sp: Span, expected: Ty<'tcx>, actual: Ty<'tcx>) {
self.demand_eqtype_with_origin(TypeOrigin::Misc(sp), expected, actual);
self.demand_eqtype_with_origin(&self.misc(sp), expected, actual);
}
pub fn demand_eqtype_with_origin(&self,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>)
{
match self.eq_types(false, origin, actual, expected) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
match self.eq_types(false, cause, actual, expected) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
},
Err(e) => {
self.report_mismatched_types(origin, expected, actual, e);
self.report_mismatched_types(cause, expected, actual, e);
}
}
}
@ -56,9 +55,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
pub fn demand_coerce(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, expected: Ty<'tcx>) {
let expected = self.resolve_type_vars_with_obligations(expected);
if let Err(e) = self.try_coerce(expr, checked_ty, expected) {
let origin = TypeOrigin::Misc(expr.span);
let cause = self.misc(expr.span);
let expr_ty = self.resolve_type_vars_with_obligations(checked_ty);
self.report_mismatched_types(origin, expected, expr_ty, e);
self.report_mismatched_types(&cause, expected, expr_ty, e);
}
}
}

View File

@ -17,7 +17,7 @@ use rustc::infer::{self, InferOk};
use middle::region;
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::traits::{self, Reveal};
use rustc::traits::{self, ObligationCause, Reveal};
use util::nodemap::FxHashSet;
use syntax::ast;
@ -93,8 +93,8 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
infcx.fresh_substs_for_item(drop_impl_span, drop_impl_did);
let fresh_impl_self_ty = drop_impl_ty.subst(tcx, fresh_impl_substs);
match infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span),
named_type, fresh_impl_self_ty) {
let cause = &ObligationCause::misc(drop_impl_span, drop_impl_node_id);
match infcx.eq_types(true, cause, named_type, fresh_impl_self_ty) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());

View File

@ -12,7 +12,7 @@
//! intrinsics that the compiler exposes.
use intrinsics;
use rustc::infer::TypeOrigin;
use rustc::traits::{ObligationCause, ObligationCauseCode};
use rustc::ty::subst::Substs;
use rustc::ty::FnSig;
use rustc::ty::{self, Ty};
@ -63,7 +63,9 @@ fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
.emit();
} else {
require_same_types(ccx,
TypeOrigin::IntrinsicType(it.span),
&ObligationCause::new(it.span,
it.id,
ObligationCauseCode::IntrinsicType),
tcx.item_type(def_id),
fty);
}

View File

@ -17,7 +17,7 @@ use rustc::traits;
use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
use rustc::ty::fold::TypeFoldable;
use rustc::infer::{self, InferOk, TypeOrigin};
use rustc::infer::{self, InferOk};
use syntax_pos::Span;
use rustc::hir;
@ -330,10 +330,9 @@ 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, TypeOrigin::Misc(self.span), self_ty, method_self_ty) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
match self.sub_types(false, &self.misc(self.span), self_ty, method_self_ty) {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
Err(_) => {
span_bug!(self.span,

View File

@ -16,13 +16,13 @@ use super::suggest;
use check::FnCtxt;
use hir::def_id::DefId;
use hir::def::Def;
use rustc::infer::InferOk;
use rustc::ty::subst::{Subst, Substs};
use rustc::traits;
use rustc::traits::{self, ObligationCause};
use rustc::ty::{self, Ty, ToPolyTraitRef, TraitRef, TypeFoldable};
use rustc::infer::{InferOk, TypeOrigin};
use rustc::util::nodemap::FxHashSet;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::Span;
use rustc::hir;
use std::mem;
use std::ops::Deref;
@ -1032,10 +1032,10 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
self.probe(|_| {
// First check that the self type can be related.
match self.sub_types(false,
TypeOrigin::Misc(DUMMY_SP),
&ObligationCause::dummy(),
self_ty,
probe.xform_self_ty) {
Ok(InferOk { obligations, .. }) => {
Ok(InferOk { obligations, value: () }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty())
}

View File

@ -87,9 +87,9 @@ use hir::def::{Def, CtorKind, PathResolution};
use hir::def_id::{DefId, LOCAL_CRATE};
use hir::pat_util;
use rustc::infer::{self, InferCtxt, InferOk, RegionVariableOrigin,
TypeOrigin, TypeTrace, type_variable};
TypeTrace, type_variable};
use rustc::ty::subst::{Kind, Subst, Substs};
use rustc::traits::{self, Reveal};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::{ParamTy, ParameterEnvironment};
use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
@ -1521,6 +1521,17 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
pub fn cause(&self,
span: Span,
code: ObligationCauseCode<'tcx>)
-> ObligationCause<'tcx> {
ObligationCause::new(span, self.body_id, code)
}
pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
self.cause(span, ObligationCauseCode::MiscObligation)
}
/// Resolves type variables in `ty` if possible. Unlike the infcx
/// version (resolve_type_vars_if_possible), this version will
/// also select obligations if it seems useful, in an effort
@ -1786,6 +1797,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
.register_predicate_obligation(self, obligation);
}
pub fn register_predicates(&self,
obligations: Vec<traits::PredicateObligation<'tcx>>)
{
for obligation in obligations {
self.register_predicate(obligation);
}
}
pub fn register_infer_ok_obligations<T>(&self, infer_ok: InferOk<'tcx, T>) -> T {
self.register_predicates(infer_ok.obligations);
infer_ok.value
}
pub fn to_ty(&self, ast_t: &hir::Ty) -> Ty<'tcx> {
let t = AstConv::ast_ty_to_ty(self, self, ast_t);
self.register_wf_obligation(t, ast_t.span, traits::MiscObligation);
@ -2096,15 +2120,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(default) = default_map.get(ty) {
let default = default.clone();
match self.eq_types(false,
TypeOrigin::Misc(default.origin_span),
ty, default.ty) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty())
},
Err(_) => {
conflicts.push((*ty, default));
}
&self.misc(default.origin_span),
ty,
default.ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => conflicts.push((*ty, default)),
}
}
}
@ -2146,6 +2166,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.report_conflicting_default_types(
first_default.origin_span,
self.body_id,
first_default,
second_default)
}
@ -2194,10 +2215,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(default) = default_map.get(ty) {
let default = default.clone();
match self.eq_types(false,
TypeOrigin::Misc(default.origin_span),
ty, default.ty) {
// FIXME(#32730) propagate obligations
Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
&self.misc(default.origin_span),
ty,
default.ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
result = Some(default);
}
@ -2765,13 +2786,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// return type (likely containing type variables if the function
// is polymorphic) and the expected return type.
// No argument expectations are produced if unification fails.
let origin = TypeOrigin::Misc(call_span);
let ures = self.sub_types(false, origin, formal_ret, ret_ty);
let origin = self.misc(call_span);
let ures = self.sub_types(false, &origin, formal_ret, ret_ty);
// FIXME(#15760) can't use try! here, FromError doesn't default
// to identity so the resulting type is not constrained.
match ures {
// FIXME(#32730) propagate obligations
Ok(InferOk { obligations, .. }) => assert!(obligations.is_empty()),
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(e) => return Err(e),
}
@ -2852,16 +2872,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
self.diverges.set(Diverges::Maybe);
let unit = self.tcx.mk_nil();
let (origin, expected, found, result) =
let (cause, expected_ty, found_ty, result);
if let Some(else_expr) = opt_else_expr {
let else_ty = self.check_expr_with_expectation(else_expr, expected);
let else_diverges = self.diverges.get();
cause = self.cause(sp, ObligationCauseCode::IfExpression);
// Only try to coerce-unify if we have a then expression
// to assign coercions to, otherwise it's () or diverging.
let origin = TypeOrigin::IfExpression(sp);
let result = if let Some(ref then) = then_blk.expr {
let res = self.try_find_coercion_lub(origin, || Some(&**then),
expected_ty = then_ty;
found_ty = else_ty;
result = if let Some(ref then) = then_blk.expr {
let res = self.try_find_coercion_lub(&cause, || Some(&**then),
then_ty, else_expr, else_ty);
// In case we did perform an adjustment, we have to update
@ -2876,33 +2898,27 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
res
} else {
self.commit_if_ok(|_| {
let trace = TypeTrace::types(origin, true, then_ty, else_ty);
let trace = TypeTrace::types(&cause, true, then_ty, else_ty);
self.lub(true, trace, &then_ty, &else_ty)
.map(|InferOk { value, obligations }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
value
})
.map(|ok| self.register_infer_ok_obligations(ok))
})
};
// We won't diverge unless both branches do (or the condition does).
self.diverges.set(cond_diverges | then_diverges & else_diverges);
(origin, then_ty, else_ty, result)
} else {
// If the condition is false we can't diverge.
self.diverges.set(cond_diverges);
let origin = TypeOrigin::IfExpressionWithNoElse(sp);
(origin, unit, then_ty,
self.eq_types(true, origin, unit, then_ty)
.map(|InferOk { obligations, .. }| {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
unit
}))
};
cause = self.cause(sp, ObligationCauseCode::IfExpressionWithNoElse);
expected_ty = unit;
found_ty = then_ty;
result = self.eq_types(true, &cause, unit, then_ty)
.map(|ok| {
self.register_infer_ok_obligations(ok);
unit
});
}
match result {
Ok(ty) => {
@ -2913,7 +2929,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
}
}
Err(e) => {
self.report_mismatched_types(origin, expected, found, e);
self.report_mismatched_types(&cause, expected_ty, found_ty, e);
self.tcx.types.err
}
}
@ -3564,17 +3580,18 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
if let Some(ref e) = *expr_opt {
self.check_expr_coercable_to_type(&e, self.ret_ty);
} else {
let eq_result = self.eq_types(false,
TypeOrigin::Misc(expr.span),
self.ret_ty,
tcx.mk_nil())
// FIXME(#32730) propagate obligations
.map(|InferOk { obligations, .. }| assert!(obligations.is_empty()));
if eq_result.is_err() {
struct_span_err!(tcx.sess, expr.span, E0069,
"`return;` in a function whose return type is not `()`")
.span_label(expr.span, &format!("return type is not ()"))
.emit();
match self.eq_types(false,
&self.misc(expr.span),
self.ret_ty,
tcx.mk_nil())
{
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
struct_span_err!(tcx.sess, expr.span, E0069,
"`return;` in a function whose return type is not `()`")
.span_label(expr.span, &format!("return type is not ()"))
.emit();
}
}
}
tcx.types.never
@ -3695,20 +3712,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
for (i, e) in args.iter().enumerate() {
let e_ty = self.check_expr_with_hint(e, coerce_to);
let origin = TypeOrigin::Misc(e.span);
let cause = self.misc(e.span);
// Special-case the first element, as it has no "previous expressions".
let result = if i == 0 {
self.try_coerce(e, e_ty, coerce_to)
} else {
let prev_elems = || args[..i].iter().map(|e| &**e);
self.try_find_coercion_lub(origin, prev_elems, unified, e, e_ty)
self.try_find_coercion_lub(&cause, prev_elems, unified, e, e_ty)
};
match result {
Ok(ty) => unified = ty,
Err(e) => {
self.report_mismatched_types(origin, unified, e_ty, e);
self.report_mismatched_types(&cause, unified, e_ty, e);
}
}
}
@ -4064,9 +4081,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
// We're not diverging and there's an expected type, which,
// in case it's not `()`, could result in an error higher-up.
// We have a chance to error here early and be more helpful.
let origin = TypeOrigin::Misc(blk.span);
let trace = TypeTrace::types(origin, false, ty, ety);
match self.sub_types(false, origin, ty, ety) {
let cause = self.misc(blk.span);
let trace = TypeTrace::types(&cause, false, ty, ety);
match self.sub_types(false, &cause, ty, ety) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
@ -4367,11 +4384,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
let ty = self.tcx.item_type(impl_def_id);
let impl_ty = self.instantiate_type_scheme(span, &substs, &ty);
match self.sub_types(false, TypeOrigin::Misc(span), self_ty, impl_ty) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
}
match self.sub_types(false, &self.misc(span), self_ty, impl_ty) {
Ok(ok) => self.register_infer_ok_obligations(ok),
Err(_) => {
span_bug!(span,
"instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",

View File

@ -91,7 +91,7 @@ use middle::region::{self, CodeExtent};
use rustc::ty::subst::Substs;
use rustc::traits;
use rustc::ty::{self, Ty, MethodCall, TypeFoldable};
use rustc::infer::{self, GenericKind, InferOk, SubregionOrigin, TypeOrigin, VerifyBound};
use rustc::infer::{self, GenericKind, SubregionOrigin, VerifyBound};
use hir::pat_util;
use rustc::ty::adjustment;
use rustc::ty::wf::ImpliedBound;
@ -1762,10 +1762,10 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
outlives);
// check whether this predicate applies to our current projection
match self.eq_types(false, TypeOrigin::Misc(span), ty, outlives.0) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
let cause = self.fcx.misc(span);
match self.eq_types(false, &cause, ty, outlives.0) {
Ok(ok) => {
self.register_infer_ok_obligations(ok);
Ok(outlives.1)
}
Err(_) => { Err(()) }

View File

@ -15,8 +15,7 @@ use CrateCtxt;
use hir::def_id::DefId;
use middle::region::{CodeExtent};
use rustc::infer::TypeOrigin;
use rustc::traits;
use rustc::traits::{self, ObligationCauseCode};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::nodemap::{FxHashSet, FxHashMap};
@ -29,7 +28,7 @@ use rustc::hir;
pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
code: traits::ObligationCauseCode<'tcx>,
code: ObligationCauseCode<'tcx>,
}
/// Helper type of a temporary returned by .for_item(...).
@ -37,7 +36,7 @@ pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(FnCtxt<'b, 'gcx, 'tcx>).
struct CheckWfFcxBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
inherited: super::InheritedBuilder<'a, 'gcx, 'tcx>,
code: traits::ObligationCauseCode<'gcx>,
code: ObligationCauseCode<'gcx>,
id: ast::NodeId,
span: Span
}
@ -67,7 +66,7 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
-> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
CheckTypeWellFormedVisitor {
ccx: ccx,
code: traits::ObligationCauseCode::MiscObligation
code: ObligationCauseCode::MiscObligation
}
}
@ -515,8 +514,8 @@ impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
debug!("check_method_receiver: receiver ty = {:?}", rcvr_ty);
let origin = TypeOrigin::MethodReceiver(span);
fcx.demand_eqtype_with_origin(origin, rcvr_ty, self_arg_ty);
let cause = fcx.cause(span, ObligationCauseCode::MethodReceiver);
fcx.demand_eqtype_with_origin(&cause, rcvr_ty, self_arg_ty);
}
fn check_variances_for_type_defn(&self,

View File

@ -19,7 +19,7 @@ use hir::def_id::DefId;
use middle::lang_items::UnsizeTraitLangItem;
use rustc::ty::subst::Subst;
use rustc::ty::{self, TyCtxt, TypeFoldable};
use rustc::traits::{self, Reveal};
use rustc::traits::{self, ObligationCause, Reveal};
use rustc::ty::ParameterEnvironment;
use rustc::ty::{Ty, TyBool, TyChar, TyError};
use rustc::ty::{TyParam, TyRawPtr};
@ -30,7 +30,7 @@ use rustc::ty::{TyProjection, TyAnon};
use rustc::ty::util::CopyImplementationError;
use middle::free_region::FreeRegionMap;
use CrateCtxt;
use rustc::infer::{self, InferCtxt, TypeOrigin};
use rustc::infer::{self, InferCtxt};
use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
@ -344,12 +344,12 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
target);
tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
let origin = TypeOrigin::Misc(span);
let cause = ObligationCause::misc(span, impl_node_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
mt_b: ty::TypeAndMut<'gcx>,
mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
infcx.report_mismatched_types(origin,
infcx.report_mismatched_types(&cause,
mk_ptr(mt_b.ty),
target,
ty::error::TypeError::Mutability);
@ -397,7 +397,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
}
// Ignore fields that aren't significantly changed
if let Ok(ok) = infcx.sub_types(false, origin, b, a) {
if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
if ok.obligations.is_empty() {
return None;
}

View File

@ -106,10 +106,10 @@ pub use rustc::util;
use dep_graph::DepNode;
use hir::map as hir_map;
use rustc::infer::{InferOk, TypeOrigin};
use rustc::infer::InferOk;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::{self, Reveal};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use session::{config, CompileResult};
use util::common::time;
@ -172,19 +172,19 @@ fn require_c_abi_if_variadic(tcx: TyCtxt,
}
fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
origin: TypeOrigin,
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>)
-> bool {
ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| {
match infcx.eq_types(false, origin.clone(), expected, actual) {
match infcx.eq_types(false, &cause, expected, actual) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
assert!(obligations.is_empty());
true
}
Err(err) => {
infcx.report_mismatched_types(origin, expected, actual, err);
infcx.report_mismatched_types(cause, expected, actual, err);
false
}
}
@ -231,7 +231,7 @@ fn check_main_fn_ty(ccx: &CrateCtxt,
require_same_types(
ccx,
TypeOrigin::MainFunctionType(main_span),
&ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
se_ty,
main_t);
}
@ -286,7 +286,7 @@ fn check_start_fn_ty(ccx: &CrateCtxt,
require_same_types(
ccx,
TypeOrigin::StartFunctionType(start_span),
&ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
se_ty,
start_t);
}