Support safe transmute in new solver
This commit is contained in:
parent
2a198c7f62
commit
d92f74e43b
5 changed files with 67 additions and 0 deletions
|
@ -83,6 +83,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
|
||||||
| TypeFlags::HAS_CT_PLACEHOLDER,
|
| TypeFlags::HAS_CT_PLACEHOLDER,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
fn has_non_region_placeholders(&self) -> bool {
|
||||||
|
self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
|
||||||
|
}
|
||||||
fn needs_subst(&self) -> bool {
|
fn needs_subst(&self) -> bool {
|
||||||
self.has_type_flags(TypeFlags::NEEDS_SUBST)
|
self.has_type_flags(TypeFlags::NEEDS_SUBST)
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
|
||||||
ecx: &mut EvalCtxt<'_, 'tcx>,
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
goal: Goal<'tcx, Self>,
|
goal: Goal<'tcx, Self>,
|
||||||
) -> QueryResult<'tcx>;
|
) -> QueryResult<'tcx>;
|
||||||
|
|
||||||
|
fn consider_builtin_transmute_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
@ -373,6 +378,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
G::consider_builtin_discriminant_kind_candidate(self, goal)
|
G::consider_builtin_discriminant_kind_candidate(self, goal)
|
||||||
} else if lang_items.destruct_trait() == Some(trait_def_id) {
|
} else if lang_items.destruct_trait() == Some(trait_def_id) {
|
||||||
G::consider_builtin_destruct_candidate(self, goal)
|
G::consider_builtin_destruct_candidate(self, goal)
|
||||||
|
} else if lang_items.transmute_trait() == Some(trait_def_id) {
|
||||||
|
G::consider_builtin_transmute_candidate(self, goal)
|
||||||
} else {
|
} else {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
};
|
};
|
||||||
|
|
|
@ -639,4 +639,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
|
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
|
||||||
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
|
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn is_transmutable(
|
||||||
|
&self,
|
||||||
|
src_and_dst: rustc_transmute::Types<'tcx>,
|
||||||
|
scope: Ty<'tcx>,
|
||||||
|
assume: rustc_transmute::Assume,
|
||||||
|
) -> Result<Certainty, NoSolution> {
|
||||||
|
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
|
||||||
|
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||||
|
ObligationCause::dummy(),
|
||||||
|
ty::Binder::dummy(src_and_dst),
|
||||||
|
scope,
|
||||||
|
assume,
|
||||||
|
) {
|
||||||
|
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
|
||||||
|
rustc_transmute::Answer::No(_)
|
||||||
|
| rustc_transmute::Answer::IfTransmutable { .. }
|
||||||
|
| rustc_transmute::Answer::IfAll(_)
|
||||||
|
| rustc_transmute::Answer::IfAny(_) => Err(NoSolution),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -524,6 +524,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
|
||||||
) -> QueryResult<'tcx> {
|
) -> QueryResult<'tcx> {
|
||||||
bug!("`Destruct` does not have an associated type: {:?}", goal);
|
bug!("`Destruct` does not have an associated type: {:?}", goal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consider_builtin_transmute_candidate(
|
||||||
|
_ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
|
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.
|
||||||
|
|
|
@ -556,6 +556,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
|
||||||
Err(NoSolution)
|
Err(NoSolution)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consider_builtin_transmute_candidate(
|
||||||
|
ecx: &mut EvalCtxt<'_, 'tcx>,
|
||||||
|
goal: Goal<'tcx, Self>,
|
||||||
|
) -> QueryResult<'tcx> {
|
||||||
|
// `rustc_transmute` does not have support for type or const params
|
||||||
|
if goal.has_non_region_placeholders() {
|
||||||
|
return Err(NoSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Erase regions because we compute layouts in `rustc_transmute`,
|
||||||
|
// which will ICE for region vars.
|
||||||
|
let substs = ecx.tcx().erase_regions(goal.predicate.trait_ref.substs);
|
||||||
|
|
||||||
|
let Some(assume) = rustc_transmute::Assume::from_const(
|
||||||
|
ecx.tcx(),
|
||||||
|
goal.param_env,
|
||||||
|
substs.const_at(3),
|
||||||
|
) else {
|
||||||
|
return Err(NoSolution);
|
||||||
|
};
|
||||||
|
|
||||||
|
let certainty = ecx.is_transmutable(
|
||||||
|
rustc_transmute::Types { dst: substs.type_at(0), src: substs.type_at(1) },
|
||||||
|
substs.type_at(2),
|
||||||
|
assume,
|
||||||
|
)?;
|
||||||
|
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
impl<'tcx> EvalCtxt<'_, 'tcx> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue