Skip to content

Commit fe89475

Browse files
Add traits::fully_solve_obligation that acts like traits::fully_normalize
It spawns up a trait engine, registers the single obligation, then fully solves it
1 parent 3e48434 commit fe89475

File tree

10 files changed

+78
-97
lines changed

10 files changed

+78
-97
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-9
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;
@@ -384,16 +384,11 @@ fn resolve_negative_obligation<'cx, 'tcx>(
384384
return false;
385385
};
386386

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

396-
// FIXME -- also add "assumed to be well formed" types into the `outlives_env`
397392
let outlives_env = OutlivesEnvironment::new(param_env);
398393
infcx.process_registered_region_obligations(outlives_env.region_bound_pairs(), param_env);
399394

compiler/rustc_trait_selection/src/traits/mod.rs

+36-7
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",
@@ -413,6 +412,36 @@ where
413412
Ok(resolved_value)
414413
}
415414

415+
pub fn fully_solve_obligation<'a, 'tcx>(
416+
infcx: &InferCtxt<'a, 'tcx>,
417+
obligation: PredicateObligation<'tcx>,
418+
) -> Vec<FulfillmentError<'tcx>> {
419+
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
420+
engine.register_predicate_obligation(infcx, obligation);
421+
engine.select_all_or_error(infcx)
422+
}
423+
424+
pub fn fully_solve_obligations<'a, 'tcx>(
425+
infcx: &InferCtxt<'a, 'tcx>,
426+
obligations: impl IntoIterator<Item = PredicateObligation<'tcx>>,
427+
) -> Vec<FulfillmentError<'tcx>> {
428+
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
429+
engine.register_predicate_obligations(infcx, obligations);
430+
engine.select_all_or_error(infcx)
431+
}
432+
433+
pub fn fully_solve_bound<'a, 'tcx>(
434+
infcx: &InferCtxt<'a, 'tcx>,
435+
cause: ObligationCause<'tcx>,
436+
param_env: ty::ParamEnv<'tcx>,
437+
ty: Ty<'tcx>,
438+
bound: DefId,
439+
) -> Vec<FulfillmentError<'tcx>> {
440+
let mut engine = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
441+
engine.register_bound(infcx, param_env, ty, bound, cause);
442+
engine.select_all_or_error(infcx)
443+
}
444+
416445
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
417446
/// returns true, then either normalize encountered an error or one of the predicates did not
418447
/// hold. Used when creating vtables to check for unsatisfiable methods.

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/specialize/mod.rs

+4-9
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)]
@@ -210,11 +208,8 @@ fn fulfill_implication<'a, 'tcx>(
210208
// (which are packed up in penv)
211209

212210
infcx.save_and_restore_in_snapshot_flag(|infcx| {
213-
let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
214-
for oblig in obligations.chain(more_obligations) {
215-
fulfill_cx.register_predicate_obligation(&infcx, oblig);
216-
}
217-
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[..] {
218213
[] => {
219214
debug!(
220215
"fulfill_implication: an impl for {:?} specializes {:?}",

compiler/rustc_typeck/src/coherence/builtin.rs

+19-30
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeV
1515
use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
1616
use rustc_trait_selection::traits::misc::{can_type_implement_copy, CopyImplementationError};
1717
use rustc_trait_selection::traits::predicate_for_trait_def;
18-
use rustc_trait_selection::traits::{self, ObligationCause, TraitEngine, TraitEngineExt};
18+
use rustc_trait_selection::traits::{self, ObligationCause};
1919
use std::collections::BTreeMap;
2020

2121
pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
@@ -109,15 +109,13 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
109109
// it is not immediately clear why Copy is not implemented for a field, since
110110
// all we point at is the field itself.
111111
tcx.infer_ctxt().ignoring_regions().enter(|infcx| {
112-
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
113-
fulfill_cx.register_bound(
112+
for error in traits::fully_solve_bound(
114113
&infcx,
114+
traits::ObligationCause::dummy_with_span(field_ty_span),
115115
param_env,
116116
ty,
117117
tcx.lang_items().copy_trait().unwrap(),
118-
traits::ObligationCause::dummy_with_span(field_ty_span),
119-
);
120-
for error in fulfill_cx.select_all_or_error(&infcx) {
118+
) {
121119
let error_predicate = error.obligation.predicate;
122120
// Only note if it's not the root obligation, otherwise it's trivial and
123121
// 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:
315313
))
316314
.emit();
317315
} else {
318-
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
319-
320-
for field in coerced_fields {
321-
let predicate = predicate_for_trait_def(
322-
tcx,
323-
param_env,
324-
cause.clone(),
325-
dispatch_from_dyn_trait,
326-
0,
327-
field.ty(tcx, substs_a),
328-
&[field.ty(tcx, substs_b).into()],
329-
);
330-
331-
fulfill_cx.register_predicate_obligation(&infcx, predicate);
332-
}
333-
334-
// Check that all transitive obligations are satisfied.
335-
let errors = fulfill_cx.select_all_or_error(&infcx);
316+
let errors = traits::fully_solve_obligations(
317+
&infcx,
318+
coerced_fields.into_iter().map(|field| {
319+
predicate_for_trait_def(
320+
tcx,
321+
param_env,
322+
cause.clone(),
323+
dispatch_from_dyn_trait,
324+
0,
325+
field.ty(tcx, substs_a),
326+
&[field.ty(tcx, substs_b).into()],
327+
)
328+
}),
329+
);
336330
if !errors.is_empty() {
337331
infcx.report_fulfillment_errors(&errors, None, false);
338332
}
@@ -573,8 +567,6 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
573567
}
574568
};
575569

576-
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
577-
578570
// Register an obligation for `A: Trait<B>`.
579571
let cause = traits::ObligationCause::misc(span, impl_hir_id);
580572
let predicate = predicate_for_trait_def(
@@ -586,10 +578,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
586578
source,
587579
&[target.into()],
588580
);
589-
fulfill_cx.register_predicate_obligation(&infcx, predicate);
590-
591-
// Check that all transitive obligations are satisfied.
592-
let errors = fulfill_cx.select_all_or_error(&infcx);
581+
let errors = traits::fully_solve_obligation(&infcx, predicate);
593582
if !errors.is_empty() {
594583
infcx.report_fulfillment_errors(&errors, None, false);
595584
}

compiler/rustc_typeck/src/hir_wf_check.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ use rustc_hir as hir;
33
use rustc_hir::intravisit::{self, Visitor};
44
use rustc_hir::{ForeignItem, ForeignItemKind, HirId};
55
use rustc_infer::infer::TyCtxtInferExt;
6-
use rustc_infer::traits::TraitEngine;
76
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
87
use rustc_middle::ty::query::Providers;
98
use rustc_middle::ty::{self, Region, ToPredicate, TyCtxt, TypeFoldable, TypeFolder};
10-
use rustc_trait_selection::traits::{self, TraitEngineExt};
9+
use rustc_trait_selection::traits;
1110

1211
pub fn provide(providers: &mut Providers) {
1312
*providers = Providers { diagnostic_hir_wf_check, ..*providers };
@@ -66,15 +65,14 @@ fn diagnostic_hir_wf_check<'tcx>(
6665
impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
6766
fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
6867
self.tcx.infer_ctxt().enter(|infcx| {
69-
let mut fulfill = <dyn TraitEngine<'tcx>>::new(self.tcx);
7068
let tcx_ty =
7169
self.icx.to_ty(ty).fold_with(&mut EraseAllBoundRegions { tcx: self.tcx });
7270
let cause = traits::ObligationCause::new(
7371
ty.span,
7472
self.hir_id,
7573
traits::ObligationCauseCode::WellFormed(None),
7674
);
77-
fulfill.register_predicate_obligation(
75+
let errors = traits::fully_solve_obligation(
7876
&infcx,
7977
traits::Obligation::new(
8078
cause,
@@ -83,8 +81,6 @@ fn diagnostic_hir_wf_check<'tcx>(
8381
.to_predicate(self.tcx),
8482
),
8583
);
86-
87-
let errors = fulfill.select_all_or_error(&infcx);
8884
if !errors.is_empty() {
8985
debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
9086
for error in errors {

compiler/rustc_typeck/src/lib.rs

+5-11
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,6 @@ use rustc_hir as hir;
104104
use rustc_hir::def_id::DefId;
105105
use rustc_hir::{Node, CRATE_HIR_ID};
106106
use rustc_infer::infer::{InferOk, TyCtxtInferExt};
107-
use rustc_infer::traits::TraitEngineExt as _;
108107
use rustc_middle::middle;
109108
use rustc_middle::ty::query::Providers;
110109
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -113,9 +112,7 @@ use rustc_session::config::EntryFnType;
113112
use rustc_span::{symbol::sym, Span, DUMMY_SP};
114113
use rustc_target::spec::abi::Abi;
115114
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
116-
use rustc_trait_selection::traits::{
117-
self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt as _,
118-
};
115+
use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode};
119116

120117
use std::iter;
121118

@@ -147,18 +144,15 @@ fn require_same_types<'tcx>(
147144
) -> bool {
148145
tcx.infer_ctxt().enter(|ref infcx| {
149146
let param_env = ty::ParamEnv::empty();
150-
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
151-
match infcx.at(cause, param_env).eq(expected, actual) {
152-
Ok(InferOk { obligations, .. }) => {
153-
fulfill_cx.register_predicate_obligations(infcx, obligations);
154-
}
147+
let errors = match infcx.at(cause, param_env).eq(expected, actual) {
148+
Ok(InferOk { obligations, .. }) => traits::fully_solve_obligations(infcx, obligations),
155149
Err(err) => {
156150
infcx.report_mismatched_types(cause, expected, actual, err).emit();
157151
return false;
158152
}
159-
}
153+
};
160154

161-
match fulfill_cx.select_all_or_error(infcx).as_slice() {
155+
match &errors[..] {
162156
[] => true,
163157
errors => {
164158
infcx.report_fulfillment_errors(errors, None, false);

0 commit comments

Comments
 (0)