diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs index c8a63c9c3f8..45dadcfff2e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs @@ -5,12 +5,11 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::LangItem; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngine; use rustc_middle::mir::*; use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty}; use rustc_span::DUMMY_SP; use rustc_trait_selection::traits::{ - self, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngineExt, + self, ImplSource, Obligation, ObligationCause, SelectionContext, }; use super::ConstCx; @@ -189,15 +188,8 @@ impl Qualif for NeedsNonConstDrop { return false; } - // If we successfully found one, then select all of the predicates - // implied by our const drop impl. - let mut fcx = >::new(cx.tcx); - for nested in impl_src.nested_obligations() { - fcx.register_predicate_obligation(&infcx, nested); - } - // If we had any errors, then it's bad - !fcx.select_all_or_error(&infcx).is_empty() + !traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty() }) } diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 294c81d0b21..6b230210888 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -205,10 +205,8 @@ impl<'tcx> AutoTraitFinder<'tcx> { // At this point, we already have all of the bounds we need. FulfillmentContext is used // to store all of the necessary region/lifetime bounds in the InferContext, as well as // an additional sanity check. - let mut fulfill = >::new(tcx); - fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy()); - let errors = fulfill.select_all_or_error(&infcx); - + let errors = + super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did); if !errors.is_empty() { panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors); } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 65afd2aeee3..8ab1aa65d3a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -10,14 +10,14 @@ use crate::traits::select::IntercrateAmbiguityCause; use crate::traits::util::impl_subject_and_oblig; use crate::traits::SkipLeakCheck; use crate::traits::{ - self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation, - PredicateObligations, SelectionContext, TraitEngineExt, + self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations, + SelectionContext, }; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::Diagnostic; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_infer::traits::{util, TraitEngine}; +use rustc_infer::traits::util; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::subst::Subst; @@ -384,16 +384,11 @@ fn resolve_negative_obligation<'cx, 'tcx>( return false; }; - let mut fulfillment_cx = >::new(infcx.tcx); - fulfillment_cx.register_predicate_obligation(infcx, o); - - let errors = fulfillment_cx.select_all_or_error(infcx); - + let errors = super::fully_solve_obligation(infcx, o); if !errors.is_empty() { return false; } - // FIXME -- also add "assumed to be well formed" types into the `outlives_env` let outlives_env = OutlivesEnvironment::new(param_env); infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env); diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index b8cbfcb8b79..5fc0128d8c6 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -30,6 +30,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; +use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::visit::TypeVisitable; @@ -161,22 +162,20 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>( // this function's result remains infallible, we must confirm // that guess. While imperfect, I believe this is sound. - // The handling of regions in this area of the code is terrible, - // see issue #29149. We should be able to improve on this with - // NLL. - let mut fulfill_cx = >::new(infcx.tcx); - // We can use a dummy node-id here because we won't pay any mind // to region obligations that arise (there shouldn't really be any // anyhow). let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID); - fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause); + // The handling of regions in this area of the code is terrible, + // see issue #29149. We should be able to improve on this with + // NLL. + let errors = fully_solve_bound(infcx, cause, param_env, ty, def_id); // Note: we only assume something is `Copy` if we can // *definitively* show that it implements `Copy`. Otherwise, // assume it is move; linear is always ok. - match fulfill_cx.select_all_or_error(infcx).as_slice() { + match &errors[..] { [] => { debug!( "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", @@ -413,6 +412,36 @@ where Ok(resolved_value) } +pub fn fully_solve_obligation<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + obligation: PredicateObligation<'tcx>, +) -> Vec> { + let mut engine = >::new(infcx.tcx); + engine.register_predicate_obligation(infcx, obligation); + engine.select_all_or_error(infcx) +} + +pub fn fully_solve_obligations<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + obligations: impl IntoIterator>, +) -> Vec> { + let mut engine = >::new(infcx.tcx); + engine.register_predicate_obligations(infcx, obligations); + engine.select_all_or_error(infcx) +} + +pub fn fully_solve_bound<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + cause: ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + bound: DefId, +) -> Vec> { + let mut engine = >::new(infcx.tcx); + engine.register_bound(infcx, param_env, ty, bound, cause); + engine.select_all_or_error(infcx) +} + /// Normalizes the predicates and checks whether they hold in an empty environment. If this /// returns true, then either normalize encountered an error or one of the predicates did not /// hold. Used when creating vtables to check for unsatisfiable methods. diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index c99564936aa..f6e196e3141 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -1,11 +1,9 @@ use crate::infer::canonical::query_response; use crate::infer::{InferCtxt, InferOk}; -use crate::traits::engine::TraitEngineExt as _; +use crate::traits; use crate::traits::query::type_op::TypeOpOutput; use crate::traits::query::Fallible; -use crate::traits::TraitEngine; use rustc_infer::infer::region_constraints::RegionConstraintData; -use rustc_infer::traits::TraitEngineExt as _; use rustc_span::source_map::DUMMY_SP; use std::fmt; @@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( infcx: &InferCtxt<'_, 'tcx>, op: impl FnOnce() -> Fallible>, ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> { - let mut fulfill_cx = >::new(infcx.tcx); - // During NLL, we expect that nobody will register region // obligations **except** as part of a custom type op (and, at the // end of each custom type op, we scrape out the region @@ -77,8 +73,7 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>( ); let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; - fulfill_cx.register_predicate_obligations(infcx, obligations); - let errors = fulfill_cx.select_all_or_error(infcx); + let errors = traits::fully_solve_obligations(infcx, obligations); if !errors.is_empty() { infcx.tcx.sess.diagnostic().delay_span_bug( DUMMY_SP, diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0506c200c61..0f76fef0eee 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -14,9 +14,7 @@ use specialization_graph::GraphExt; use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; use crate::traits::select::IntercrateAmbiguityCause; -use crate::traits::{ - self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine, TraitEngineExt, -}; +use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause}; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -26,8 +24,8 @@ use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK; use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS; use rustc_span::{Span, DUMMY_SP}; +use super::util; use super::SelectionContext; -use super::{util, FulfillmentContext}; /// Information pertinent to an overlapping impl error. #[derive(Debug)] @@ -210,11 +208,8 @@ fn fulfill_implication<'a, 'tcx>( // (which are packed up in penv) infcx.save_and_restore_in_snapshot_flag(|infcx| { - let mut fulfill_cx = >::new(infcx.tcx); - for oblig in obligations.chain(more_obligations) { - fulfill_cx.register_predicate_obligation(&infcx, oblig); - } - match fulfill_cx.select_all_or_error(infcx).as_slice() { + let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations)); + match &errors[..] { [] => { debug!( "fulfill_implication: an impl for {:?} specializes {:?}", diff --git a/compiler/rustc_typeck/src/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs index 50946cc1def..043e21fc1e3 100644 --- a/compiler/rustc_typeck/src/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeV use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError}; use rustc_trait_selection::traits::predicate_for_trait_def; -use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt}; +use rustc_trait_selection::traits::{self, ObligationCause}; use std::collections::BTreeMap; pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) { @@ -109,15 +109,13 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { // it is not immediately clear why Copy is not implemented for a field, since // all we point at is the field itself. tcx.infer_ctxt().ignoring_regions().enter(|infcx| { - let mut fulfill_cx = >::new(tcx); - fulfill_cx.register_bound( + for error in traits::fully_solve_bound( &infcx, + traits::ObligationCause::dummy_with_span(field_ty_span), param_env, ty, tcx.lang_items().copy_trait().unwrap(), - traits::ObligationCause::dummy_with_span(field_ty_span), - ); - for error in fulfill_cx.select_all_or_error(&infcx) { + ) { let error_predicate = error.obligation.predicate; // Only note if it's not the root obligation, otherwise it's trivial and // should be self-explanatory (i.e. a field literally doesn't implement Copy). @@ -315,24 +313,20 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did: )) .emit(); } else { - let mut fulfill_cx = >::new(infcx.tcx); - - for field in coerced_fields { - let predicate = predicate_for_trait_def( - tcx, - param_env, - cause.clone(), - dispatch_from_dyn_trait, - 0, - field.ty(tcx, substs_a), - &[field.ty(tcx, substs_b).into()], - ); - - fulfill_cx.register_predicate_obligation(&infcx, predicate); - } - - // Check that all transitive obligations are satisfied. - let errors = fulfill_cx.select_all_or_error(&infcx); + let errors = traits::fully_solve_obligations( + &infcx, + coerced_fields.into_iter().map(|field| { + predicate_for_trait_def( + tcx, + param_env, + cause.clone(), + dispatch_from_dyn_trait, + 0, + field.ty(tcx, substs_a), + &[field.ty(tcx, substs_b).into()], + ) + }), + ); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } @@ -573,8 +567,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn } }; - let mut fulfill_cx = >::new(infcx.tcx); - // Register an obligation for `A: Trait`. let cause = traits::ObligationCause::misc(span, impl_hir_id); let predicate = predicate_for_trait_def( @@ -586,10 +578,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn source, &[target.into()], ); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - - // Check that all transitive obligations are satisfied. - let errors = fulfill_cx.select_all_or_error(&infcx); + let errors = traits::fully_solve_obligation(&infcx, predicate); if !errors.is_empty() { infcx.report_fulfillment_errors(&errors, None, false); } diff --git a/compiler/rustc_typeck/src/hir_wf_check.rs b/compiler/rustc_typeck/src/hir_wf_check.rs index 55c7a15f9bc..fd9715e6ca3 100644 --- a/compiler/rustc_typeck/src/hir_wf_check.rs +++ b/compiler/rustc_typeck/src/hir_wf_check.rs @@ -3,11 +3,10 @@ use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ForeignItem, ForeignItemKind, HirId}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_infer::traits::TraitEngine; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder}; -use rustc_trait_selection::traits::{self, TraitEngineExt}; +use rustc_trait_selection::traits; pub fn provide(providers: &mut Providers) { *providers = Providers { diagnostic_hir_wf_check, ..*providers }; @@ -66,7 +65,6 @@ fn diagnostic_hir_wf_check<'tcx>( impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> { fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { self.tcx.infer_ctxt().enter(|infcx| { - let mut fulfill = >::new(self.tcx); let tcx_ty = self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx }); let cause = traits::ObligationCause::new( @@ -74,7 +72,7 @@ fn diagnostic_hir_wf_check<'tcx>( self.hir_id, traits::ObligationCauseCode::WellFormed(None), ); - fulfill.register_predicate_obligation( + let errors = traits::fully_solve_obligation( &infcx, traits::Obligation::new( cause, @@ -83,8 +81,6 @@ fn diagnostic_hir_wf_check<'tcx>( .to_predicate(self.tcx), ), ); - - let errors = fulfill.select_all_or_error(&infcx); if !errors.is_empty() { debug!("Wf-check got errors for {:?}: {:?}", ty, errors); for error in errors { diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 04c54589d68..1563f3552c5 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -104,7 +104,6 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{Node, CRATE_HIR_ID}; use rustc_infer::infer::{InferOk, TyCtxtInferExt}; -use rustc_infer::traits::TraitEngineExt as _; use rustc_middle::middle; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -113,9 +112,7 @@ use rustc_session::config::EntryFnType; use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _, -}; +use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::iter; @@ -147,18 +144,15 @@ fn require_same_types<'tcx>( ) -> bool { tcx.infer_ctxt().enter(|ref infcx| { let param_env = ty::ParamEnv::empty(); - let mut fulfill_cx = >::new(infcx.tcx); - match infcx.at(cause, param_env).eq(expected, actual) { - Ok(InferOk { obligations, .. }) => { - fulfill_cx.register_predicate_obligations(infcx, obligations); - } + let errors = match infcx.at(cause, param_env).eq(expected, actual) { + Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations), Err(err) => { infcx.report_mismatched_types(cause, expected, actual, err).emit(); return false; } - } + }; - match fulfill_cx.select_all_or_error(infcx).as_slice() { + match &errors[..] { [] => true, errors => { infcx.report_fulfillment_errors(errors, None, false); diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 5c46d6c7df7..ef7d75aa8ed 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{EarlyBinder, Opaque, PredicateKind::Trait}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{sym, Span}; use rustc_trait_selection::traits::error_reporting::suggestions::InferCtxtExt; -use rustc_trait_selection::traits::{self, FulfillmentError, TraitEngine}; +use rustc_trait_selection::traits::{self, FulfillmentError}; declare_clippy_lint! { /// ### What it does @@ -80,9 +80,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { let span = decl.output.span(); let send_errors = cx.tcx.infer_ctxt().enter(|infcx| { let cause = traits::ObligationCause::misc(span, hir_id); - let mut fulfillment_cx = traits::FulfillmentContext::new(); - fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause); - fulfillment_cx.select_all_or_error(&infcx) + traits::fully_solve_bound(&infcx, cause, cx.param_env, ret_ty, send_trait) }); if !send_errors.is_empty() { span_lint_and_then(