Skip to content
Open
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
5 changes: 4 additions & 1 deletion compiler/rustc_borrowck/src/type_check/canonical.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
locations,
category,
param_env.and(type_op::prove_predicate::ProvePredicate { predicate }),
param_env.and(type_op::prove_predicate::ProvePredicate {
predicate,
body_id: self.infcx.root_def_id,
}),
);
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/traits/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::ty::{self, GenericArg, Ty, TyCtxt};

pub mod type_op {
use rustc_macros::{StableHash, TypeFoldable, TypeVisitable};
use rustc_span::def_id::LocalDefId;

use crate::ty::{Predicate, Ty, UserType};

Expand All @@ -40,6 +41,7 @@ pub mod type_op {
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, StableHash, TypeFoldable, TypeVisitable)]
pub struct ProvePredicate<'tcx> {
pub predicate: Predicate<'tcx>,
pub body_id: LocalDefId,
}

/// Normalizes, but not in the new solver.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_next_trait_solver/src/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,6 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
src: <Self::Interner as Interner>::Ty,
dst: <Self::Interner as Interner>::Ty,
assume: <Self::Interner as Interner>::Const,
body_id: Option<<Self::Interner as Interner>::LocalDefId>,
) -> Result<Certainty, NoSolution>;
}
32 changes: 19 additions & 13 deletions compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ where
nested_goals: Vec<(GoalSource, Goal<I, I::Predicate>, Option<GoalStalledOn<I>>)>,

pub(super) origin_span: I::Span,
root_body_id: Option<I::LocalDefId>,

@lcnr lcnr Jun 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is quite concerning. This either entirely wrecks caching or is easily unsound wrt to incremental

What do you need this for?

View changes since the review


// Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`?
//
Expand Down Expand Up @@ -168,6 +169,7 @@ pub trait SolverDelegateEvalExt: SolverDelegate {
&self,
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
span: <Self::Interner as Interner>::Span,
body_id: Option<<Self::Interner as Interner>::LocalDefId>,
stalled_on: Option<GoalStalledOn<Self::Interner>>,
) -> Result<GoalEvaluation<Self::Interner>, NoSolution>;

Expand Down Expand Up @@ -215,11 +217,13 @@ where
&self,
goal: Goal<I, I::Predicate>,
span: I::Span,
body_id: Option<I::LocalDefId>,
stalled_on: Option<GoalStalledOn<I>>,
) -> Result<GoalEvaluation<I>, NoSolution> {
let result = EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, |ecx| {
ecx.evaluate_goal(GoalSource::Misc, goal, stalled_on)
});
let result =
EvalCtxt::enter_root(self, self.cx().recursion_limit(), span, body_id, |ecx| {
ecx.evaluate_goal(GoalSource::Misc, goal, stalled_on)
});

match result {
Ok(i) => Ok(i),
Expand All @@ -236,7 +240,7 @@ where
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
) -> bool {
self.probe(|| {
EvalCtxt::enter_root(self, self.cx().recursion_limit(), I::Span::dummy(), |ecx| {
EvalCtxt::enter_root(self, self.cx().recursion_limit(), I::Span::dummy(), None, |ecx| {
ecx.evaluate_goal(GoalSource::Misc, goal, None)
})
.is_ok_and(|r| match r.certainty {
Expand All @@ -259,7 +263,7 @@ where
goal: Goal<Self::Interner, <Self::Interner as Interner>::Predicate>,
) -> bool {
self.probe(|| {
EvalCtxt::enter_root(self, root_depth, I::Span::dummy(), |ecx| {
EvalCtxt::enter_root(self, root_depth, I::Span::dummy(), None, |ecx| {
ecx.evaluate_goal(GoalSource::Misc, goal, None)
})
})
Expand Down Expand Up @@ -339,6 +343,7 @@ where
delegate: &D,
root_depth: usize,
origin_span: I::Span,
root_body_id: Option<I::LocalDefId>,
f: impl FnOnce(&mut EvalCtxt<'_, D>) -> R,
) -> R {
let mut search_graph = SearchGraph::new(root_depth);
Expand All @@ -357,6 +362,7 @@ where
var_values: CanonicalVarValues::dummy(),
current_goal_kind: CurrentGoalKind::Misc,
origin_span,
root_body_id,
tainted: Ok(()),
opaque_accesses: AccessedOpaques::default(),
};
Expand All @@ -382,6 +388,7 @@ where
search_graph: &'a mut SearchGraph<D>,
canonical_input: CanonicalInput<I>,
proof_tree_builder: &mut inspect::ProofTreeBuilder<D>,
root_body_id: Option<I::LocalDefId>,
f: impl FnOnce(
&mut EvalCtxt<'_, D>,
Goal<I, I::Predicate>,
Expand Down Expand Up @@ -421,6 +428,7 @@ where
search_graph,
nested_goals: Default::default(),
origin_span: I::Span::dummy(),
root_body_id,
tainted: Ok(()),
inspect: proof_tree_builder.new_evaluation_step(var_values),
opaque_accesses: AccessedOpaques::default(),
Expand Down Expand Up @@ -572,11 +580,12 @@ where
TypingMode::ErasedNotCoherence(MayBeErased),
);

let mut inspect = inspect::ProofTreeBuilder::new_noop(self.root_body_id);
let (canonical_result, accessed_opaques) = self.search_graph.evaluate_goal(
self.cx(),
canonical_goal,
step_kind,
&mut inspect::ProofTreeBuilder::new_noop(),
&mut inspect,
);

let should_rerun = self.should_rerun_after_erased_canonicalization(
Expand All @@ -599,12 +608,9 @@ where
let (orig_values, canonical_goal) =
canonicalize_goal(self.delegate, goal, &opaque_types, typing_mode);

let (canonical_result, accessed_opaques) = self.search_graph.evaluate_goal(
self.cx(),
canonical_goal,
step_kind,
&mut inspect::ProofTreeBuilder::new_noop(),
);
let mut inspect = inspect::ProofTreeBuilder::new_noop(self.root_body_id);
let (canonical_result, accessed_opaques) =
self.search_graph.evaluate_goal(self.cx(), canonical_goal, step_kind, &mut inspect);
assert!(
!accessed_opaques.might_rerun(),
"we run without TypingMode::ErasedNotCoherence, so opaques are available, and we don't retry if the outer typing mode is ErasedNotCoherence: {accessed_opaques:?} after {goal:?}"
Expand Down Expand Up @@ -1516,7 +1522,7 @@ where
dst: I::Ty,
assume: I::Const,
) -> Result<Certainty, NoSolution> {
self.delegate.is_transmutable(dst, src, assume)
self.delegate.is_transmutable(dst, src, assume, self.root_body_id)
}

pub(super) fn replace_bound_vars<T: TypeFoldable<I>>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ where
search_graph: outer.search_graph,
nested_goals: propagated_nested_goals,
origin_span: outer.origin_span,
root_body_id: outer.root_body_id,
tainted: outer.tainted,
inspect: outer.inspect.take_and_enter_probe(),
opaque_accesses: AccessedOpaques::default(),
Expand Down
11 changes: 8 additions & 3 deletions compiler/rustc_next_trait_solver/src/solve/inspect/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,27 @@ where
I: Interner,
{
state: Option<Box<Option<inspect::Probe<I>>>>,
root_body_id: Option<I::LocalDefId>,
_infcx: PhantomData<D>,
}

impl<D: SolverDelegate<Interner = I>, I: Interner> ProofTreeBuilder<D> {
pub(crate) fn new() -> ProofTreeBuilder<D> {
ProofTreeBuilder { state: Some(Box::new(None)), _infcx: PhantomData }
ProofTreeBuilder { state: Some(Box::new(None)), root_body_id: None, _infcx: PhantomData }
}

pub(crate) fn new_noop() -> ProofTreeBuilder<D> {
ProofTreeBuilder { state: None, _infcx: PhantomData }
pub(crate) fn new_noop(root_body_id: Option<I::LocalDefId>) -> ProofTreeBuilder<D> {
ProofTreeBuilder { state: None, root_body_id, _infcx: PhantomData }
}

pub(crate) fn is_noop(&self) -> bool {
self.state.is_none()
}

pub(crate) fn root_body_id(&self) -> Option<I::LocalDefId> {
self.root_body_id
}

pub(crate) fn new_evaluation_step(
&mut self,
var_values: ty::CanonicalVarValues<I>,
Expand Down
40 changes: 24 additions & 16 deletions compiler/rustc_next_trait_solver/src/solve/search_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,22 +140,30 @@ where
inspect: &mut Self::ProofTreeBuilder,
) -> (QueryResult<I>, AccessedOpaques<I>) {
ensure_sufficient_stack(|| {
EvalCtxt::enter_canonical(cx, search_graph, input, inspect, |ecx, goal| {
let result = ecx.compute_goal(goal);

// if we're in `RerunNonErased`, don't even bother with inspect,
// and immediately return
let result = match result {
Ok(i) => Ok(i),
Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution),
Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => {
return Err(e.into());
}
};

ecx.inspect.query_result(result);
result.map_err(Into::into)
})
let root_body_id = inspect.root_body_id();
EvalCtxt::enter_canonical(
cx,
search_graph,
input,
inspect,
root_body_id,
|ecx, goal| {
let result = ecx.compute_goal(goal);

// if we're in `RerunNonErased`, don't even bother with inspect,
// and immediately return
let result = match result {
Ok(i) => Ok(i),
Err(NoSolutionOrRerunNonErased::NoSolution(NoSolution)) => Err(NoSolution),
Err(NoSolutionOrRerunNonErased::RerunNonErased(e)) => {
return Err(e.into());
}
};

ecx.inspect.query_result(result);
result.map_err(Into::into)
},
)
})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2927,8 +2927,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
return (obligation.clone(), trait_predicate);
};

let caller_module = self.tcx.parent_module_from_def_id(obligation.cause.body_id);
let is_normalized_yes = matches!(
rustc_transmute::TransmuteTypeEnv::new(self.tcx).is_transmutable(
rustc_transmute::TransmuteTypeEnv::new(self.tcx, caller_module).is_transmutable(
trait_ref.args.type_at(1),
trait_ref.args.type_at(0),
assume,
Expand Down Expand Up @@ -2985,8 +2986,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let dst = trait_pred.trait_ref.args.type_at(0);
let src = trait_pred.trait_ref.args.type_at(1);
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
let caller_module = self.tcx.parent_module_from_def_id(obligation.cause.body_id);

match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx)
match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx, caller_module)
.is_transmutable(src, dst, assume)
{
Answer::No(reason) => {
Expand Down
11 changes: 9 additions & 2 deletions compiler/rustc_trait_selection/src/solve/delegate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::ops::Deref;

use rustc_data_structures::fx::FxHashMap;
use rustc_hir::LangItem;
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId};
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::canonical::{
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarKind, CanonicalVarValues,
Expand Down Expand Up @@ -365,6 +365,7 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
src: Ty<'tcx>,
dst: Ty<'tcx>,
assume: ty::Const<'tcx>,
body_id: Option<LocalDefId>,
) -> Result<Certainty, NoSolution> {
// Erase regions because we compute layouts in `rustc_transmute`,
// which will ICE for region vars.
Expand All @@ -374,8 +375,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
return Err(NoSolution);
};

let caller_module = body_id
.map(|body_id| self.tcx.parent_module_from_def_id(body_id))
.unwrap_or(LocalModDefId::CRATE_DEF_ID);

// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx).is_transmutable(src, dst, assume) {
match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx, caller_module)
.is_transmutable(src, dst, assume)
{
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
}
Expand Down
8 changes: 7 additions & 1 deletion compiler/rustc_trait_selection/src/solve/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ impl<'tcx> ObligationStorage<'tcx> {
let result = <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
goal,
o.cause.span,
Some(o.cause.body_id),
stalled_on.take(),
);
matches!(result, Ok(GoalEvaluation { has_changed: HasChanged::Yes, .. }))
Expand Down Expand Up @@ -205,7 +206,12 @@ where
continue;
}

let result = delegate.evaluate_root_goal(goal, obligation.cause.span, stalled_on);
let result = delegate.evaluate_root_goal(
goal,
obligation.cause.span,
Some(obligation.cause.body_id),
stalled_on,
);
self.inspect_evaluated_obligation(infcx, &obligation, &result);
let GoalEvaluation { goal, certainty, has_changed, stalled_on } = match result {
Ok(result) => result,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>(
match <&SolverDelegate<'tcx>>::from(infcx).evaluate_root_goal(
root_obligation.as_goal(),
root_obligation.cause.span,
Some(root_obligation.cause.body_id),
None,
) {
Ok(GoalEvaluation {
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_trait_selection/src/solve/normalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ where
ty::AliasRelationDirection::Equate,
);
let goal = Goal::new(infcx.tcx, at.param_env, predicate);
let result = delegate.evaluate_root_goal(goal, at.cause.span, None)?;
let result =
delegate.evaluate_root_goal(goal, at.cause.span, Some(at.cause.body_id), None)?;
let normalized = infcx.resolve_vars_if_possible(infer_term);
let stalled_goal = match result.certainty {
Certainty::Yes => None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
) -> Result<Self::QueryResponse, NoSolution> {
ocx.register_obligation(Obligation::new(
ocx.infcx.tcx,
ObligationCause::dummy_with_span(span),
ObligationCause::misc(span, key.value.body_id),
key.param_env,
key.value.predicate,
));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let src = predicate.trait_ref.args.type_at(1);

debug!(?src, ?dst);
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx);
let caller_module = self.tcx().parent_module_from_def_id(obligation.cause.body_id);
let mut transmute_env =
rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx, caller_module);
let maybe_transmutable = transmute_env.is_transmutable(src, dst, assume);

let fully_flattened = match maybe_transmutable {
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_traits/src/type_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ fn type_op_prove_predicate<'tcx>(
pub fn type_op_prove_predicate_with_cause<'tcx>(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
cause: ObligationCause<'tcx>,
mut cause: ObligationCause<'tcx>,
) {
let ParamEnvAnd { param_env, value: ProvePredicate { predicate } } = key;
let ParamEnvAnd { param_env, value: ProvePredicate { predicate, body_id } } = key;
cause.body_id = body_id;
ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
}
16 changes: 9 additions & 7 deletions compiler/rustc_transmute/src/layout/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,18 +139,20 @@ pub mod rustc {
/// A visibility node in the layout.
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
pub enum Def<'tcx> {
Adt(ty::AdtDef<'tcx>),
Variant(&'tcx ty::VariantDef),
Field(&'tcx ty::FieldDef),
Adt(ty::AdtDef<'tcx>, bool),
Variant(&'tcx ty::VariantDef, bool),
Field(&'tcx ty::FieldDef, bool),
Primitive,
}

impl<'tcx> super::Def for Def<'tcx> {
fn has_safety_invariants(&self) -> bool {
// Rust presently has no notion of 'unsafe fields', so for now we
// make the conservative assumption that everything besides
// primitive types carry safety invariants.
self != &Self::Primitive
match self {
Self::Adt(_, has_safety_invariants)
| Self::Variant(_, has_safety_invariants)
| Self::Field(_, has_safety_invariants) => *has_safety_invariants,
Self::Primitive => false,
}
}
}

Expand Down
Loading
Loading