Skip to content
Closed
Show file tree
Hide file tree
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
47 changes: 33 additions & 14 deletions compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(from_trait) = self.tcx.lang_items().from_trait() else {
return UnordSet::new();
};
let obligations = self.fulfillment_cx.borrow().pending_obligations();
let obligations = self
.fulfillment_cx
.borrow()
.pending_obligations_potentially_referencing_float_infer(self);
debug!(?obligations);
let mut vids = UnordSet::new();
for obligation in obligations {
Expand All @@ -209,6 +212,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}

/// Using an intentionally low depth to minimize the chance of future
/// breaking changes in case we adapt the approach later on. This also
/// avoids any hangs for exponentially growing proof trees.
const MAX_DEPTH_FOR_OBLIGATIONS_VISITORS: usize = 5;

struct NestedObligationsForSelfTy<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
self_ty: ty::TyVid,
Expand All @@ -223,10 +231,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'_, 'tcx> {
}

fn config(&self) -> InspectConfig {
// Using an intentionally low depth to minimize the chance of future
// breaking changes in case we adapt the approach later on. This also
// avoids any hangs for exponentially growing proof trees.
InspectConfig { max_depth: 5 }
InspectConfig { max_depth: MAX_DEPTH_FOR_OBLIGATIONS_VISITORS }
}

fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
Expand Down Expand Up @@ -282,23 +287,37 @@ impl<'tcx> ProofTreeVisitor<'tcx> for FindFromFloatForF32RootVids<'_, 'tcx> {
}

fn config(&self) -> InspectConfig {
// Avoid hang from exponentially growing proof trees (see `cycle-modulo-ambig-aliases.rs`).
// 3 is more than enough for all occurrences in practice (a.k.a. `Into`).
InspectConfig { max_depth: 3 }
InspectConfig { max_depth: MAX_DEPTH_FOR_OBLIGATIONS_VISITORS }
}

fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
// No need to walk into goal subtrees that certainly hold, since they
// wouldn't then be stalled on an infer var.
if inspect_goal.result() == Ok(Certainty::Yes) {
return;
}

// We don't care about any pending goals which don't actually
// use any float infer var.
if !inspect_goal
.orig_values()
.iter()
.filter_map(|arg| arg.as_type())
.any(|ty| matches!(self.fcx.shallow_resolve(ty).kind(), ty::Infer(ty::FloatVar(_))))
{
debug!(goal = ?inspect_goal.goal(), "goal does not mention float infer var");
return;
}

if let Some(vid) = self
.fcx
.predicate_from_float_for_f32_root_vid(self.from_trait, inspect_goal.goal().predicate)
{
self.vids.insert(vid);
} else if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
let start_len = self.vids.len();
let _ = candidate.goal().infcx().commit_if_ok(|_| {
candidate.visit_nested_no_probe(self);
if self.vids.len() > start_len { Ok(()) } else { Err(()) }
});
}

if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
candidate.visit_nested_no_probe(self);
}
}
}
11 changes: 11 additions & 0 deletions compiler/rustc_infer/src/traits/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,17 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx {
self.pending_obligations()
}

/// Pending obligations potentially referencing float inference variables.
///
/// FIXME: use a generic filter for `pending_obligations_potentially_referencing_sub_root`
/// and this after `TraitEngine` doesn't need to be dyn compatible.
fn pending_obligations_potentially_referencing_float_infer(
&self,
_infcx: &InferCtxt<'tcx>,
) -> PredicateObligations<'tcx> {
self.pending_obligations()
}

/// Among all pending obligations, collect those are stalled on a inference variable which has
/// changed since the last call to `try_evaluate_obligations`. Those obligations are marked as
/// successful and returned.
Expand Down
32 changes: 12 additions & 20 deletions compiler/rustc_mir_dataflow/src/framework/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,28 +195,20 @@ where
debug_assert_eq!(target.block, self.pos.block);

let block_data = &self.body[target.block];
#[rustfmt::skip]
let next_effect = if A::Direction::IS_FORWARD {
self.pos.curr_effect_index.map_or_else(
|| Effect::Early.at_index(0),
EffectIndex::next_in_forward_order,
)
} else {
self.pos.curr_effect_index.map_or_else(
|| Effect::Early.at_index(block_data.statements.len()),
EffectIndex::next_in_backward_order,
)
};

let next_effect = self.pos.curr_effect_index.map_or_else(
|| A::Direction::first_index(block_data),
|idx| A::Direction::next_index(idx),
);
let target_effect_index = effect.at_index(target.statement_index);

A::Direction::apply_effects_in_range(
&self.results.analysis,
&mut self.state,
target.block,
block_data,
next_effect..=target_effect_index,
);
let mut idx = next_effect;
loop {
self.results.analysis.apply_effect(&mut self.state, target.block, block_data, idx);
if idx == target_effect_index {
break;
}
idx = A::Direction::next_index(idx);
}

self.pos =
CursorPosition { block: target.block, curr_effect_index: Some(target_effect_index) };
Expand Down
Loading
Loading