Make select_* methods return Vec for TraitEngine
This commit is contained in:
parent
b3074819f6
commit
f1126f1272
25 changed files with 147 additions and 117 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -52,31 +52,33 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
|||
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 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)
|
||||
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 +149,7 @@ impl TraitEngine<'tcx> for FulfillmentContext<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
if errors.is_empty() { Ok(()) } else { Err(errors) }
|
||||
errors
|
||||
}
|
||||
|
||||
fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>> {
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -129,7 +129,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
|
|||
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();
|
||||
|
||||
|
@ -163,7 +163,7 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> {
|
|||
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(
|
||||
&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)
|
||||
}
|
||||
|
@ -266,7 +274,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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
// *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,
|
||||
|
@ -189,12 +189,12 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
|
|||
);
|
||||
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
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue