1
Fork 0

Rollup merge of #110126 - compiler-errors:new-solver-safe-transmute, r=oli-obk

Support safe transmute in new solver

Basically copies the same implementation as the old solver, but instead of looking for param types, we look for type or const placeholders.
This commit is contained in:
Michael Goulet 2023-04-11 20:28:48 -07:00 committed by GitHub
commit 87c9b3f35e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 1184 additions and 121 deletions

View file

@ -225,6 +225,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
fn consider_builtin_transmute_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx>;
}
impl<'tcx> EvalCtxt<'_, 'tcx> {
@ -373,6 +378,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
G::consider_builtin_discriminant_kind_candidate(self, goal)
} else if lang_items.destruct_trait() == Some(trait_def_id) {
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 {
Err(NoSolution)
};

View file

@ -639,4 +639,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
crate::traits::wf::unnormalized_obligations(self.infcx, param_env, arg)
.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),
}
}
}

View file

@ -524,6 +524,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
) -> QueryResult<'tcx> {
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.

View file

@ -598,6 +598,35 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
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> {