Skip to content

Make select_* methods return Vec for TraitEngine #90700

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 9, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -339,7 +339,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway.
let _errors = fulfill_cx.select_all_or_error(infcx).err().unwrap_or_else(Vec::new);
let _errors = fulfill_cx.select_all_or_error(infcx);

let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
debug!("{:#?}", region_constraints);
5 changes: 3 additions & 2 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
@@ -1054,8 +1054,9 @@ fn check_return_ty_is_sync(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, hir_id: HirId)
let mut fulfillment_cx = traits::FulfillmentContext::new();
let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span));
fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&err, None, false);
let errors = fulfillment_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}
});
}
4 changes: 2 additions & 2 deletions compiler/rustc_infer/src/infer/canonical/query_response.rs
Original file line number Diff line number Diff line change
@@ -108,7 +108,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
let tcx = self.tcx;

// Select everything, returning errors.
let true_errors = fulfill_cx.select_where_possible(self).err().unwrap_or_else(Vec::new);
let true_errors = fulfill_cx.select_where_possible(self);
debug!("true_errors = {:#?}", true_errors);

if !true_errors.is_empty() {
@@ -118,7 +118,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
}

// Anything left unselected *now* must be an ambiguity.
let ambig_errors = fulfill_cx.select_all_or_error(self).err().unwrap_or_else(Vec::new);
let ambig_errors = fulfill_cx.select_all_or_error(self);
debug!("ambig_errors = {:#?}", ambig_errors);

let region_obligations = self.take_registered_region_obligations();
15 changes: 5 additions & 10 deletions compiler/rustc_infer/src/traits/engine.rs
Original file line number Diff line number Diff line change
@@ -46,30 +46,25 @@ pub trait TraitEngine<'tcx>: 'tcx {
obligation: PredicateObligation<'tcx>,
);

fn select_all_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>>;

fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
) -> Vec<FulfillmentError<'tcx>> {
self.select_all_or_error(infcx)
}

fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>>;
fn select_where_possible(&mut self, infcx: &InferCtxt<'_, 'tcx>)
-> Vec<FulfillmentError<'tcx>>;

// FIXME(fee1-dead) this should not provide a default body for chalk as chalk should be updated
fn select_with_constness_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
_constness: hir::Constness,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
) -> Vec<FulfillmentError<'tcx>> {
self.select_where_possible(infcx)
}

5 changes: 3 additions & 2 deletions compiler/rustc_trait_selection/src/autoderef.rs
Original file line number Diff line number Diff line change
@@ -152,11 +152,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
},
cause,
);
if let Err(e) = fulfillcx.select_where_possible(&self.infcx) {
let errors = fulfillcx.select_where_possible(&self.infcx);
if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e);
debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
return None;
}
let obligations = fulfillcx.pending_obligations();
8 changes: 5 additions & 3 deletions compiler/rustc_trait_selection/src/traits/auto_trait.rs
Original file line number Diff line number Diff line change
@@ -187,9 +187,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// an additional sanity check.
let mut fulfill = FulfillmentContext::new();
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e)
});
let errors = fulfill.select_all_or_error(&infcx);

if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
}

let body_id_map: FxHashMap<_, _> = infcx
.inner
44 changes: 21 additions & 23 deletions compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
Original file line number Diff line number Diff line change
@@ -49,34 +49,32 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
self.obligations.insert(obligation);
}

fn select_all_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
self.select_where_possible(infcx)?;

if self.obligations.is_empty() {
Ok(())
} else {
let errors = self
.obligations
.iter()
.map(|obligation| FulfillmentError {
obligation: obligation.clone(),
code: FulfillmentErrorCode::CodeAmbiguity,
// FIXME - does Chalk have a notation of 'root obligation'?
// This is just for diagnostics, so it's okay if this is wrong
root_obligation: obligation.clone(),
})
.collect();
Err(errors)
fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_where_possible(infcx);

if !errors.is_empty() {
return errors;
}
}

// any remaining obligations are errors
self.obligations
.iter()
.map(|obligation| FulfillmentError {
obligation: obligation.clone(),
code: FulfillmentErrorCode::CodeAmbiguity,
// FIXME - does Chalk have a notation of 'root obligation'?
// This is just for diagnostics, so it's okay if this is wrong
root_obligation: obligation.clone(),
})
.collect()
}

fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot());

let mut errors = Vec::new();
@@ -147,7 +145,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
}
}

if errors.is_empty() { Ok(()) } else { Err(errors) }
errors
}

fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/traits/codegen.rs
Original file line number Diff line number Diff line change
@@ -120,7 +120,8 @@ where
// In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight
// optimization to stop iterating early.
if let Err(errors) = fulfill_cx.select_all_or_error(infcx) {
let errors = fulfill_cx.select_all_or_error(infcx);
if !errors.is_empty() {
infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
&format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
52 changes: 22 additions & 30 deletions compiler/rustc_trait_selection/src/traits/fulfill.rs
Original file line number Diff line number Diff line change
@@ -126,10 +126,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
}

/// Attempts to select obligations using `selcx`.
fn select(
&mut self,
selcx: &mut SelectionContext<'a, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
fn select(&mut self, selcx: &mut SelectionContext<'a, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();

@@ -163,7 +160,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
errors.len()
);

if errors.is_empty() { Ok(()) } else { Err(errors) }
errors
}
}

@@ -223,41 +220,36 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
.register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
}

fn select_all_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
self.select_where_possible(infcx)?;

let errors: Vec<_> = self
.predicates
.to_errors(CodeAmbiguity)
.into_iter()
.map(to_fulfillment_error)
.collect();
if errors.is_empty() { Ok(()) } else { Err(errors) }
fn select_all_or_error(&mut self, infcx: &InferCtxt<'_, 'tcx>) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_where_possible(infcx);
if !errors.is_empty() {
return errors;
}
}

self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}

fn select_all_with_constness_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: rustc_hir::Constness,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
self.select_with_constness_where_possible(infcx, constness)?;

let errors: Vec<_> = self
.predicates
.to_errors(CodeAmbiguity)
.into_iter()
.map(to_fulfillment_error)
.collect();
if errors.is_empty() { Ok(()) } else { Err(errors) }
) -> Vec<FulfillmentError<'tcx>> {
{
let errors = self.select_with_constness_where_possible(infcx, constness);
if !errors.is_empty() {
return errors;
}
}

self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
}

fn select_where_possible(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::new(infcx);
self.select(&mut selcx)
}
@@ -266,7 +258,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
constness: hir::Constness,
) -> Result<(), Vec<FulfillmentError<'tcx>>> {
) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::with_constness(infcx, constness);
self.select(&mut selcx)
}
23 changes: 14 additions & 9 deletions compiler/rustc_trait_selection/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -180,21 +180,21 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
// 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) {
Ok(()) => {
match fulfill_cx.select_all_or_error(infcx).as_slice() {
[] => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty,
infcx.tcx.def_path_str(def_id)
);
true
}
Err(e) => {
errors => {
debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}",
ty,
infcx.tcx.def_path_str(def_id),
e
?ty,
bound = %infcx.tcx.def_path_str(def_id),
?errors,
"type_known_to_meet_bound_modulo_regions"
);
false
}
@@ -410,7 +410,10 @@ where
}

debug!("fully_normalize: select_all_or_error start");
fulfill_cx.select_all_or_error(infcx)?;
let errors = fulfill_cx.select_all_or_error(infcx);
if !errors.is_empty() {
return Err(errors);
}
debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_value);
@@ -441,7 +444,9 @@ pub fn impossible_predicates<'tcx>(
fulfill_cx.register_predicate_obligation(&infcx, obligation);
}

fulfill_cx.select_all_or_error(&infcx).is_err()
let errors = fulfill_cx.select_all_or_error(&infcx);

!errors.is_empty()
});
debug!("impossible_predicates = {:?}", result);
result
Original file line number Diff line number Diff line change
@@ -77,10 +77,11 @@ fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations);
if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
let errors = fulfill_cx.select_all_or_error(infcx);
if !errors.is_empty() {
infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP,
&format!("errors selecting obligation during MIR typeck: {:?}", e),
&format!("errors selecting obligation during MIR typeck: {:?}", errors),
);
}

25 changes: 12 additions & 13 deletions compiler/rustc_trait_selection/src/traits/specialize/mod.rs
Original file line number Diff line number Diff line change
@@ -225,8 +225,18 @@ fn fulfill_implication<'a, 'tcx>(
for oblig in obligations.chain(more_obligations) {
fulfill_cx.register_predicate_obligation(&infcx, oblig);
}
match fulfill_cx.select_all_or_error(infcx) {
Err(errors) => {
match fulfill_cx.select_all_or_error(infcx).as_slice() {
[] => {
debug!(
"fulfill_implication: an impl for {:?} specializes {:?}",
source_trait_ref, target_trait_ref
);

// Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_vars_if_possible(target_substs))
}
errors => {
// no dice!
debug!(
"fulfill_implication: for impls on {:?} and {:?}, \
@@ -238,17 +248,6 @@ fn fulfill_implication<'a, 'tcx>(
);
Err(())
}

Ok(()) => {
debug!(
"fulfill_implication: an impl for {:?} specializes {:?}",
source_trait_ref, target_trait_ref
);

// Now resolve the *substitution* we built for the target earlier, replacing
// the inference variables inside with whatever we got from fulfillment.
Ok(infcx.resolve_vars_if_possible(target_substs))
}
}
})
}
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ fn type_marked_structural(
//
// 2. We are sometimes doing future-incompatibility lints for
// now, so we do not want unconditional errors here.
fulfillment_cx.select_all_or_error(infcx).is_ok()
fulfillment_cx.select_all_or_error(infcx).is_empty()
}

/// This implements the traversal over the structure of a given type to try to
6 changes: 3 additions & 3 deletions compiler/rustc_traits/src/implied_outlives_bounds.rs
Original file line number Diff line number Diff line change
@@ -128,9 +128,9 @@ fn compute_implied_outlives_bounds<'tcx>(

// Ensure that those obligations that we had to solve
// get solved *here*.
match fulfill_cx.select_all_or_error(infcx) {
Ok(()) => Ok(implied_bounds),
Err(_) => Err(NoSolution),
match fulfill_cx.select_all_or_error(infcx).as_slice() {
[] => Ok(implied_bounds),
_ => Err(NoSolution),
}
}

5 changes: 3 additions & 2 deletions compiler/rustc_typeck/src/check/check.rs
Original file line number Diff line number Diff line change
@@ -663,8 +663,9 @@ fn check_opaque_meets_bounds<'tcx>(

// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(errors, None, false);
let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}

// Finally, resolve all regions. This catches wily misuses of
2 changes: 1 addition & 1 deletion compiler/rustc_typeck/src/check/coercion.rs
Original file line number Diff line number Diff line change
@@ -950,7 +950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
let mut fcx = traits::FulfillmentContext::new_in_snapshot();
fcx.register_predicate_obligations(self, ok.obligations);
fcx.select_where_possible(&self).is_ok()
fcx.select_where_possible(&self).is_empty()
})
}

23 changes: 13 additions & 10 deletions compiler/rustc_typeck/src/check/compare_method.rs
Original file line number Diff line number Diff line change
@@ -391,8 +391,9 @@ fn compare_predicate_entailment<'tcx>(

// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(errors, None, false);
let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}

@@ -1094,8 +1095,9 @@ crate fn compare_const_impl<'tcx>(

// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(errors, None, false);
let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return;
}

@@ -1210,8 +1212,9 @@ fn compare_type_predicate_entailment<'tcx>(

// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(errors, None, false);
let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}

@@ -1427,10 +1430,10 @@ pub fn check_type_bounds<'tcx>(

// Check that all obligations are satisfied by the implementation's
// version.
if let Err(ref errors) =
inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness)
{
infcx.report_fulfillment_errors(errors, None, false);
let errors =
inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}

5 changes: 3 additions & 2 deletions compiler/rustc_typeck/src/check/dropck.rs
Original file line number Diff line number Diff line change
@@ -113,9 +113,10 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
}
}

if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
let errors = fulfillment_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
// this could be reached when we get lazy normalization
infcx.report_fulfillment_errors(errors, None, false);
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported);
}

24 changes: 14 additions & 10 deletions compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
Original file line number Diff line number Diff line change
@@ -642,11 +642,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

#[instrument(skip(self), level = "debug")]
pub(in super::super) fn select_all_obligations_or_error(&self) {
if let Err(errors) = self
let errors = self
.fulfillment_cx
.borrow_mut()
.select_all_with_constness_or_error(&self, self.inh.constness)
{
.select_all_with_constness_or_error(&self, self.inh.constness);

if !errors.is_empty() {
self.report_fulfillment_errors(&errors, self.inh.body_id, false);
}
}
@@ -657,13 +658,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
let result = self
let mut result = self
.fulfillment_cx
.borrow_mut()
.select_with_constness_where_possible(self, self.inh.constness);
if let Err(mut errors) = result {
mutate_fulfillment_errors(&mut errors);
self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred);
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.report_fulfillment_errors(&result, self.inh.body_id, fallback_has_occurred);
}
}

@@ -793,14 +794,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're
// just trying to get hints here.
self.save_and_restore_in_snapshot_flag(|_| {
let errors = self.save_and_restore_in_snapshot_flag(|_| {
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation);
}
fulfill.select_where_possible(self)
})
.map_err(|_| ())?;
});

if !errors.is_empty() {
return Err(());
}
}
Err(_) => return Err(()),
}
5 changes: 1 addition & 4 deletions compiler/rustc_typeck/src/check/op.rs
Original file line number Diff line number Diff line change
@@ -826,10 +826,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
fulfill.register_predicate_obligation(self, obligation);
Err(match fulfill.select_where_possible(&self.infcx) {
Err(errors) => errors,
_ => vec![],
})
Err(fulfill.select_where_possible(&self.infcx))
}
}
}
6 changes: 4 additions & 2 deletions compiler/rustc_typeck/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
@@ -263,7 +263,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
}

// Check that all transitive obligations are satisfied.
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}

@@ -522,7 +523,8 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI
fulfill_cx.register_predicate_obligation(&infcx, predicate);

// Check that all transitive obligations are satisfied.
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
let errors = fulfill_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
}

3 changes: 2 additions & 1 deletion compiler/rustc_typeck/src/hir_wf_check.rs
Original file line number Diff line number Diff line change
@@ -88,7 +88,8 @@ fn diagnostic_hir_wf_check<'tcx>(
),
);

if let Err(errors) = fulfill.select_all_or_error(&infcx) {
let errors = fulfill.select_all_or_error(&infcx);
if !errors.is_empty() {
tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors {
if error.obligation.predicate == self.predicate {
13 changes: 7 additions & 6 deletions compiler/rustc_typeck/src/lib.rs
Original file line number Diff line number Diff line change
@@ -157,10 +157,10 @@ fn require_same_types<'tcx>(
}
}

match fulfill_cx.select_all_or_error(infcx) {
Ok(()) => true,
Err(errors) => {
infcx.report_fulfillment_errors(&errors, None, false);
match fulfill_cx.select_all_or_error(infcx).as_slice() {
[] => true,
errors => {
infcx.report_fulfillment_errors(errors, None, false);
false
}
}
@@ -352,8 +352,9 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
term_id,
cause,
);
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&err, None, false);
let errors = fulfillment_cx.select_all_or_error(&infcx);
if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
error = true;
}
});
3 changes: 2 additions & 1 deletion compiler/rustc_typeck/src/outlives/outlives_bounds.rs
Original file line number Diff line number Diff line change
@@ -83,7 +83,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
// variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new();
fulfill_cx.register_predicate_obligations(self, result.obligations);
if fulfill_cx.select_all_or_error(self).is_err() {
let errors = fulfill_cx.select_all_or_error(self);
if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
"implied_outlives_bounds failed to solve obligations from instantiation",
4 changes: 2 additions & 2 deletions src/tools/clippy/clippy_lints/src/future_not_send.rs
Original file line number Diff line number Diff line change
@@ -77,13 +77,13 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
if is_future {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span();
let send_result = cx.tcx.infer_ctxt().enter(|infcx| {
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)
});
if let Err(send_errors) = send_result {
if !send_errors.is_empty() {
span_lint_and_then(
cx,
FUTURE_NOT_SEND,