Skip to content

Commit

Permalink
Merge pull request #898 from Nadrieril/fix-some-binder-crashes
Browse files Browse the repository at this point in the history
Fix some binder-related crashes
  • Loading branch information
W95Psp authored Sep 19, 2024
2 parents ec8c2d8 + 56f08df commit 288f77f
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 85 deletions.
1 change: 1 addition & 0 deletions engine/lib/import_thir.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1074,6 +1074,7 @@ end) : EXPR = struct
| Dyn -> Dyn
| SelfImpl { path; _ } -> List.fold ~init:Self ~f:browse_path path
| Builtin { trait } -> Builtin (c_trait_ref span trait.value)
| Error str -> failwith @@ "impl_expr_atom: Error " ^ str

and c_generic_value (span : Thir.span) (ty : Thir.generic_arg) : generic_value
=
Expand Down
43 changes: 38 additions & 5 deletions frontend/exporter/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ mod types {
pub type ExportedDefIds = Rc<RefCell<HashSet<rustc_hir::def_id::DefId>>>;
pub type RcThir<'tcx> = Rc<rustc_middle::thir::Thir<'tcx>>;
pub type RcMir<'tcx> = Rc<rustc_middle::mir::Body<'tcx>>;
pub type Binder<'tcx> = rustc_middle::ty::Binder<'tcx, ()>;
}

mk!(
Expand All @@ -173,12 +174,22 @@ mk!(
thir: {'tcx} types::RcThir,
mir: {'tcx} types::RcMir,
owner_id: {} rustc_hir::def_id::DefId,
binder: {'tcx} types::Binder,
}
);

pub use self::types::*;

impl<'tcx> State<Base<'tcx>, (), (), ()> {
pub type StateWithBase<'tcx> = State<Base<'tcx>, (), (), (), ()>;
pub type StateWithOwner<'tcx> = State<Base<'tcx>, (), (), rustc_hir::def_id::DefId, ()>;
pub type StateWithBinder<'tcx> =
State<Base<'tcx>, (), (), rustc_hir::def_id::DefId, types::Binder<'tcx>>;
pub type StateWithThir<'tcx> =
State<Base<'tcx>, types::RcThir<'tcx>, (), rustc_hir::def_id::DefId, ()>;
pub type StateWithMir<'tcx> =
State<Base<'tcx>, (), types::RcMir<'tcx>, rustc_hir::def_id::DefId, ()>;

impl<'tcx> State<Base<'tcx>, (), (), (), ()> {
pub fn new(
tcx: rustc_middle::ty::TyCtxt<'tcx>,
options: hax_frontend_exporter_options::Options,
Expand All @@ -187,22 +198,24 @@ impl<'tcx> State<Base<'tcx>, (), (), ()> {
thir: (),
mir: (),
owner_id: (),
binder: (),
base: Base::new(tcx, options),
}
}
}

impl<'tcx> State<Base<'tcx>, (), (), rustc_hir::def_id::DefId> {
impl<'tcx> StateWithOwner<'tcx> {
pub fn new_from_state_and_id<S: BaseState<'tcx>>(s: &S, id: rustc_hir::def_id::DefId) -> Self {
State {
thir: (),
mir: (),
owner_id: id,
binder: (),
base: s.base().clone(),
}
}
}
impl<'tcx> State<Base<'tcx>, (), Rc<rustc_middle::mir::Body<'tcx>>, rustc_hir::def_id::DefId> {
impl<'tcx> StateWithMir<'tcx> {
pub fn new_from_mir(
tcx: rustc_middle::ty::TyCtxt<'tcx>,
options: hax_frontend_exporter_options::Options,
Expand All @@ -213,32 +226,52 @@ impl<'tcx> State<Base<'tcx>, (), Rc<rustc_middle::mir::Body<'tcx>>, rustc_hir::d
thir: (),
mir: Rc::new(mir),
owner_id,
binder: (),
base: Base::new(tcx, options),
}
}
}
impl<'tcx> StateWithThir<'tcx> {
pub fn from_thir(
base: Base<'tcx>,
owner_id: rustc_hir::def_id::DefId,
thir: types::RcThir<'tcx>,
) -> Self {
Self {
thir,
mir: (),
owner_id,
binder: (),
base,
}
}
}

/// Updates the OnwerId in a state, making sure to override `opt_def_id` in base as well.
pub fn with_owner_id<'tcx, THIR, MIR>(
mut base: types::Base<'tcx>,
thir: THIR,
mir: MIR,
owner_id: rustc_hir::def_id::DefId,
) -> State<types::Base<'tcx>, THIR, MIR, rustc_hir::def_id::DefId> {
) -> State<types::Base<'tcx>, THIR, MIR, rustc_hir::def_id::DefId, ()> {
base.opt_def_id = Some(owner_id);
State {
thir,
owner_id,
base,
mir,
binder: (),
}
}

pub trait BaseState<'tcx> = HasBase<'tcx> + Clone + IsState<'tcx>;

/// State of anything below a `owner_id`
/// State of anything below a `owner_id`.
pub trait UnderOwnerState<'tcx> = BaseState<'tcx> + HasOwnerId;

/// State of anything below a binder.
pub trait UnderBinderState<'tcx> = UnderOwnerState<'tcx> + HasBinder<'tcx>;

/// While translating expressions, we expect to always have a THIR
/// body and an `owner_id` in the state
pub trait ExprState<'tcx> = UnderOwnerState<'tcx> + HasThir<'tcx>;
Expand Down
43 changes: 31 additions & 12 deletions frontend/exporter/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ pub enum ImplExprAtom {
Dyn,
/// A built-in trait whose implementation is computed by the compiler, such as `Sync`.
Builtin { r#trait: Binder<TraitRef> },
/// An error happened while resolving traits.
Error(String),
}

/// An `ImplExpr` describes the full data of a trait implementation. Because of generics, this may
Expand Down Expand Up @@ -87,7 +89,8 @@ pub mod rustc {
{
fn sinto(&self, s: &S) -> crate::ImplExpr {
use crate::ParamEnv;
match impl_expr(s.base().tcx, s.owner_id(), s.param_env(), self) {
let warn = |msg: &str| crate::warning!(s, "{}", msg);
match impl_expr(s.base().tcx, s.owner_id(), s.param_env(), self, &warn) {
Ok(x) => x.sinto(s),
Err(e) => crate::fatal!(s, "{}", e),
}
Expand Down Expand Up @@ -228,6 +231,7 @@ pub mod rustc {
tcx: TyCtxt<'tcx>,
predicates: impl Iterator<Item = Predicate<'tcx>>,
) -> impl Iterator<Item = PolyTraitPredicate<'tcx>> {
// Warning: this skip_binder seems dangerous
let generics = self.skip_binder().trait_ref.args;
predicates
.filter_map(|pred| pred.as_trait_clause())
Expand Down Expand Up @@ -311,7 +315,14 @@ pub mod rustc {
{
// If a predicate was already seen, we know it is
// not the one we are looking for: we skip it.
if seen.contains(&candidate.pred) {
if seen.iter().any(|seen_pred: &PolyTraitPredicate<'tcx>| {
predicate_equality(
tcx,
candidate.pred.upcast(tcx),
(*seen_pred).upcast(tcx),
param_env,
)
}) {
continue;
}
seen.insert(candidate.pred);
Expand All @@ -336,6 +347,7 @@ pub mod rustc {
});
}
for (item, binder) in candidate.pred.associated_items_trait_predicates(tcx) {
// Warning: this skip_binder seems dangerous
for (index, parent_pred) in binder.skip_binder().into_iter() {
let mut path = candidate.path.clone();
path.push(PathChunk::AssocItem {
Expand Down Expand Up @@ -396,6 +408,8 @@ pub mod rustc {
Dyn,
/// A built-in trait whose implementation is computed by the compiler, such as `Sync`.
Builtin { r#trait: PolyTraitRef<'tcx> },
/// An error happened while resolving traits.
Error(String),
}

#[derive(Clone, Debug)]
Expand All @@ -422,13 +436,14 @@ pub mod rustc {
}
}

#[tracing::instrument(level = "trace", skip(tcx))]
#[tracing::instrument(level = "trace", skip(tcx, warn))]
fn impl_exprs<'tcx>(
tcx: TyCtxt<'tcx>,
owner_id: DefId,
obligations: &Vec<
rustc_trait_selection::traits::Obligation<'tcx, rustc_middle::ty::Predicate<'tcx>>,
>,
warn: &impl Fn(&str),
) -> Result<Vec<ImplExpr<'tcx>>, String> {
obligations
.into_iter()
Expand All @@ -439,18 +454,21 @@ pub mod rustc {
owner_id,
obligation.param_env,
&trait_ref.map_bound(|p| p.trait_ref),
warn,
)
})
})
.collect()
}

#[tracing::instrument(level = "trace", skip(tcx, param_env))]
#[tracing::instrument(level = "trace", skip(tcx, param_env, warn))]
fn impl_expr<'tcx>(
tcx: TyCtxt<'tcx>,
owner_id: DefId,
param_env: rustc_middle::ty::ParamEnv<'tcx>,
tref: &rustc_middle::ty::PolyTraitRef<'tcx>,
// Call back into hax-related code to display a nice warning.
warn: &impl Fn(&str),
) -> Result<ImplExpr<'tcx>, String> {
use rustc_trait_selection::traits::*;
let impl_source = copy_paste_from_rustc::codegen_select_candidate(tcx, (param_env, *tref))
Expand All @@ -464,15 +482,17 @@ pub mod rustc {
def_id: impl_def_id,
generics,
}
.with_args(impl_exprs(tcx, owner_id, &nested)?, *tref),
.with_args(impl_exprs(tcx, owner_id, &nested, warn)?, *tref),
ImplSource::Param(nested) => {
let nested = impl_exprs(tcx, owner_id, &nested, warn)?;
let predicates = tcx.predicates_defined_on_or_above(owner_id);
let Some((path, apred)) =
search_clause::path_to(tcx, &predicates, tref.clone(), param_env)
else {
return Err(format!(
"Could not find a clause for `{tref:?}` in the item parameters"
));
let msg =
format!("Could not find a clause for `{tref:?}` in the item parameters");
warn(&msg);
return Ok(ImplExprAtom::Error(msg).with_args(nested, *tref));
};

let Some(trait_clause) = apred.clause.as_trait_clause() else {
Expand All @@ -486,15 +506,14 @@ pub mod rustc {
let r#trait = trait_clause.to_poly_trait_ref();
if apred.is_extra_self_predicate {
ImplExprAtom::SelfImpl { r#trait, path }
.with_args(impl_exprs(tcx, owner_id, &nested)?, *tref)
} else {
ImplExprAtom::LocalBound {
predicate: apred.clause.as_predicate(),
r#trait,
path,
}
.with_args(impl_exprs(tcx, owner_id, &nested)?, *tref)
}
.with_args(nested, *tref)
}
// We ignore the contained obligations here. For example for `(): Send`, the
// obligations contained would be `[(): Send]`, which leads to an infinite loop. There
Expand Down Expand Up @@ -608,8 +627,8 @@ impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, ImplExpr>
}
}

/// `impl_did`, susbts correctly `Self` from `clause` and (1) derive a
/// `Clause` and (2) resolve an `ImplExpr`.
/// Given a clause `clause` in the context of some impl block `impl_did`, susbts correctly `Self`
/// from `clause` and (1) derive a `Clause` and (2) resolve an `ImplExpr`.
#[cfg(feature = "rustc")]
pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
Expand Down
Loading

0 comments on commit 288f77f

Please sign in to comment.