diff options
| author | Jack Wrenn <jack@wrenn.fyi> | 2021-07-03 12:18:13 -0400 |
|---|---|---|
| committer | Jack Wrenn <jack@wrenn.fyi> | 2022-07-27 17:33:56 +0000 |
| commit | bc4a1dea416e1695cf77acd17ea743d4d802bae0 (patch) | |
| tree | f53690a1600de8fa7923dd3da10daf919978c492 /compiler/rustc_trait_selection/src/traits | |
| parent | 2a220937c283803bfd5d1155e4a81e6287089504 (diff) | |
| download | rust-bc4a1dea416e1695cf77acd17ea743d4d802bae0.tar.gz rust-bc4a1dea416e1695cf77acd17ea743d4d802bae0.zip | |
Initial (incomplete) implementation of transmutability trait.
This initial implementation handles transmutations between types with specified layouts, except when references are involved. Co-authored-by: Igor null <m1el.2027@gmail.com>
Diffstat (limited to 'compiler/rustc_trait_selection/src/traits')
3 files changed, 78 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 6e8581128dd..a18b835e70c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -305,6 +305,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else if lang_items.destruct_trait() == Some(def_id) { self.assemble_const_destruct_candidates(obligation, &mut candidates); + } else if lang_items.transmute_trait() == Some(def_id) { + // User-defined transmutability impls are permitted. + self.assemble_candidates_from_impls(obligation, &mut candidates); + self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -874,6 +878,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + fn assemble_candidates_for_transmutability( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if obligation.has_param_types_or_consts() { + candidates.ambiguous = false; + return; + } + + if obligation.has_infer_types_or_consts() { + candidates.ambiguous = true; + return; + } + + candidates.vec.push(TransmutabilityCandidate); + } + + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_trait_alias( &mut self, obligation: &TraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d4c9fd1c5f9..a609fb2b172 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -48,6 +48,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(data) } + TransmutabilityCandidate => { + let data = self.confirm_transmutability_candidate(obligation)?; + ImplSource::Builtin(data) + } + ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); @@ -267,6 +272,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSourceBuiltinData { nested: obligations } } + fn confirm_transmutability_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + debug!(?obligation, "confirm_transmutability_candidate"); + + let predicate = obligation.predicate; + + let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i)); + let bool_at = |i| { + predicate + .skip_binder() + .trait_ref + .substs + .const_at(i) + .try_eval_bool(self.tcx(), obligation.param_env) + .unwrap() + }; + + let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { + src: p.trait_ref.substs.type_at(1), + dst: p.trait_ref.substs.type_at(0), + }); + + let scope = type_at(2).skip_binder(); + + let assume = rustc_transmute::Assume { + alignment: bool_at(3), + lifetimes: bool_at(4), + validity: bool_at(5), + visibility: bool_at(6), + }; + + let cause = obligation.cause.clone(); + + let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx); + + let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume); + + use rustc_transmute::Answer; + + match maybe_transmutable { + Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }), + _ => Err(Unimplemented), + } + } + /// This handles the case where an `auto trait Foo` impl is being used. /// The idea is that the impl applies to `X : Foo` if the following conditions are met: /// diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 17f34012d1d..9ca23228b98 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1630,6 +1630,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } + // FIXME(@jswrenn): this should probably be more sophisticated + (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, + // (*) ( BuiltinCandidate { has_nested: false } |
