From aee1ee3cc298c32a22a5730d7133b64e950a8dec Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 4 Oct 2016 02:19:40 +0300 Subject: [PATCH] rustc: harden against InferOk having obligations in more cases. --- src/librustc/infer/mod.rs | 13 +++++++--- src/librustc/traits/coherence.rs | 14 ++++++----- src/librustc/traits/specialize/mod.rs | 22 +++++++++------- src/librustc_typeck/check/compare_method.rs | 8 +++++- src/librustc_typeck/check/dropck.rs | 28 +++++++++++++-------- src/librustc_typeck/coherence/mod.rs | 20 +++++++++------ src/librustc_typeck/lib.rs | 17 ++++++++----- 7 files changed, 78 insertions(+), 44 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index bbcd87d9cabfc..21820ca071921 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1069,7 +1069,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.probe(|_| { let origin = TypeOrigin::Misc(syntax_pos::DUMMY_SP); let trace = TypeTrace::types(origin, true, a, b); - self.sub(true, trace, &a, &b).map(|_| ()) + self.sub(true, trace, &a, &b).map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }) }) } @@ -1592,8 +1595,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // anyhow. We should make this typetrace stuff more // generic so we don't have to do anything quite this // terrible. - self.equate(true, TypeTrace::dummy(self.tcx), a, b) - }).map(|_| ()) + let trace = TypeTrace::dummy(self.tcx); + self.equate(true, trace, a, b).map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }) + }) } pub fn node_ty(&self, id: ast::NodeId) -> McResult> { diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 68c88249ec0c3..1ccd048cedcaa 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -14,7 +14,7 @@ use super::{SelectionContext, Obligation, ObligationCause}; use hir::def_id::{DefId, LOCAL_CRATE}; use ty::{self, Ty, TyCtxt}; -use infer::{InferCtxt, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeOrigin}; use syntax_pos::DUMMY_SP; #[derive(Copy, Clone)] @@ -55,11 +55,13 @@ 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. - if let Err(_) = selcx.infcx().eq_impl_headers(true, - TypeOrigin::Misc(DUMMY_SP), - &a_impl_header, - &b_impl_header) { - return None; + match selcx.infcx().eq_impl_headers(true, TypeOrigin::Misc(DUMMY_SP), &a_impl_header, + &b_impl_header) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + } + Err(_) => return None } debug!("overlap: unification check succeeded"); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 24cafa7f7253a..909247d1cb245 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -22,7 +22,7 @@ use super::util::impl_trait_ref_and_oblig; use rustc_data_structures::fnv::FnvHashMap; use hir::def_id::DefId; -use infer::{InferCtxt, TypeOrigin}; +use infer::{InferCtxt, InferOk, TypeOrigin}; use middle::region; use ty::subst::{Subst, Substs}; use traits::{self, Reveal, ObligationCause}; @@ -222,14 +222,18 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, target_substs); // do the impls unify? If not, no specialization. - if let Err(_) = infcx.eq_trait_refs(true, - TypeOrigin::Misc(DUMMY_SP), - source_trait_ref, - target_trait_ref) { - debug!("fulfill_implication: {:?} does not unify with {:?}", - source_trait_ref, - target_trait_ref); - return Err(()); + match infcx.eq_trait_refs(true, TypeOrigin::Misc(DUMMY_SP), source_trait_ref, + target_trait_ref) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()) + } + Err(_) => { + debug!("fulfill_implication: {:?} does not unify with {:?}", + source_trait_ref, + target_trait_ref); + return Err(()); + } } // attempt to prove all of the predicates for impl2 given those for impl1 diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 6f450f57275c5..2cb719675ac48 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -298,7 +298,13 @@ fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, debug!("compare_impl_method: trait_fty={:?}", trait_fty); - if let Err(terr) = infcx.sub_types(false, origin, impl_fty, trait_fty) { + let sub_result = infcx.sub_types(false, origin, impl_fty, trait_fty) + .map(|InferOk { obligations, .. }| { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + }); + + if let Err(terr) = sub_result { debug!("sub_types failed: impl ty {:?}, trait ty {:?}", impl_fty, trait_fty); diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 5e2b49bac1b2f..e72bcb3079c5c 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -13,7 +13,7 @@ use check::regionck::RegionCtxt; use hir::def_id::DefId; use middle::free_region::FreeRegionMap; -use rustc::infer; +use rustc::infer::{self, InferOk}; use middle::region; use rustc::ty::subst::{Subst, Substs}; use rustc::ty::{self, AdtKind, Ty, TyCtxt}; @@ -93,16 +93,22 @@ 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); - if let Err(_) = infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), - named_type, fresh_impl_self_ty) { - let item_span = tcx.map.span(self_type_node_id); - struct_span_err!(tcx.sess, drop_impl_span, E0366, - "Implementations of Drop cannot be specialized") - .span_note(item_span, - "Use same sequence of generic type and region \ - parameters that is on the struct/enum definition") - .emit(); - return Err(()); + match infcx.eq_types(true, infer::TypeOrigin::Misc(drop_impl_span), + named_type, fresh_impl_self_ty) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + } + Err(_) => { + let item_span = tcx.map.span(self_type_node_id); + struct_span_err!(tcx.sess, drop_impl_span, E0366, + "Implementations of Drop cannot be specialized") + .span_note(item_span, + "Use same sequence of generic type and region \ + parameters that is on the struct/enum definition") + .emit(); + return Err(()); + } } if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) { diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index ca22faa2ec36a..4a4dea5b514e5 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -415,15 +415,19 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> { if f.unsubst_ty().is_phantom_data() { // Ignore PhantomData fields - None - } else if infcx.sub_types(false, origin, b, a).is_ok() { - // Ignore fields that aren't significantly changed - None - } else { - // Collect up all fields that were significantly changed - // i.e. those that contain T in coerce_unsized T -> U - Some((i, a, b)) + return None; } + + // Ignore fields that aren't significantly changed + if let Ok(ok) = infcx.sub_types(false, origin, b, a) { + if ok.obligations.is_empty() { + return None; + } + } + + // Collect up all fields that were significantly changed + // i.e. those that contain T in coerce_unsized T -> U + Some((i, a, b)) }) .collect::>(); diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 671274a4057c0..75f0dac59501d 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -106,7 +106,7 @@ pub use rustc::util; use dep_graph::DepNode; use hir::map as hir_map; -use rustc::infer::TypeOrigin; +use rustc::infer::{InferOk, TypeOrigin}; use rustc::ty::subst::Substs; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::traits::{self, Reveal}; @@ -198,11 +198,16 @@ fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, actual: Ty<'tcx>) -> bool { ccx.tcx.infer_ctxt(None, None, Reveal::NotSpecializable).enter(|infcx| { - if let Err(err) = infcx.eq_types(false, origin.clone(), expected, actual) { - infcx.report_mismatched_types(origin, expected, actual, err); - false - } else { - true + match infcx.eq_types(false, origin.clone(), expected, actual) { + Ok(InferOk { obligations, .. }) => { + // FIXME(#32730) propagate obligations + assert!(obligations.is_empty()); + true + } + Err(err) => { + infcx.report_mismatched_types(origin, expected, actual, err); + false + } } }) }