diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index e98792b120de2..a1bafe113e415 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -199,10 +199,8 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { // `tained_by_errors`) to avoid reporting certain kinds of errors. err_count_on_creation: usize, - // This flag is used for debugging, and is set to true if there are - // any obligations set during the current snapshot. In that case, the - // snapshot can't be rolled back. - pub obligations_in_snapshot: Cell, + // This flag is true while there is an active snapshot. + in_snapshot: Cell, } /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized @@ -507,7 +505,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'gcx> { projection_mode: Reveal::UserFacing, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: self.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), } } } @@ -545,7 +543,7 @@ impl<'a, 'gcx, 'tcx> InferCtxtBuilder<'a, 'gcx, 'tcx> { projection_mode: projection_mode, tainted_by_errors_flag: Cell::new(false), err_count_on_creation: tcx.sess.err_count(), - obligations_in_snapshot: Cell::new(false), + in_snapshot: Cell::new(false), })) } } @@ -573,7 +571,7 @@ pub struct CombinedSnapshot { int_snapshot: unify::Snapshot, float_snapshot: unify::Snapshot, region_vars_snapshot: RegionSnapshot, - obligations_in_snapshot: bool, + was_in_snapshot: bool, } /// Helper trait for shortening the lifetimes inside a @@ -734,6 +732,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.projection_mode } + pub fn is_in_snapshot(&self) -> bool { + self.in_snapshot.get() + } + pub fn freshen>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } @@ -861,38 +863,37 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { result.map(move |t| InferOk { value: t, obligations: fields.obligations }) } - // Clear the "obligations in snapshot" flag, invoke the closure, + // Clear the "currently in a snapshot" flag, invoke the closure, // then restore the flag to its original value. This flag is a // debugging measure designed to detect cases where we start a - // snapshot, create type variables, register obligations involving - // those type variables in the fulfillment cx, and then have to - // unroll the snapshot, leaving "dangling type variables" behind. - // In such cases, the flag will be set by the fulfillment cx, and - // an assertion will fail when rolling the snapshot back. Very - // useful, much better than grovelling through megabytes of - // RUST_LOG output. + // snapshot, create type variables, and register obligations + // which may involve those type variables in the fulfillment cx, + // potentially leaving "dangling type variables" behind. + // In such cases, an assertion will fail when attempting to + // register obligations, within a snapshot. Very useful, much + // better than grovelling through megabytes of RUST_LOG output. // - // HOWEVER, in some cases the flag is wrong. In particular, we + // HOWEVER, in some cases the flag is unhelpful. In particular, we // sometimes create a "mini-fulfilment-cx" in which we enroll // obligations. As long as this fulfillment cx is fully drained // before we return, this is not a problem, as there won't be any // escaping obligations in the main cx. In those cases, you can // use this function. - pub fn save_and_restore_obligations_in_snapshot_flag(&self, func: F) -> R + pub fn save_and_restore_in_snapshot_flag(&self, func: F) -> R where F: FnOnce(&Self) -> R { - let flag = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let flag = self.in_snapshot.get(); + self.in_snapshot.set(false); let result = func(self); - self.obligations_in_snapshot.set(flag); + self.in_snapshot.set(flag); result } fn start_snapshot(&self) -> CombinedSnapshot { debug!("start_snapshot()"); - let obligations_in_snapshot = self.obligations_in_snapshot.get(); - self.obligations_in_snapshot.set(false); + let in_snapshot = self.in_snapshot.get(); + self.in_snapshot.set(true); CombinedSnapshot { projection_cache_snapshot: self.projection_cache.borrow_mut().snapshot(), @@ -900,7 +901,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot: self.int_unification_table.borrow_mut().snapshot(), float_snapshot: self.float_unification_table.borrow_mut().snapshot(), region_vars_snapshot: self.region_vars.start_snapshot(), - obligations_in_snapshot: obligations_in_snapshot, + was_in_snapshot: in_snapshot, } } @@ -911,10 +912,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - assert!(!self.obligations_in_snapshot.get()); - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() @@ -939,9 +939,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { int_snapshot, float_snapshot, region_vars_snapshot, - obligations_in_snapshot } = snapshot; + was_in_snapshot } = snapshot; - self.obligations_in_snapshot.set(obligations_in_snapshot); + self.in_snapshot.set(was_in_snapshot); self.projection_cache .borrow_mut() diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 64453f2983b92..d771be077ae3a 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -171,7 +171,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { debug!("register_predicate_obligation(obligation={:?})", obligation); - infcx.obligations_in_snapshot.set(true); + assert!(!infcx.is_in_snapshot()); if infcx.tcx.fulfilled_predicates.borrow().check_duplicate(&obligation.predicate) { debug!("register_predicate_obligation: duplicate"); diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 50a4d982832ac..92b7c736d42fd 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -242,7 +242,7 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, // attempt to prove all of the predicates for impl2 given those for impl1 // (which are packed up in penv) - infcx.save_and_restore_obligations_in_snapshot_flag(|infcx| { + infcx.save_and_restore_in_snapshot_flag(|infcx| { let mut fulfill_cx = FulfillmentContext::new(); for oblig in obligations.into_iter() { fulfill_cx.register_predicate_obligation(&infcx, oblig); diff --git a/src/librustc_typeck/check/assoc.rs b/src/librustc_typeck/check/assoc.rs deleted file mode 100644 index 9610477d8fd91..0000000000000 --- a/src/librustc_typeck/check/assoc.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc::infer::InferCtxt; -use rustc::traits::{self, FulfillmentContext, Normalized, MiscObligation, SelectionContext, - ObligationCause}; -use rustc::ty::fold::TypeFoldable; -use syntax::ast; -use syntax_pos::Span; - -// FIXME(@jroesch): Ideally we should be able to drop the fulfillment_cx argument. -pub fn normalize_associated_types_in<'a, 'gcx, 'tcx, T>( - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - fulfillment_cx: &mut FulfillmentContext<'tcx>, - span: Span, - body_id: ast::NodeId, - value: &T) -> T - - where T : TypeFoldable<'tcx> -{ - debug!("normalize_associated_types_in(value={:?})", value); - let mut selcx = SelectionContext::new(infcx); - let cause = ObligationCause::new(span, body_id, MiscObligation); - let Normalized { value: result, obligations } = traits::normalize(&mut selcx, cause, value); - debug!("normalize_associated_types_in: result={:?} predicates={:?}", - result, - obligations); - for obligation in obligations { - fulfillment_cx.register_predicate_obligation(infcx, obligation); - } - result -} diff --git a/src/librustc_typeck/check/autoderef.rs b/src/librustc_typeck/check/autoderef.rs index 647adbbb82f2d..92fb02c6379dc 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/src/librustc_typeck/check/autoderef.rs @@ -149,22 +149,25 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { self.fcx.resolve_type_vars_if_possible(&self.cur_ty) } - pub fn finalize(self, pref: LvaluePreference, exprs: &[E]) - where E: AsCoercionSite - { + pub fn finalize(self, pref: LvaluePreference, expr: &hir::Expr) { let fcx = self.fcx; - fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, exprs)); + fcx.register_infer_ok_obligations(self.finalize_as_infer_ok(pref, &[expr])); } pub fn finalize_as_infer_ok(self, pref: LvaluePreference, exprs: &[E]) -> InferOk<'tcx, ()> where E: AsCoercionSite { - let methods: Vec<_> = self.steps + let Autoderef { fcx, span, mut obligations, steps, .. } = self; + let methods: Vec<_> = steps .iter() .map(|&(ty, kind)| { if let AutoderefKind::Overloaded = kind { - self.fcx.try_overloaded_deref(self.span, None, ty, pref) + fcx.try_overloaded_deref(span, None, ty, pref) + .map(|InferOk { value, obligations: o }| { + obligations.extend(o); + value + }) } else { None } @@ -174,7 +177,7 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { debug!("finalize({:?}) - {:?},{:?}", pref, methods, - self.obligations); + obligations); for expr in exprs { let expr = expr.as_coercion_site(); @@ -182,14 +185,14 @@ impl<'a, 'gcx, 'tcx> Autoderef<'a, 'gcx, 'tcx> { for (n, method) in methods.iter().enumerate() { if let &Some(method) = method { let method_call = MethodCall::autoderef(expr.id, n as u32); - self.fcx.tables.borrow_mut().method_map.insert(method_call, method); + fcx.tables.borrow_mut().method_map.insert(method_call, method); } } } InferOk { value: (), - obligations: self.obligations + obligations } } } @@ -211,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { base_expr: Option<&hir::Expr>, base_ty: Ty<'tcx>, lvalue_pref: LvaluePreference) - -> Option> { + -> Option>> { debug!("try_overloaded_deref({:?},{:?},{:?},{:?})", span, base_expr, diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 9c5870c12aad4..32f130aca1cb9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }) .next(); let callee_ty = autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, &[callee_expr]); + autoderef.finalize(LvaluePreference::NoPreference, callee_expr); let output = match result { None => { @@ -173,7 +173,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { adjusted_ty, None) { None => continue, - Some(method_callee) => { + Some(ok) => { + let method_callee = self.register_infer_ok_obligations(ok); return Some(method_callee); } } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 2e9057800a54a..c6a1f6cfc0d7f 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -711,16 +711,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let cause = self.cause(expr.span, ObligationCauseCode::ExprAssignable); let coerce = Coerce::new(self, cause); - self.commit_if_ok(|_| { - let ok = coerce.coerce(&[expr], source, target)?; - let adjustment = self.register_infer_ok_obligations(ok); - self.apply_adjustment(expr.id, adjustment); - - // We should now have added sufficient adjustments etc to - // ensure that the type of expression, post-adjustment, is - // a subtype of target. - Ok(target) - }) + let ok = self.commit_if_ok(|_| coerce.coerce(&[expr], source, target))?; + + let adjustment = self.register_infer_ok_obligations(ok); + self.apply_adjustment(expr.id, adjustment); + + // We should now have added sufficient adjustments etc to + // ensure that the type of expression, post-adjustment, is + // a subtype of target. + Ok(target) } /// Given some expressions, their known unified type and another expression, diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 905d8688ea194..8a6853461a5e8 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -20,7 +20,6 @@ use rustc::util::common::ErrorReported; use syntax::ast; use syntax_pos::Span; -use super::assoc; use super::{Inherited, FnCtxt}; use astconv::ExplicitSelf; @@ -227,7 +226,6 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| { let inh = Inherited::new(infcx); let infcx = &inh.infcx; - let fulfillment_cx = &inh.fulfillment_cx; debug!("compare_impl_method: caller_bounds={:?}", infcx.parameter_environment.caller_bounds); @@ -239,12 +237,11 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, infer::HigherRankedType, &ty::Binder(impl_m_own_bounds.predicates)); for predicate in impl_m_own_bounds { - let traits::Normalized { value: predicate, .. } = + let traits::Normalized { value: predicate, obligations } = traits::normalize(&mut selcx, normalize_cause.clone(), &predicate); - fulfillment_cx.borrow_mut().register_predicate_obligation( - &infcx, - traits::Obligation::new(cause.clone(), predicate)); + inh.register_predicates(obligations); + inh.register_predicate(traits::Obligation::new(cause.clone(), predicate)); } // We now need to check that the signature of the impl method is @@ -277,11 +274,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let impl_sig = impl_sig.subst(tcx, impl_to_skol_substs); let impl_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx.borrow_mut(), - impl_m_span, - impl_m_body_id, - &impl_sig); + inh.normalize_associated_types_in(impl_m_span, + impl_m_body_id, + &impl_sig); let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig)); debug!("compare_impl_method: impl_fty={:?}", impl_fty); @@ -291,11 +286,9 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_sig = trait_sig.subst(tcx, trait_to_skol_substs); let trait_sig = - assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx.borrow_mut(), - impl_m_span, - impl_m_body_id, - &trait_sig); + inh.normalize_associated_types_in(impl_m_span, + impl_m_body_id, + &trait_sig); let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig)); debug!("compare_impl_method: trait_fty={:?}", trait_fty); @@ -344,7 +337,7 @@ fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Check that all obligations are satisfied by the implementation's // version. - if let Err(ref errors) = fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { + if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { infcx.report_fulfillment_errors(errors); return Err(ErrorReported); } @@ -731,7 +724,8 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref); tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| { - let mut fulfillment_cx = traits::FulfillmentContext::new(); + let inh = Inherited::new(infcx); + let infcx = &inh.infcx; // The below is for the most part highly similar to the procedure // for methods above. It is simpler in many respects, especially @@ -761,31 +755,21 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let trait_ty = tcx.item_type(trait_c.def_id).subst(tcx, trait_to_skol_substs); 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. - let impl_ty = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &impl_ty); + // There is no "body" here, so just pass dummy id. + let impl_ty = inh.normalize_associated_types_in(impl_c_span, + impl_c_node_id, + &impl_ty); - debug!("compare_const_impl: impl_ty={:?}", impl_ty); + debug!("compare_const_impl: impl_ty={:?}", impl_ty); - let trait_ty = assoc::normalize_associated_types_in(&infcx, - &mut fulfillment_cx, - impl_c_span, - ast::CRATE_NODE_ID, - &trait_ty); + let trait_ty = inh.normalize_associated_types_in(impl_c_span, + impl_c_node_id, + &trait_ty); - debug!("compare_const_impl: trait_ty={:?}", trait_ty); + debug!("compare_const_impl: trait_ty={:?}", trait_ty); - infcx.sub_types(false, &cause, impl_ty, trait_ty) - .map(|InferOk { obligations, value: () }| { - for obligation in obligations { - fulfillment_cx.register_predicate_obligation(&infcx, obligation); - } - }) - }); + let err = infcx.sub_types(false, &cause, impl_ty, trait_ty) + .map(|ok| inh.register_infer_ok_obligations(ok)); if let Err(terr) = err { debug!("checking associated const for compatibility: impl ty {:?}, trait ty {:?}", @@ -822,5 +806,7 @@ pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, &terr); diag.emit(); } + + // FIXME(#41323) Check the obligations in the fulfillment context. }); } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 28ac335cf195a..26ba965fe5cc6 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -137,7 +137,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { assert_eq!(n, pick.autoderefs); autoderef.unambiguous_final_ty(); - autoderef.finalize(LvaluePreference::NoPreference, &[self.self_expr]); + autoderef.finalize(LvaluePreference::NoPreference, self.self_expr); let target = pick.unsize.unwrap_or(autoderefd_ty); let target = target.adjust_for_autoref(self.tcx, autoref); @@ -445,7 +445,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { "expr was deref-able {} times but now isn't?", autoderefs); }); - autoderef.finalize(PreferMutLvalue, &[expr]); + autoderef.finalize(PreferMutLvalue, expr); } } Some(_) | None => {} @@ -543,7 +543,8 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> { Some(&base_expr), self.node_ty(base_expr.id), PreferMutLvalue); - let method = method.expect("re-trying deref failed"); + let ok = method.expect("re-trying deref failed"); + let method = self.register_infer_ok_obligations(ok); self.tables.borrow_mut().method_map.insert(method_call, method); } } diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index 9ecf0ffa71ebd..7dd2699a6eaf0 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -17,7 +17,8 @@ use rustc::ty::subst::Substs; use rustc::traits; use rustc::ty::{self, ToPredicate, ToPolyTraitRef, TraitRef, TypeFoldable}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow}; -use rustc::infer; +use rustc::ty::subst::Subst; +use rustc::infer::{self, InferOk}; use syntax::ast; use syntax_pos::Span; @@ -159,7 +160,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> { + -> Option>> { self.lookup_method_in_trait_adjusted(span, self_expr, m_name, @@ -190,7 +191,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { unsize: bool, self_ty: ty::Ty<'tcx>, opt_input_types: Option>>) - -> Option> { + -> Option>> { debug!("lookup_in_trait_adjusted(self_ty={:?}, self_expr={:?}, \ m_name={}, trait_def_id={:?})", self_ty, @@ -236,6 +237,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert_eq!(generics.regions.len(), 0); debug!("lookup_in_trait_adjusted: method_item={:?}", method_item); + let mut obligations = vec![]; // Instantiate late-bound regions and substitute the trait // parameters into the method type to get the actual method type. @@ -248,10 +250,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let fn_sig = self.replace_late_bound_regions_with_fresh_var(span, infer::FnCall, &fn_sig).0; - let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig); + let fn_sig = fn_sig.subst(self.tcx, substs); + let fn_sig = match self.normalize_associated_types_in_as_infer_ok(span, &fn_sig) { + InferOk { value, obligations: o } => { + obligations.extend(o); + value + } + }; let transformed_self_ty = fn_sig.inputs()[0]; - let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs, - ty::Binder(fn_sig)); + let method_ty = tcx.mk_fn_def(def_id, substs, ty::Binder(fn_sig)); debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}", method_ty, @@ -265,18 +272,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // // Note that as the method comes from a trait, it should not have // any late-bound regions appearing in its bounds. - let method_bounds = self.instantiate_bounds(span, def_id, trait_ref.substs); - assert!(!method_bounds.has_escaping_regions()); - self.add_obligations_for_parameters(traits::ObligationCause::misc(span, self.body_id), - &method_bounds); + let bounds = self.tcx.item_predicates(def_id).instantiate(self.tcx, substs); + let bounds = match self.normalize_associated_types_in_as_infer_ok(span, &bounds) { + InferOk { value, obligations: o } => { + obligations.extend(o); + value + } + }; + assert!(!bounds.has_escaping_regions()); - // Also register an obligation for the method type being well-formed. - self.register_wf_obligation(method_ty, span, traits::MiscObligation); + let cause = traits::ObligationCause::misc(span, self.body_id); + obligations.extend(traits::predicates_for_generics(cause.clone(), &bounds)); - // FIXME(#18653) -- Try to resolve obligations, giving us more - // typing information, which can sometimes be needed to avoid - // pathological region inference failures. - self.select_obligations_where_possible(); + // Also add an obligation for the method type being well-formed. + obligations.push(traits::Obligation::new(cause, ty::Predicate::WellFormed(method_ty))); // Insert any adjustments needed (always an autoref of some mutability). if let Some(self_expr) = self_expr { @@ -317,7 +326,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("callee = {:?}", callee); - Some(callee) + Some(InferOk { + obligations, + value: callee + }) } pub fn resolve_ufcs(&self, diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 32aeeeb110556..902cfb889f8c2 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -128,7 +128,6 @@ use rustc_back::slice; use rustc::middle::const_val::eval_length; use rustc_const_math::ConstInt; -mod assoc; mod autoderef; pub mod dropck; pub mod _match; @@ -536,7 +535,7 @@ impl<'a, 'gcx, 'tcx> InheritedBuilder<'a, 'gcx, 'tcx> { } impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { - pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { + fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self { Inherited { infcx: infcx, fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()), @@ -547,20 +546,55 @@ impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> { } } + fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { + debug!("register_predicate({:?})", obligation); + if obligation.has_escaping_regions() { + span_bug!(obligation.cause.span, "escaping regions in predicate {:?}", + obligation); + } + self.fulfillment_cx + .borrow_mut() + .register_predicate_obligation(self, obligation); + } + + fn register_predicates(&self, obligations: Vec>) { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + fn normalize_associated_types_in(&self, span: Span, body_id: ast::NodeId, - value: &T) - -> T + value: &T) -> T where T : TypeFoldable<'tcx> { - assoc::normalize_associated_types_in(self, - &mut self.fulfillment_cx.borrow_mut(), - span, - body_id, - value) + let ok = self.normalize_associated_types_in_as_infer_ok(span, body_id, value); + self.register_infer_ok_obligations(ok) } + fn normalize_associated_types_in_as_infer_ok(&self, + span: Span, + body_id: ast::NodeId, + value: &T) + -> InferOk<'tcx, T> + where T : TypeFoldable<'tcx> + { + debug!("normalize_associated_types_in(value={:?})", value); + let mut selcx = traits::SelectionContext::new(self); + let cause = ObligationCause::misc(span, body_id); + let traits::Normalized { value, obligations } = + traits::normalize(&mut selcx, cause, value); + debug!("normalize_associated_types_in: result={:?} predicates={:?}", + value, + obligations); + InferOk { value, obligations } + } } struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> } @@ -1713,14 +1747,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { -> ty::InstantiatedPredicates<'tcx> { let bounds = self.tcx.item_predicates(def_id); let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result.predicates); + let result = self.normalize_associated_types_in(span, &result); debug!("instantiate_bounds(bounds={:?}, substs={:?}) = {:?}", bounds, substs, result); - ty::InstantiatedPredicates { - predicates: result - } + result } /// Replace all anonymized types with fresh inference variables @@ -1763,7 +1795,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { fn normalize_associated_types_in(&self, span: Span, value: &T) -> T where T : TypeFoldable<'tcx> { - self.inh.normalize_associated_types_in(span, self.body_id, value) + let ok = self.normalize_associated_types_in_as_infer_ok(span, value); + self.register_infer_ok_obligations(ok) + } + + fn normalize_associated_types_in_as_infer_ok(&self, span: Span, value: &T) + -> InferOk<'tcx, T> + where T : TypeFoldable<'tcx> + { + self.inh.normalize_associated_types_in_as_infer_ok(span, self.body_id, value) } pub fn write_nil(&self, node_id: ast::NodeId) { @@ -1804,32 +1844,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .register_bound(self, ty, def_id, cause); } - pub fn register_predicate(&self, - obligation: traits::PredicateObligation<'tcx>) - { - debug!("register_predicate({:?})", obligation); - if obligation.has_escaping_regions() { - span_bug!(obligation.cause.span, "escaping regions in predicate {:?}", - obligation); - } - self.fulfillment_cx - .borrow_mut() - .register_predicate_obligation(self, obligation); - } - - pub fn register_predicates(&self, - obligations: Vec>) - { - for obligation in obligations { - self.register_predicate(obligation); - } - } - - pub fn register_infer_ok_obligations(&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, ast_t); self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); @@ -2072,12 +2086,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { expr, base_expr, adj_ty, autoderefs, false, lvalue_pref, idx_ty) { - autoderef.finalize(lvalue_pref, &[base_expr]); + autoderef.finalize(lvalue_pref, base_expr); return Some(final_mt); } if let ty::TyArray(element_ty, _) = adj_ty.sty { - autoderef.finalize(lvalue_pref, &[base_expr]); + autoderef.finalize(lvalue_pref, base_expr); let adjusted_ty = self.tcx.mk_slice(element_ty); return self.try_index_step( MethodCall::expr(expr.id), expr, base_expr, @@ -2161,8 +2175,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // If some lookup succeeds, write callee into table and extract index/element // type from the method signature. // If some lookup succeeded, install method in table - method.map(|method| { + method.map(|ok| { debug!("try_index_step: success, using overloaded indexing"); + let method = self.register_infer_ok_obligations(ok); self.tables.borrow_mut().method_map.insert(method_call, method); (input_ty, self.make_overloaded_lvalue_return_type(method).ty) }) @@ -2586,7 +2601,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // we can. We don't care if some things turn // out unconstrained or ambiguous, as we're // just trying to get hints here. - let result = self.save_and_restore_obligations_in_snapshot_flag(|_| { + let result = self.save_and_restore_in_snapshot_flag(|_| { let mut fulfill = FulfillmentContext::new(); let ok = ok; // FIXME(#30046) for obligation in ok.obligations { @@ -2755,7 +2770,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(field) = base_def.struct_variant().find_field_named(field.node) { let field_ty = self.field_ty(expr.span, field, substs); if self.tcx.vis_is_accessible_from(field.vis, self.body_id) { - autoderef.finalize(lvalue_pref, &[base]); + autoderef.finalize(lvalue_pref, base); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); self.tcx.check_stability(field.did, expr.id, expr.span); @@ -2879,7 +2894,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { }; if let Some(field_ty) = field { - autoderef.finalize(lvalue_pref, &[base]); + autoderef.finalize(lvalue_pref, base); self.apply_autoderef_adjustment(base.id, autoderefs, base_t); return field_ty; } @@ -3292,8 +3307,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some(mt) = oprnd_t.builtin_deref(true, NoPreference) { oprnd_t = mt.ty; - } else if let Some(method) = self.try_overloaded_deref( + } else if let Some(ok) = self.try_overloaded_deref( expr.span, Some(&oprnd), oprnd_t, lvalue_pref) { + let method = self.register_infer_ok_obligations(ok); oprnd_t = self.make_overloaded_lvalue_return_type(method).ty; self.tables.borrow_mut().method_map.insert(MethodCall::expr(expr.id), method); diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs index cc33bd8754d9e..42296006b79d1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/src/librustc_typeck/check/op.rs @@ -398,20 +398,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let method = match trait_did { Some(trait_did) => { - self.lookup_method_in_trait_adjusted(expr.span, - Some(lhs_expr), - opname, - trait_did, - 0, - false, - lhs_ty, - Some(other_tys)) + self.lookup_method_in_trait(expr.span, + Some(lhs_expr), + opname, + trait_did, + lhs_ty, + Some(other_tys)) } None => None }; match method { - Some(method) => { + Some(ok) => { + let method = self.register_infer_ok_obligations(ok); + self.select_obligations_where_possible(); + let method_ty = method.ty; // HACK(eddyb) Fully qualified path to work around a resolve bug. diff --git a/src/test/run-pass/coerce-overloaded-autoderef.rs b/src/test/run-pass/coerce-overloaded-autoderef.rs index a053311a0403e..091e29dd18a6b 100644 --- a/src/test/run-pass/coerce-overloaded-autoderef.rs +++ b/src/test/run-pass/coerce-overloaded-autoderef.rs @@ -68,4 +68,8 @@ fn use_vec_ref(v: &Vec) { use_slice(&&&mut &&&v); } +fn use_op_rhs(s: &mut String) { + *s += {&String::from(" ")}; +} + pub fn main() {}