1
Fork 0

Make select_* methods return Vec for TraitEngine

This commit is contained in:
Deadbeef 2021-11-08 23:35:23 +08:00
parent b3074819f6
commit f1126f1272
No known key found for this signature in database
GPG key ID: 027DF9338862ADDD
25 changed files with 147 additions and 117 deletions

View file

@ -339,7 +339,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
// We generally shouldn't have errors here because the query was // We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug` // already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway. // 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| { let (sub_region, cause) = infcx.with_region_constraints(|region_constraints| {
debug!("{:#?}", region_constraints); debug!("{:#?}", region_constraints);

View file

@ -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 mut fulfillment_cx = traits::FulfillmentContext::new();
let sync_def_id = tcx.require_lang_item(LangItem::Sync, Some(body.span)); 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); fulfillment_cx.register_bound(&infcx, ty::ParamEnv::empty(), ty, sync_def_id, cause);
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { let errors = fulfillment_cx.select_all_or_error(&infcx);
infcx.report_fulfillment_errors(&err, None, false); if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
} }
}); });
} }

View file

@ -108,7 +108,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
let tcx = self.tcx; let tcx = self.tcx;
// Select everything, returning errors. // 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); debug!("true_errors = {:#?}", true_errors);
if !true_errors.is_empty() { if !true_errors.is_empty() {
@ -118,7 +118,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> {
} }
// Anything left unselected *now* must be an ambiguity. // 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); debug!("ambig_errors = {:#?}", ambig_errors);
let region_obligations = self.take_registered_region_obligations(); let region_obligations = self.take_registered_region_obligations();

View file

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

View file

@ -152,11 +152,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
}, },
cause, 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, // This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative // but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design). // by design).
debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", e); debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
return None; return None;
} }
let obligations = fulfillcx.pending_obligations(); let obligations = fulfillcx.pending_obligations();

View file

@ -187,9 +187,11 @@ impl<'tcx> AutoTraitFinder<'tcx> {
// an additional sanity check. // an additional sanity check.
let mut fulfill = FulfillmentContext::new(); let mut fulfill = FulfillmentContext::new();
fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy()); fulfill.register_bound(&infcx, full_env, ty, trait_did, ObligationCause::dummy());
fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { let errors = fulfill.select_all_or_error(&infcx);
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, e)
}); if !errors.is_empty() {
panic!("Unable to fulfill trait {:?} for '{:?}': {:?}", trait_did, ty, errors);
}
let body_id_map: FxHashMap<_, _> = infcx let body_id_map: FxHashMap<_, _> = infcx
.inner .inner

View file

@ -52,13 +52,17 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn select_all_or_error( fn select_all_or_error(
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Vec<FulfillmentError<'tcx>> {
self.select_where_possible(infcx)?; {
let errors = self.select_where_possible(infcx);
if self.obligations.is_empty() { if !errors.is_empty() {
Ok(()) return errors;
} else { }
let errors = self }
// any remaining obligations are errors
self
.obligations .obligations
.iter() .iter()
.map(|obligation| FulfillmentError { .map(|obligation| FulfillmentError {
@ -68,15 +72,13 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
// This is just for diagnostics, so it's okay if this is wrong // This is just for diagnostics, so it's okay if this is wrong
root_obligation: obligation.clone(), root_obligation: obligation.clone(),
}) })
.collect(); .collect()
Err(errors)
}
} }
fn select_where_possible( fn select_where_possible(
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Vec<FulfillmentError<'tcx>> {
assert!(!infcx.is_in_snapshot()); assert!(!infcx.is_in_snapshot());
let mut errors = Vec::new(); let mut errors = Vec::new();
@ -147,7 +149,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
} }
} }
if errors.is_empty() { Ok(()) } else { Err(errors) } errors
} }
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> { fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {

View file

@ -120,7 +120,8 @@ where
// In principle, we only need to do this so long as `result` // In principle, we only need to do this so long as `result`
// contains unbound type parameters. It could be a slight // contains unbound type parameters. It could be a slight
// optimization to stop iterating early. // 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( infcx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP, rustc_span::DUMMY_SP,
&format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),

View file

@ -129,7 +129,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
fn select( fn select(
&mut self, &mut self,
selcx: &mut SelectionContext<'a, 'tcx>, selcx: &mut SelectionContext<'a, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter(); let _enter = span.enter();
@ -163,7 +163,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
errors.len() errors.len()
); );
if errors.is_empty() { Ok(()) } else { Err(errors) } errors
} }
} }
@ -226,38 +226,46 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
fn select_all_or_error( fn select_all_or_error(
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Vec<FulfillmentError<'tcx>> {
self.select_where_possible(infcx)?; {
let errors = self.select_where_possible(infcx);
if !errors.is_empty() {
return errors;
}
}
let errors: Vec<_> = self self
.predicates .predicates
.to_errors(CodeAmbiguity) .to_errors(CodeAmbiguity)
.into_iter() .into_iter()
.map(to_fulfillment_error) .map(to_fulfillment_error)
.collect(); .collect()
if errors.is_empty() { Ok(()) } else { Err(errors) }
} }
fn select_all_with_constness_or_error( fn select_all_with_constness_or_error(
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
constness: rustc_hir::Constness, constness: rustc_hir::Constness,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Vec<FulfillmentError<'tcx>> {
self.select_with_constness_where_possible(infcx, constness)?; {
let errors = self.select_with_constness_where_possible(infcx, constness);
if !errors.is_empty() {
return errors;
}
}
let errors: Vec<_> = self self
.predicates .predicates
.to_errors(CodeAmbiguity) .to_errors(CodeAmbiguity)
.into_iter() .into_iter()
.map(to_fulfillment_error) .map(to_fulfillment_error)
.collect(); .collect()
if errors.is_empty() { Ok(()) } else { Err(errors) }
} }
fn select_where_possible( fn select_where_possible(
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::new(infcx); let mut selcx = SelectionContext::new(infcx);
self.select(&mut selcx) self.select(&mut selcx)
} }
@ -266,7 +274,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
&mut self, &mut self,
infcx: &InferCtxt<'_, 'tcx>, infcx: &InferCtxt<'_, 'tcx>,
constness: hir::Constness, constness: hir::Constness,
) -> Result<(), Vec<FulfillmentError<'tcx>>> { ) -> Vec<FulfillmentError<'tcx>> {
let mut selcx = SelectionContext::with_constness(infcx, constness); let mut selcx = SelectionContext::with_constness(infcx, constness);
self.select(&mut selcx) self.select(&mut selcx)
} }

View file

@ -180,8 +180,8 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
// Note: we only assume something is `Copy` if we can // Note: we only assume something is `Copy` if we can
// *definitively* show that it implements `Copy`. Otherwise, // *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok. // assume it is move; linear is always ok.
match fulfill_cx.select_all_or_error(infcx) { match fulfill_cx.select_all_or_error(infcx).as_slice() {
Ok(()) => { [] => {
debug!( debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success", "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
ty, ty,
@ -189,12 +189,12 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
); );
true true
} }
Err(e) => { errors => {
debug!( debug!(
"type_known_to_meet_bound_modulo_regions: ty={:?} bound={} errors={:?}", ?ty,
ty, bound = %infcx.tcx.def_path_str(def_id),
infcx.tcx.def_path_str(def_id), ?errors,
e "type_known_to_meet_bound_modulo_regions"
); );
false false
} }
@ -410,7 +410,10 @@ where
} }
debug!("fully_normalize: select_all_or_error start"); 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"); debug!("fully_normalize: select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value); let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
debug!("fully_normalize: resolved_value={:?}", resolved_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.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); debug!("impossible_predicates = {:?}", result);
result result

View file

@ -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())?; let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
fulfill_cx.register_predicate_obligations(infcx, obligations); 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( infcx.tcx.sess.diagnostic().delay_span_bug(
DUMMY_SP, DUMMY_SP,
&format!("errors selecting obligation during MIR typeck: {:?}", e), &format!("errors selecting obligation during MIR typeck: {:?}", errors),
); );
} }

View file

@ -225,8 +225,18 @@ fn fulfill_implication<'a, 'tcx>(
for oblig in obligations.chain(more_obligations) { for oblig in obligations.chain(more_obligations) {
fulfill_cx.register_predicate_obligation(&infcx, oblig); fulfill_cx.register_predicate_obligation(&infcx, oblig);
} }
match fulfill_cx.select_all_or_error(infcx) { match fulfill_cx.select_all_or_error(infcx).as_slice() {
Err(errors) => { [] => {
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! // no dice!
debug!( debug!(
"fulfill_implication: for impls on {:?} and {:?}, \ "fulfill_implication: for impls on {:?} and {:?}, \
@ -238,17 +248,6 @@ fn fulfill_implication<'a, 'tcx>(
); );
Err(()) 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))
}
} }
}) })
} }

View file

@ -103,7 +103,7 @@ fn type_marked_structural(
// //
// 2. We are sometimes doing future-incompatibility lints for // 2. We are sometimes doing future-incompatibility lints for
// now, so we do not want unconditional errors here. // 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 /// This implements the traversal over the structure of a given type to try to

View file

@ -128,9 +128,9 @@ fn compute_implied_outlives_bounds<'tcx>(
// Ensure that those obligations that we had to solve // Ensure that those obligations that we had to solve
// get solved *here*. // get solved *here*.
match fulfill_cx.select_all_or_error(infcx) { match fulfill_cx.select_all_or_error(infcx).as_slice() {
Ok(()) => Ok(implied_bounds), [] => Ok(implied_bounds),
Err(_) => Err(NoSolution), _ => Err(NoSolution),
} }
} }

View file

@ -663,8 +663,9 @@ fn check_opaque_meets_bounds<'tcx>(
// Check that all obligations are satisfied by the implementation's // Check that all obligations are satisfied by the implementation's
// version. // version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
infcx.report_fulfillment_errors(errors, None, false); if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
} }
// Finally, resolve all regions. This catches wily misuses of // Finally, resolve all regions. This catches wily misuses of

View file

@ -950,7 +950,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}; };
let mut fcx = traits::FulfillmentContext::new_in_snapshot(); let mut fcx = traits::FulfillmentContext::new_in_snapshot();
fcx.register_predicate_obligations(self, ok.obligations); fcx.register_predicate_obligations(self, ok.obligations);
fcx.select_where_possible(&self).is_ok() fcx.select_where_possible(&self).is_empty()
}) })
} }

View file

@ -391,8 +391,9 @@ fn compare_predicate_entailment<'tcx>(
// Check that all obligations are satisfied by the implementation's // Check that all obligations are satisfied by the implementation's
// version. // version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
infcx.report_fulfillment_errors(errors, None, false); if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported); return Err(ErrorReported);
} }
@ -1094,8 +1095,9 @@ crate fn compare_const_impl<'tcx>(
// Check that all obligations are satisfied by the implementation's // Check that all obligations are satisfied by the implementation's
// version. // version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
infcx.report_fulfillment_errors(errors, None, false); if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return; return;
} }
@ -1210,8 +1212,9 @@ fn compare_type_predicate_entailment<'tcx>(
// Check that all obligations are satisfied by the implementation's // Check that all obligations are satisfied by the implementation's
// version. // version.
if let Err(ref errors) = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { let errors = inh.fulfillment_cx.borrow_mut().select_all_or_error(&infcx);
infcx.report_fulfillment_errors(errors, None, false); if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
return Err(ErrorReported); return Err(ErrorReported);
} }
@ -1427,10 +1430,9 @@ pub fn check_type_bounds<'tcx>(
// Check that all obligations are satisfied by the implementation's // Check that all obligations are satisfied by the implementation's
// version. // version.
if let Err(ref errors) = let errors = inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness);
inh.fulfillment_cx.borrow_mut().select_all_with_constness_or_error(&infcx, constness) if !errors.is_empty() {
{ infcx.report_fulfillment_errors(&errors, None, false);
infcx.report_fulfillment_errors(errors, None, false);
return Err(ErrorReported); return Err(ErrorReported);
} }

View file

@ -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 // 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); return Err(ErrorReported);
} }

View file

@ -642,11 +642,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
pub(in super::super) fn select_all_obligations_or_error(&self) { pub(in super::super) fn select_all_obligations_or_error(&self) {
if let Err(errors) = self let errors =self
.fulfillment_cx .fulfillment_cx
.borrow_mut() .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); self.report_fulfillment_errors(&errors, self.inh.body_id, false);
} }
} }
@ -657,13 +658,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fallback_has_occurred: bool, fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>), mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) { ) {
let result = self let mut result = self
.fulfillment_cx .fulfillment_cx
.borrow_mut() .borrow_mut()
.select_with_constness_where_possible(self, self.inh.constness); .select_with_constness_where_possible(self, self.inh.constness);
if let Err(mut errors) = result { if !result.is_empty() {
mutate_fulfillment_errors(&mut errors); mutate_fulfillment_errors(&mut result);
self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); 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 // we can. We don't care if some things turn
// out unconstrained or ambiguous, as we're // out unconstrained or ambiguous, as we're
// just trying to get hints here. // 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); let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
for obligation in ok.obligations { for obligation in ok.obligations {
fulfill.register_predicate_obligation(self, obligation); fulfill.register_predicate_obligation(self, obligation);
} }
fulfill.select_where_possible(self) fulfill.select_where_possible(self)
}) });
.map_err(|_| ())?;
if !errors.is_empty() {
return Err(());
}
} }
Err(_) => return Err(()), Err(_) => return Err(()),
} }

View file

@ -826,10 +826,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys)); self.obligation_for_method(span, trait_did, lhs_ty, Some(other_tys));
let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx); let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
fulfill.register_predicate_obligation(self, obligation); fulfill.register_predicate_obligation(self, obligation);
Err(match fulfill.select_where_possible(&self.infcx) { Err(fulfill.select_where_possible(&self.infcx))
Err(errors) => errors,
_ => vec![],
})
} }
} }
} }

View file

@ -263,7 +263,8 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
} }
// Check that all transitive obligations are satisfied. // 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); 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); fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied. // 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); infcx.report_fulfillment_errors(&errors, None, false);
} }

View file

@ -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); tracing::debug!("Wf-check got errors for {:?}: {:?}", ty, errors);
for error in errors { for error in errors {
if error.obligation.predicate == self.predicate { if error.obligation.predicate == self.predicate {

View file

@ -157,10 +157,10 @@ fn require_same_types<'tcx>(
} }
} }
match fulfill_cx.select_all_or_error(infcx) { match fulfill_cx.select_all_or_error(infcx).as_slice() {
Ok(()) => true, [] => true,
Err(errors) => { errors => {
infcx.report_fulfillment_errors(&errors, None, false); infcx.report_fulfillment_errors(errors, None, false);
false false
} }
} }
@ -352,8 +352,9 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
term_id, term_id,
cause, cause,
); );
if let Err(err) = fulfillment_cx.select_all_or_error(&infcx) { let errors = fulfillment_cx.select_all_or_error(&infcx);
infcx.report_fulfillment_errors(&err, None, false); if !errors.is_empty() {
infcx.report_fulfillment_errors(&errors, None, false);
error = true; error = true;
} }
}); });

View file

@ -83,7 +83,8 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
// variables. Process these constraints. // variables. Process these constraints.
let mut fulfill_cx = FulfillmentContext::new(); let mut fulfill_cx = FulfillmentContext::new();
fulfill_cx.register_predicate_obligations(self, result.obligations); 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( self.tcx.sess.delay_span_bug(
span, span,
"implied_outlives_bounds failed to solve obligations from instantiation", "implied_outlives_bounds failed to solve obligations from instantiation",

View file

@ -77,13 +77,13 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
if is_future { if is_future {
let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap(); let send_trait = cx.tcx.get_diagnostic_item(sym::Send).unwrap();
let span = decl.output.span(); 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 cause = traits::ObligationCause::misc(span, hir_id);
let mut fulfillment_cx = traits::FulfillmentContext::new(); let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause); fulfillment_cx.register_bound(&infcx, cx.param_env, ret_ty, send_trait, cause);
fulfillment_cx.select_all_or_error(&infcx) fulfillment_cx.select_all_or_error(&infcx)
}); });
if let Err(send_errors) = send_result { if !send_errors.is_empty() {
span_lint_and_then( span_lint_and_then(
cx, cx,
FUTURE_NOT_SEND, FUTURE_NOT_SEND,