Don't throw away information just to recompute it again

This commit is contained in:
Oli Scherer 2022-09-08 15:18:43 +00:00
parent 00fcc82df2
commit 8aed75bee0
3 changed files with 22 additions and 26 deletions

View File

@ -1022,7 +1022,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
predicate: ty::PolyCoercePredicate<'tcx>, predicate: ty::PolyCoercePredicate<'tcx>,
) -> Option<InferResult<'tcx, ()>> { ) -> Result<InferResult<'tcx, ()>, (TyVid, TyVid)> {
let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate { let subtype_predicate = predicate.map_bound(|p| ty::SubtypePredicate {
a_is_expected: false, // when coercing from `a` to `b`, `b` is expected a_is_expected: false, // when coercing from `a` to `b`, `b` is expected
a: p.a, a: p.a,
@ -1036,7 +1036,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
cause: &ObligationCause<'tcx>, cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
predicate: ty::PolySubtypePredicate<'tcx>, predicate: ty::PolySubtypePredicate<'tcx>,
) -> Option<InferResult<'tcx, ()>> { ) -> Result<InferResult<'tcx, ()>, (TyVid, TyVid)> {
// Check for two unresolved inference variables, in which case we can // Check for two unresolved inference variables, in which case we can
// make no progress. This is partly a micro-optimization, but it's // make no progress. This is partly a micro-optimization, but it's
// also an opportunity to "sub-unify" the variables. This isn't // also an opportunity to "sub-unify" the variables. This isn't
@ -1055,12 +1055,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
match (r_a.kind(), r_b.kind()) { match (r_a.kind(), r_b.kind()) {
(&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => { (&ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid))) => {
self.inner.borrow_mut().type_variables().sub(a_vid, b_vid); self.inner.borrow_mut().type_variables().sub(a_vid, b_vid);
return None; return Err((a_vid, b_vid));
} }
_ => {} _ => {}
} }
Some(self.commit_if_ok(|_snapshot| { Ok(self.commit_if_ok(|_snapshot| {
let ty::SubtypePredicate { a_is_expected, a, b } = let ty::SubtypePredicate { a_is_expected, a, b } =
self.replace_bound_vars_with_placeholders(predicate); self.replace_bound_vars_with_placeholders(predicate);
@ -1848,7 +1848,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
/// Tries to extract an inference variable from a type, returns `None` /// Tries to extract an inference variable from a type, returns `None`
/// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`). /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`).
pub fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> { fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> {
match *ty.kind() { match *ty.kind() {
ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)),
ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)),
@ -1859,7 +1859,7 @@ impl<'tcx> TyOrConstInferVar<'tcx> {
/// Tries to extract an inference variable from a constant, returns `None` /// Tries to extract an inference variable from a constant, returns `None`
/// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`). /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> { fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
match ct.kind() { match ct.kind() {
ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)), ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
_ => None, _ => None,

View File

@ -427,16 +427,14 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
obligation.param_env, obligation.param_env,
Binder::dummy(subtype), Binder::dummy(subtype),
) { ) {
None => { Err((a, b)) => {
// None means that both are unresolved. // None means that both are unresolved.
pending_obligation.stalled_on = vec![ pending_obligation.stalled_on =
TyOrConstInferVar::maybe_from_ty(subtype.a).unwrap(), vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
TyOrConstInferVar::maybe_from_ty(subtype.b).unwrap(),
];
ProcessResult::Unchanged ProcessResult::Unchanged
} }
Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
Some(Err(err)) => { Ok(Err(err)) => {
let expected_found = let expected_found =
ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b); ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
@ -453,16 +451,14 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
obligation.param_env, obligation.param_env,
Binder::dummy(coerce), Binder::dummy(coerce),
) { ) {
None => { Err((a, b)) => {
// None means that both are unresolved. // None means that both are unresolved.
pending_obligation.stalled_on = vec![ pending_obligation.stalled_on =
TyOrConstInferVar::maybe_from_ty(coerce.a).unwrap(), vec![TyOrConstInferVar::Ty(a), TyOrConstInferVar::Ty(b)];
TyOrConstInferVar::maybe_from_ty(coerce.b).unwrap(),
];
ProcessResult::Unchanged ProcessResult::Unchanged
} }
Some(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)), Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
Some(Err(err)) => { Ok(Err(err)) => {
let expected_found = ExpectedFound::new(false, coerce.a, coerce.b); let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError( ProcessResult::Error(FulfillmentErrorCode::CodeSubtypeError(
expected_found, expected_found,

View File

@ -462,15 +462,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let p = bound_predicate.rebind(p); let p = bound_predicate.rebind(p);
// Does this code ever run? // Does this code ever run?
match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) {
Some(Ok(InferOk { mut obligations, .. })) => { Ok(Ok(InferOk { mut obligations, .. })) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
self.evaluate_predicates_recursively( self.evaluate_predicates_recursively(
previous_stack, previous_stack,
obligations.into_iter(), obligations.into_iter(),
) )
} }
Some(Err(_)) => Ok(EvaluatedToErr), Ok(Err(_)) => Ok(EvaluatedToErr),
None => Ok(EvaluatedToAmbig), Err(..) => Ok(EvaluatedToAmbig),
} }
} }
@ -478,15 +478,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let p = bound_predicate.rebind(p); let p = bound_predicate.rebind(p);
// Does this code ever run? // Does this code ever run?
match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) { match self.infcx.coerce_predicate(&obligation.cause, obligation.param_env, p) {
Some(Ok(InferOk { mut obligations, .. })) => { Ok(Ok(InferOk { mut obligations, .. })) => {
self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.add_depth(obligations.iter_mut(), obligation.recursion_depth);
self.evaluate_predicates_recursively( self.evaluate_predicates_recursively(
previous_stack, previous_stack,
obligations.into_iter(), obligations.into_iter(),
) )
} }
Some(Err(_)) => Ok(EvaluatedToErr), Ok(Err(_)) => Ok(EvaluatedToErr),
None => Ok(EvaluatedToAmbig), Err(..) => Ok(EvaluatedToAmbig),
} }
} }