// 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);
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);
}
});
}
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() {
}
// 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();
fn select_all_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'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>>>;
+ ) -> 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)
}
},
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();
// 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
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)
+ ) -> 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();
}
}
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
// 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),
fn select(
&mut self,
selcx: &mut SelectionContext<'a, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
+ ) -> Vec<FulfillmentError<'tcx>> {
let span = debug_span!("select", obligation_forest_size = ?self.predicates.len());
let _enter = span.enter();
errors.len()
);
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ errors
}
}
fn select_all_or_error(
&mut self,
infcx: &InferCtxt<'_, 'tcx>,
- ) -> Result<(), Vec<FulfillmentError<'tcx>>> {
- self.select_where_possible(infcx)?;
+ ) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_where_possible(infcx);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
- let errors: Vec<_> = self
+ self
.predicates
.to_errors(CodeAmbiguity)
.into_iter()
.map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ .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)?;
+ ) -> Vec<FulfillmentError<'tcx>> {
+ {
+ let errors = self.select_with_constness_where_possible(infcx, constness);
+ if !errors.is_empty() {
+ return errors;
+ }
+ }
- let errors: Vec<_> = self
+ self
.predicates
.to_errors(CodeAmbiguity)
.into_iter()
.map(to_fulfillment_error)
- .collect();
- if errors.is_empty() { Ok(()) } else { Err(errors) }
+ .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)
}
&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)
}
// 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,
);
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
}
}
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);
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
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),
);
}
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 {:?}, \
);
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))
- }
}
})
}
//
// 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
// 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),
}
}
// 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
};
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()
})
}
// 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);
}
// 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;
}
// 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);
}
// 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);
}
}
}
- 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);
}
#[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);
}
}
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);
}
}
// 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(()),
}
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))
}
}
}
}
// 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);
}
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);
}
),
);
- 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 {
}
}
- 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
}
}
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;
}
});
// 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",
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,