Skip to content

Commit d92f74e

Browse files
Support safe transmute in new solver
1 parent 2a198c7 commit d92f74e

File tree

5 files changed

+67
-0
lines changed

5 files changed

+67
-0
lines changed

compiler/rustc_middle/src/ty/visit.rs

+3
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
8383
| TypeFlags::HAS_CT_PLACEHOLDER,
8484
)
8585
}
86+
fn has_non_region_placeholders(&self) -> bool {
87+
self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
88+
}
8689
fn needs_subst(&self) -> bool {
8790
self.has_type_flags(TypeFlags::NEEDS_SUBST)
8891
}

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
225225
ecx: &mut EvalCtxt<'_, 'tcx>,
226226
goal: Goal<'tcx, Self>,
227227
) -> QueryResult<'tcx>;
228+
229+
fn consider_builtin_transmute_candidate(
230+
ecx: &mut EvalCtxt<'_, 'tcx>,
231+
goal: Goal<'tcx, Self>,
232+
) -> QueryResult<'tcx>;
228233
}
229234

230235
impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -373,6 +378,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
373378
G::consider_builtin_discriminant_kind_candidate(self, goal)
374379
} else if lang_items.destruct_trait() == Some(trait_def_id) {
375380
G::consider_builtin_destruct_candidate(self, goal)
381+
} else if lang_items.transmute_trait() == Some(trait_def_id) {
382+
G::consider_builtin_transmute_candidate(self, goal)
376383
} else {
377384
Err(NoSolution)
378385
};

compiler/rustc_trait_selection/src/solve/eval_ctxt.rs

+21
Original file line numberDiff line numberDiff line change
@@ -639,4 +639,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
639639
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
640640
.map(|obligations| obligations.into_iter().map(|obligation| obligation.into()))
641641
}
642+
643+
pub(super) fn is_transmutable(
644+
&self,
645+
src_and_dst: rustc_transmute::Types<'tcx>,
646+
scope: Ty<'tcx>,
647+
assume: rustc_transmute::Assume,
648+
) -> Result<Certainty, NoSolution> {
649+
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
650+
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
651+
ObligationCause::dummy(),
652+
ty::Binder::dummy(src_and_dst),
653+
scope,
654+
assume,
655+
) {
656+
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
657+
rustc_transmute::Answer::No(_)
658+
| rustc_transmute::Answer::IfTransmutable { .. }
659+
| rustc_transmute::Answer::IfAll(_)
660+
| rustc_transmute::Answer::IfAny(_) => Err(NoSolution),
661+
}
662+
}
642663
}

compiler/rustc_trait_selection/src/solve/project_goals.rs

+7
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
524524
) -> QueryResult<'tcx> {
525525
bug!("`Destruct` does not have an associated type: {:?}", goal);
526526
}
527+
528+
fn consider_builtin_transmute_candidate(
529+
_ecx: &mut EvalCtxt<'_, 'tcx>,
530+
goal: Goal<'tcx, Self>,
531+
) -> QueryResult<'tcx> {
532+
bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
533+
}
527534
}
528535

529536
/// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code.

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+29
Original file line numberDiff line numberDiff line change
@@ -556,6 +556,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
556556
Err(NoSolution)
557557
}
558558
}
559+
560+
fn consider_builtin_transmute_candidate(
561+
ecx: &mut EvalCtxt<'_, 'tcx>,
562+
goal: Goal<'tcx, Self>,
563+
) -> QueryResult<'tcx> {
564+
// `rustc_transmute` does not have support for type or const params
565+
if goal.has_non_region_placeholders() {
566+
return Err(NoSolution);
567+
}
568+
569+
// Erase regions because we compute layouts in `rustc_transmute`,
570+
// which will ICE for region vars.
571+
let substs = ecx.tcx().erase_regions(goal.predicate.trait_ref.substs);
572+
573+
let Some(assume) = rustc_transmute::Assume::from_const(
574+
ecx.tcx(),
575+
goal.param_env,
576+
substs.const_at(3),
577+
) else {
578+
return Err(NoSolution);
579+
};
580+
581+
let certainty = ecx.is_transmutable(
582+
rustc_transmute::Types { dst: substs.type_at(0), src: substs.type_at(1) },
583+
substs.type_at(2),
584+
assume,
585+
)?;
586+
ecx.evaluate_added_goals_and_make_canonical_response(certainty)
587+
}
559588
}
560589

561590
impl<'tcx> EvalCtxt<'_, 'tcx> {

0 commit comments

Comments
 (0)