Skip to content

Commit bd04658

Browse files
committed
Auto merge of #99743 - compiler-errors:fulfillment-context-cleanups, r=jackh726
Some `FulfillmentContext`-related cleanups Use `ObligationCtxt` in some places, remove some `FulfillmentContext`s in others... r? types
2 parents 55f4641 + f5af266 commit bd04658

File tree

12 files changed

+127
-163
lines changed

12 files changed

+127
-163
lines changed

compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,11 @@
55
use rustc_errors::ErrorGuaranteed;
66
use rustc_hir::LangItem;
77
use rustc_infer::infer::TyCtxtInferExt;
8-
use rustc_infer::traits::TraitEngine;
98
use rustc_middle::mir::*;
109
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
1110
use rustc_span::DUMMY_SP;
1211
use rustc_trait_selection::traits::{
13-
self, ImplSource, Obligation, ObligationCause, SelectionContext, TraitEngineExt,
12+
self, ImplSource, Obligation, ObligationCause, SelectionContext,
1413
};
1514

1615
use super::ConstCx;
@@ -189,15 +188,8 @@ impl Qualif for NeedsNonConstDrop {
189188
return false;
190189
}
191190

192-
// If we successfully found one, then select all of the predicates
193-
// implied by our const drop impl.
194-
let mut fcx = <dyn TraitEngine<'tcx>>::new(cx.tcx);
195-
for nested in impl_src.nested_obligations() {
196-
fcx.register_predicate_obligation(&infcx, nested);
197-
}
198-
199191
// If we had any errors, then it's bad
200-
!fcx.select_all_or_error(&infcx).is_empty()
192+
!traits::fully_solve_obligations(&infcx, impl_src.nested_obligations()).is_empty()
201193
})
202194
}
203195

compiler/rustc_trait_selection/src/traits/auto_trait.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -205,10 +205,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
205205
// At this point, we already have all of the bounds we need. FulfillmentContext is used
206206
// to store all of the necessary region/lifetime bounds in the InferContext, as well as
207207
// an additional sanity check.
208-
let mut fulfill = <dyn TraitEngine<'tcx>>::new(tcx);
209-
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
210-
let errors = fulfill.select_all_or_error(&infcx);
211-
208+
let errors =
209+
super::fully_solve_bound(&infcx, ObligationCause::dummy(), full_env, ty, trait_did);
212210
if !errors.is_empty() {
213211
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
214212
}

compiler/rustc_trait_selection/src/traits/coherence.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ use crate::traits::select::IntercrateAmbiguityCause;
1010
use crate::traits::util::impl_subject_and_oblig;
1111
use crate::traits::SkipLeakCheck;
1212
use crate::traits::{
13-
self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
14-
PredicateObligations, SelectionContext, TraitEngineExt,
13+
self, Normalized, Obligation, ObligationCause, PredicateObligation, PredicateObligations,
14+
SelectionContext,
1515
};
1616
use rustc_data_structures::fx::FxIndexSet;
1717
use rustc_errors::Diagnostic;
1818
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1919
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
20-
use rustc_infer::traits::{util, TraitEngine};
20+
use rustc_infer::traits::util;
2121
use rustc_middle::traits::specialization_graph::OverlapMode;
2222
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
2323
use rustc_middle::ty::subst::Subst;
@@ -302,7 +302,6 @@ fn negative_impl<'cx, 'tcx>(
302302
let impl_env = tcx.param_env(impl1_def_id);
303303
let subject1 = match traits::fully_normalize(
304304
&infcx,
305-
FulfillmentContext::new(),
306305
ObligationCause::dummy(),
307306
impl_env,
308307
tcx.impl_subject(impl1_def_id),
@@ -385,16 +384,11 @@ fn resolve_negative_obligation<'cx, 'tcx>(
385384
return false;
386385
};
387386

388-
let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
389-
fulfillment_cx.register_predicate_obligation(infcx, o);
390-
391-
let errors = fulfillment_cx.select_all_or_error(infcx);
392-
387+
let errors = super::fully_solve_obligation(infcx, o);
393388
if !errors.is_empty() {
394389
return false;
395390
}
396391

397-
// FIXME -- also add "assumed to be well formed" types into the `outlives_env`
398392
let outlives_env = OutlivesEnvironment::new(param_env);
399393
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
400394

compiler/rustc_trait_selection/src/traits/misc.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,7 @@ pub fn can_type_implement_copy<'tcx>(
6363
} else {
6464
ObligationCause::dummy_with_span(span)
6565
};
66-
let ctx = traits::FulfillmentContext::new();
67-
match traits::fully_normalize(&infcx, ctx, cause, param_env, ty) {
66+
match traits::fully_normalize(&infcx, cause, param_env, ty) {
6867
Ok(ty) => {
6968
if !infcx.type_is_copy_modulo_regions(param_env, ty, span) {
7069
infringing.push((field, ty));

compiler/rustc_trait_selection/src/traits/mod.rs

+59-30
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use rustc_errors::ErrorGuaranteed;
3030
use rustc_hir as hir;
3131
use rustc_hir::def_id::DefId;
3232
use rustc_hir::lang_items::LangItem;
33+
use rustc_infer::traits::TraitEngineExt as _;
3334
use rustc_middle::ty::fold::TypeFoldable;
3435
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
3536
use rustc_middle::ty::visit::TypeVisitable;
@@ -161,22 +162,20 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
161162
// this function's result remains infallible, we must confirm
162163
// that guess. While imperfect, I believe this is sound.
163164

164-
// The handling of regions in this area of the code is terrible,
165-
// see issue #29149. We should be able to improve on this with
166-
// NLL.
167-
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
168-
169165
// We can use a dummy node-id here because we won't pay any mind
170166
// to region obligations that arise (there shouldn't really be any
171167
// anyhow).
172168
let cause = ObligationCause::misc(span, hir::CRATE_HIR_ID);
173169

174-
fulfill_cx.register_bound(infcx, param_env, ty, def_id, cause);
170+
// The handling of regions in this area of the code is terrible,
171+
// see issue #29149. We should be able to improve on this with
172+
// NLL.
173+
let errors = fully_solve_bound(infcx, cause, param_env, ty, def_id);
175174

176175
// Note: we only assume something is `Copy` if we can
177176
// *definitively* show that it implements `Copy`. Otherwise,
178177
// assume it is move; linear is always ok.
179-
match fulfill_cx.select_all_or_error(infcx).as_slice() {
178+
match &errors[..] {
180179
[] => {
181180
debug!(
182181
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
@@ -222,15 +221,13 @@ fn do_normalize_predicates<'tcx>(
222221
// them here too, and we will remove this function when
223222
// we move over to lazy normalization *anyway*.
224223
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
225-
let fulfill_cx = FulfillmentContext::new();
226-
let predicates =
227-
match fully_normalize(&infcx, fulfill_cx, cause, elaborated_env, predicates) {
228-
Ok(predicates) => predicates,
229-
Err(errors) => {
230-
let reported = infcx.report_fulfillment_errors(&errors, None, false);
231-
return Err(reported);
232-
}
233-
};
224+
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
225+
Ok(predicates) => predicates,
226+
Err(errors) => {
227+
let reported = infcx.report_fulfillment_errors(&errors, None, false);
228+
return Err(reported);
229+
}
230+
};
234231

235232
debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
236233

@@ -381,9 +378,9 @@ pub fn normalize_param_env_or_error<'tcx>(
381378
)
382379
}
383380

381+
/// Normalize a type and process all resulting obligations, returning any errors
384382
pub fn fully_normalize<'a, 'tcx, T>(
385383
infcx: &InferCtxt<'a, 'tcx>,
386-
mut fulfill_cx: FulfillmentContext<'tcx>,
387384
cause: ObligationCause<'tcx>,
388385
param_env: ty::ParamEnv<'tcx>,
389386
value: T,
@@ -399,8 +396,10 @@ where
399396
"fully_normalize: normalized_value={:?} obligations={:?}",
400397
normalized_value, obligations
401398
);
399+
400+
let mut fulfill_cx = FulfillmentContext::new();
402401
for obligation in obligations {
403-
fulfill_cx.register_predicate_obligation(selcx.infcx(), obligation);
402+
fulfill_cx.register_predicate_obligation(infcx, obligation);
404403
}
405404

406405
debug!("fully_normalize: select_all_or_error start");
@@ -414,6 +413,43 @@ where
414413
Ok(resolved_value)
415414
}
416415

416+
/// Process an obligation (and any nested obligations that come from it) to
417+
/// completion, returning any errors
418+
pub fn fully_solve_obligation<'a, 'tcx>(
419+
infcx: &InferCtxt<'a, 'tcx>,
420+
obligation: PredicateObligation<'tcx>,
421+
) -> Vec<FulfillmentError<'tcx>> {
422+
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
423+
engine.register_predicate_obligation(infcx, obligation);
424+
engine.select_all_or_error(infcx)
425+
}
426+
427+
/// Process a set of obligations (and any nested obligations that come from them)
428+
/// to completion
429+
pub fn fully_solve_obligations<'a, 'tcx>(
430+
infcx: &InferCtxt<'a, 'tcx>,
431+
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
432+
) -> Vec<FulfillmentError<'tcx>> {
433+
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
434+
engine.register_predicate_obligations(infcx, obligations);
435+
engine.select_all_or_error(infcx)
436+
}
437+
438+
/// Process a bound (and any nested obligations that come from it) to completion.
439+
/// This is a convenience function for traits that have no generic arguments, such
440+
/// as auto traits, and builtin traits like Copy or Sized.
441+
pub fn fully_solve_bound<'a, 'tcx>(
442+
infcx: &InferCtxt<'a, 'tcx>,
443+
cause: ObligationCause<'tcx>,
444+
param_env: ty::ParamEnv<'tcx>,
445+
ty: Ty<'tcx>,
446+
bound: DefId,
447+
) -> Vec<FulfillmentError<'tcx>> {
448+
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
449+
engine.register_bound(infcx, param_env, ty, bound, cause);
450+
engine.select_all_or_error(infcx)
451+
}
452+
417453
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
418454
/// returns true, then either normalize encountered an error or one of the predicates did not
419455
/// hold. Used when creating vtables to check for unsatisfiable methods.
@@ -428,20 +464,13 @@ pub fn impossible_predicates<'tcx>(
428464
infcx.set_tainted_by_errors();
429465

430466
let param_env = ty::ParamEnv::reveal_all();
431-
let mut selcx = SelectionContext::new(&infcx);
432-
let mut fulfill_cx = FulfillmentContext::new();
433-
let cause = ObligationCause::dummy();
434-
let Normalized { value: predicates, obligations } =
435-
normalize(&mut selcx, param_env, cause.clone(), predicates);
436-
for obligation in obligations {
437-
fulfill_cx.register_predicate_obligation(&infcx, obligation);
438-
}
467+
let ocx = ObligationCtxt::new(&infcx);
468+
let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates);
439469
for predicate in predicates {
440-
let obligation = Obligation::new(cause.clone(), param_env, predicate);
441-
fulfill_cx.register_predicate_obligation(&infcx, obligation);
470+
let obligation = Obligation::new(ObligationCause::dummy(), param_env, predicate);
471+
ocx.register_obligation(obligation);
442472
}
443-
444-
let errors = fulfill_cx.select_all_or_error(&infcx);
473+
let errors = ocx.select_all_or_error();
445474

446475
// Clean up after ourselves
447476
let _ = infcx.inner.borrow_mut().opaque_type_storage.take_opaque_types();

compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
use crate::infer::canonical::query_response;
22
use crate::infer::{InferCtxt, InferOk};
3-
use crate::traits::engine::TraitEngineExt as _;
3+
use crate::traits;
44
use crate::traits::query::type_op::TypeOpOutput;
55
use crate::traits::query::Fallible;
6-
use crate::traits::TraitEngine;
76
use rustc_infer::infer::region_constraints::RegionConstraintData;
8-
use rustc_infer::traits::TraitEngineExt as _;
97
use rustc_span::source_map::DUMMY_SP;
108

119
use std::fmt;
@@ -62,8 +60,6 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
6260
infcx: &InferCtxt<'_, 'tcx>,
6361
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
6462
) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
65-
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
66-
6763
// During NLL, we expect that nobody will register region
6864
// obligations **except** as part of a custom type op (and, at the
6965
// 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>(
7773
);
7874

7975
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
80-
fulfill_cx.register_predicate_obligations(infcx, obligations);
81-
let errors = fulfill_cx.select_all_or_error(infcx);
76+
let errors = traits::fully_solve_obligations(infcx, obligations);
8277
if !errors.is_empty() {
8378
infcx.tcx.sess.diagnostic().delay_span_bug(
8479
DUMMY_SP,

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+18-15
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use hir::LangItem;
99
use rustc_hir as hir;
1010
use rustc_hir::def_id::DefId;
11-
use rustc_infer::traits::TraitEngine;
11+
use rustc_infer::traits::ObligationCause;
1212
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
1313
use rustc_lint_defs::builtin::DEREF_INTO_DYN_SUPERTRAIT;
1414
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -706,8 +706,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
706706
fn need_migrate_deref_output_trait_object(
707707
&mut self,
708708
ty: Ty<'tcx>,
709-
cause: &traits::ObligationCause<'tcx>,
710709
param_env: ty::ParamEnv<'tcx>,
710+
cause: &ObligationCause<'tcx>,
711711
) -> Option<(Ty<'tcx>, DefId)> {
712712
let tcx = self.tcx();
713713
if tcx.features().trait_upcasting {
@@ -729,24 +729,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
729729
return None;
730730
}
731731

732-
let mut fulfillcx = traits::FulfillmentContext::new_in_snapshot();
733-
let normalized_ty = fulfillcx.normalize_projection_type(
734-
&self.infcx,
732+
let ty = traits::normalize_projection_type(
733+
self,
735734
param_env,
736735
ty::ProjectionTy {
737736
item_def_id: tcx.lang_items().deref_target()?,
738737
substs: trait_ref.substs,
739738
},
740739
cause.clone(),
741-
);
742-
743-
let ty::Dynamic(data, ..) = normalized_ty.kind() else {
744-
return None;
745-
};
746-
747-
let def_id = data.principal_def_id()?;
748-
749-
return Some((normalized_ty, def_id));
740+
0,
741+
// We're *intentionally* throwing these away,
742+
// since we don't actually use them.
743+
&mut vec![],
744+
)
745+
.ty()
746+
.unwrap();
747+
748+
if let ty::Dynamic(data, ..) = ty.kind() {
749+
Some((ty, data.principal_def_id()?))
750+
} else {
751+
None
752+
}
750753
}
751754

752755
/// Searches for unsizing that might apply to `obligation`.
@@ -809,8 +812,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
809812
if let Some((deref_output_ty, deref_output_trait_did)) = self
810813
.need_migrate_deref_output_trait_object(
811814
source,
812-
&obligation.cause,
813815
obligation.param_env,
816+
&obligation.cause,
814817
)
815818
{
816819
if deref_output_trait_did == target_trait_did {

compiler/rustc_trait_selection/src/traits/specialize/mod.rs

+4-10
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ use specialization_graph::GraphExt;
1414

1515
use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt};
1616
use crate::traits::select::IntercrateAmbiguityCause;
17-
use crate::traits::{
18-
self, coherence, FutureCompatOverlapErrorKind, ObligationCause, TraitEngine, TraitEngineExt,
19-
};
17+
use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
2018
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
2119
use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
2220
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -26,8 +24,8 @@ use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
2624
use rustc_session::lint::builtin::ORDER_DEPENDENT_TRAIT_OBJECTS;
2725
use rustc_span::{Span, DUMMY_SP};
2826

27+
use super::util;
2928
use super::SelectionContext;
30-
use super::{util, FulfillmentContext};
3129

3230
/// Information pertinent to an overlapping impl error.
3331
#[derive(Debug)]
@@ -153,7 +151,6 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
153151
tcx.infer_ctxt().enter(|infcx| {
154152
let impl1_trait_ref = match traits::fully_normalize(
155153
&infcx,
156-
FulfillmentContext::new(),
157154
ObligationCause::dummy(),
158155
penv,
159156
impl1_trait_ref,
@@ -211,11 +208,8 @@ fn fulfill_implication<'a, 'tcx>(
211208
// (which are packed up in penv)
212209

213210
infcx.save_and_restore_in_snapshot_flag(|infcx| {
214-
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
215-
for oblig in obligations.chain(more_obligations) {
216-
fulfill_cx.register_predicate_obligation(&infcx, oblig);
217-
}
218-
match fulfill_cx.select_all_or_error(infcx).as_slice() {
211+
let errors = traits::fully_solve_obligations(&infcx, obligations.chain(more_obligations));
212+
match &errors[..] {
219213
[] => {
220214
debug!(
221215
"fulfill_implication: an impl for {:?} specializes {:?}",

0 commit comments

Comments
 (0)