diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index c355e8b82a6..4617d3860a3 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -87,6 +87,8 @@ pub struct InferCtxt<'a, 'tcx: 'a> { pub parameter_environment: ty::ParameterEnvironment<'a, 'tcx>, + pub fulfillment_cx: RefCell>, + // This is a temporary field used for toggling on normalization in the inference context, // as we move towards the approach described here: // https://internals.rust-lang.org/t/flattening-the-contexts-for-fun-and-profit/2293 @@ -327,9 +329,16 @@ pub fn fixup_err_to_string(f: fixup_err) -> String { } } +/// errors_will_be_reported is required to proxy to the fulfillment context +/// FIXME -- a better option would be to hold back on modifying +/// the global cache until we know that all dependent obligations +/// are also satisfied. In that case, we could actually remove +/// this boolean flag, and we'd also avoid the problem of squelching +/// duplicate errors that occur across fns. pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, tables: &'a RefCell>, - param_env: Option>) + param_env: Option>, + errors_will_be_reported: bool) -> InferCtxt<'a, 'tcx> { InferCtxt { tcx: tcx, @@ -339,6 +348,7 @@ pub fn new_infer_ctxt<'a, 'tcx>(tcx: &'a ty::ctxt<'tcx>, float_unification_table: RefCell::new(UnificationTable::new()), region_vars: RegionVarBindings::new(tcx), parameter_environment: param_env.unwrap_or(tcx.empty_parameter_environment()), + fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(errors_will_be_reported)), normalize: false, err_count_on_creation: tcx.sess.err_count() } @@ -1009,6 +1019,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { raw_ty.adjust(self.tcx, expr.span, expr.id, + raw_ty, adjustment, |method_call| self.tables .borrow() diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 9df6ed5d681..c5afb7dd3db 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -397,7 +397,7 @@ pub fn normalize_param_env_or_error<'a,'tcx>(unnormalized_env: ty::ParameterEnvi let elaborated_env = unnormalized_env.with_caller_bounds(predicates); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env)); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(elaborated_env), false); let predicates = match fully_normalize(&infcx, &infcx.parameter_environment, cause, &infcx.parameter_environment.caller_bounds) { Ok(predicates) => predicates, diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 9c2aea1e67a..32a1f74063b 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -957,7 +957,7 @@ pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, trait_ref, trait_ref.def_id()); tcx.populate_implementations_for_trait_if_necessary(trait_ref.def_id()); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. @@ -1019,7 +1019,7 @@ pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, predicates); let tcx = ccx.tcx(); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); let typer = NormalizingClosureTyper::new(tcx); let mut selcx = traits::SelectionContext::new(&infcx, &typer); let mut fulfill_cx = traits::FulfillmentContext::new(false); diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 67ccf64621a..6ad164719cf 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -324,7 +324,7 @@ pub fn normalize_associated_type<'tcx,T>(tcx: &ty::ctxt<'tcx>, value: &T) -> T // FIXME(#20304) -- cache // NOTE: @jroesch // Here is of an example where we do not use a param_env but use a typer instead. - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); let typer = NormalizingClosureTyper::new(tcx); let mut selcx = traits::SelectionContext::new(&infcx, &typer); let cause = traits::ObligationCause::dummy(); diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs index b5ee46ece94..6d1e9dfacf2 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/src/librustc_typeck/check/closure.rs @@ -125,7 +125,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>( expected_vid: ty::TyVid) -> (Option>, Option) { - let fulfillment_cx = fcx.inh.fulfillment_cx.borrow(); + let fulfillment_cx = fcx.inh.infcx.fulfillment_cx.borrow(); // Here `expected_ty` is known to be a type inference variable. let expected_sig = diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index f62411e8582..6375926298f 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -43,7 +43,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_impl_method: impl_trait_ref (liberated) = {:?}", impl_trait_ref); - let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let mut infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); let mut fulfillment_cx = traits::FulfillmentContext::new(true); let trait_to_impl_substs = &impl_trait_ref.substs; @@ -419,7 +419,7 @@ pub fn compare_const_impl<'tcx>(tcx: &ty::ctxt<'tcx>, debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, true); let mut fulfillment_cx = traits::FulfillmentContext::new(true); // The below is for the most part highly similar to the procedure diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 6f0fbfebf46..7d911cf8b03 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -93,7 +93,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( ty: named_type } = tcx.lookup_item_type(self_type_did); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); infcx.commit_if_ok(|snapshot| { let (named_type_to_skolem, skol_map) = diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 2db1598db4b..76286cfe9ba 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -159,7 +159,7 @@ pub struct Inherited<'a, 'tcx: 'a> { fn_sig_map: RefCell>>>, // Tracks trait obligations incurred during this function body. - fulfillment_cx: RefCell>, + // fulfillment_cx: RefCell>, // When we process a call like `c()` where `c` is a closure type, // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or @@ -295,11 +295,11 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { -> Inherited<'a, 'tcx> { Inherited { - infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env)), + // I'm probably screwed here ... more boolean prop ... + infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), false), locals: RefCell::new(NodeMap()), tables: tables, fn_sig_map: RefCell::new(NodeMap()), - fulfillment_cx: RefCell::new(traits::FulfillmentContext::new(true)), deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_cast_checks: RefCell::new(Vec::new()), } @@ -313,7 +313,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { -> T where T : TypeFoldable<'tcx> + HasTypeFlags { - let mut fulfillment_cx = self.fulfillment_cx.borrow_mut(); + let mut fulfillment_cx = self.infcx.fulfillment_cx.borrow_mut(); assoc::normalize_associated_types_in(&self.infcx, typer, &mut *fulfillment_cx, span, @@ -1389,7 +1389,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let cause = traits::ObligationCause::new(span, self.body_id, traits::ObligationCauseCode::MiscObligation); - self.inh.fulfillment_cx + self.inh + .infcx + .fulfillment_cx .borrow_mut() .normalize_projection_type(self.infcx(), self.infcx(), @@ -1513,7 +1515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { builtin_bound: ty::BuiltinBound, cause: traits::ObligationCause<'tcx>) { - self.inh.fulfillment_cx.borrow_mut() + self.inh.infcx.fulfillment_cx.borrow_mut() .register_builtin_bound(self.infcx(), ty, builtin_bound, cause); } @@ -1522,7 +1524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { debug!("register_predicate({:?})", obligation); - self.inh.fulfillment_cx + self.inh.infcx.fulfillment_cx .borrow_mut() .register_predicate_obligation(self.infcx(), obligation); } @@ -1558,6 +1560,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let raw_ty = self.infcx().shallow_resolve(raw_ty); let resolve_ty = |ty: Ty<'tcx>| self.infcx().resolve_type_vars_if_possible(&ty); raw_ty.adjust(self.tcx(), expr.span, expr.id, adjustment, |method_call| { + .method_map self.inh.tables.borrow().method_map.get(&method_call) .map(|method| resolve_ty(method.ty)) }) @@ -1648,7 +1651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { region: ty::Region, cause: traits::ObligationCause<'tcx>) { - let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); + let mut fulfillment_cx = self.inh.infcx.fulfillment_cx.borrow_mut(); fulfillment_cx.register_region_obligation(ty, region, cause); } @@ -1747,7 +1750,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { assert!(self.inh.deferred_call_resolutions.borrow().is_empty()); self.select_all_obligations_and_apply_defaults(); - let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut(); + let mut fulfillment_cx = self.inh.infcx.fulfillment_cx.borrow_mut(); match fulfillment_cx.select_all_or_error(self.infcx(), self.infcx()) { Ok(()) => { } Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); } @@ -1757,7 +1760,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Select as many obligations as we can at present. fn select_obligations_where_possible(&self) { match - self.inh.fulfillment_cx + self.inh.infcx.fulfillment_cx .borrow_mut() .select_where_possible(self.infcx(), self.infcx()) { @@ -1772,7 +1775,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// work. fn select_new_obligations(&self) { match - self.inh.fulfillment_cx + self.inh.infcx.fulfillment_cx .borrow_mut() .select_new_obligations(self.infcx(), self.infcx()) { diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index a8630190738..661e1856ce8 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -318,9 +318,13 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // Make a copy of the region obligations vec because we'll need // to be able to borrow the fulfillment-cx below when projecting. let region_obligations = - self.fcx.inh.fulfillment_cx.borrow() - .region_obligations(node_id) - .to_vec(); + self.fcx + .inh + .infcx + .fulfillment_cx + .borrow() + .region_obligations(node_id) + .to_vec(); for r_o in ®ion_obligations { debug!("visit_region_obligations: r_o={:?}", @@ -332,7 +336,7 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // Processing the region obligations should not cause the list to grow further: assert_eq!(region_obligations.len(), - self.fcx.inh.fulfillment_cx.borrow().region_obligations(node_id).len()); + self.fcx.inh.infcx.fulfillment_cx.borrow().region_obligations(node_id).len()); } /// This method populates the region map's `free_region_map`. It walks over the transformed diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index fbabc287342..23336c43995 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -448,7 +448,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)", source, target); - let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env)); + let infcx = new_infer_ctxt(tcx, &tcx.tables, Some(param_env), true); let check_mutbl = |mt_a: ty::mt<'tcx>, mt_b: ty::mt<'tcx>, mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| { @@ -632,7 +632,8 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, pub fn check_coherence(crate_context: &CrateCtxt) { CoherenceChecker { crate_context: crate_context, - inference_context: new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None), + // XXXJAREDXXX: not sure if the bool is right here? + inference_context: new_infer_ctxt(crate_context.tcx, &crate_context.tcx.tables, None, false), inherent_impls: RefCell::new(FnvHashMap()), }.check(crate_context.tcx.map.krate()); unsafety::check(crate_context.tcx); diff --git a/src/librustc_typeck/coherence/overlap.rs b/src/librustc_typeck/coherence/overlap.rs index 3495714fcc7..42c6bcbfbb9 100644 --- a/src/librustc_typeck/coherence/overlap.rs +++ b/src/librustc_typeck/coherence/overlap.rs @@ -133,7 +133,7 @@ impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> { impl1_def_id, impl2_def_id); - let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None); + let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, None, false); if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id) { self.report_overlap_error(trait_def_id, impl1_def_id, impl2_def_id); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 7909908079f..c45fbb70002 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -2211,7 +2211,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>( base_type, base_type_free); - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); drop(::require_same_types(tcx, Some(&infcx), false, diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 48a64675c70..8c3ef4ae631 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -188,7 +188,7 @@ fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>, { let result = match maybe_infcx { None => { - let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None); + let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false); infer::mk_eqty(&infcx, t1_is_expected, infer::Misc(span), t1, t2) } Some(infcx) => {