Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
W95Psp committed May 13, 2024
1 parent 9387c52 commit b260c7b
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 83 deletions.
67 changes: 13 additions & 54 deletions frontend/exporter/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ pub enum ImplExprPathChunk {
AssocItem {
item: AssocItem,
predicate: Binder<TraitPredicate>,
clause_id: u64,
clause_id: PredicateId,
index: usize,
},
Parent {
predicate: Binder<TraitPredicate>,
clause_id: u64,
clause_id: PredicateId,
index: usize,
},
}
Expand All @@ -32,7 +32,7 @@ pub enum ImplExprAtom {
},
/// A context-bound clause like `where T: Trait`.
LocalBound {
clause_id: u64,
clause_id: PredicateId,
r#trait: Binder<TraitRef>,
path: Vec<ImplExprPathChunk>,
},
Expand Down Expand Up @@ -73,6 +73,7 @@ pub struct ImplExpr {
mod search_clause {
use crate::prelude::UnderOwnerState;
use crate::rustc_utils::*;
use crate::{IntoPredicateId, PredicateId};
use rustc_middle::ty::*;

fn predicates_to_poly_trait_predicates<'tcx>(
Expand All @@ -90,12 +91,12 @@ mod search_clause {
AssocItem {
item: AssocItem,
predicate: PolyTraitPredicate<'tcx>,
clause_id: u64,
clause_id: PredicateId,
index: usize,
},
Parent {
predicate: PolyTraitPredicate<'tcx>,
clause_id: u64,
clause_id: PredicateId,
index: usize,
},
}
Expand Down Expand Up @@ -224,10 +225,7 @@ mod search_clause {
cons(
PathChunk::Parent {
predicate: p,
clause_id: {
use rustc_middle::ty::ToPredicate;
crate::clause_id_of_predicate(s, p.to_predicate(s.base().tcx))
},
clause_id: p.clause_id(s),
index,
},
path,
Expand All @@ -244,13 +242,7 @@ mod search_clause {
cons(
PathChunk::AssocItem {
item,
clause_id: {
use rustc_middle::ty::ToPredicate;
crate::clause_id_of_predicate(
s,
p.to_predicate(s.base().tcx),
)
},
clause_id: p.clause_id(s),
predicate: p,
index,
},
Expand Down Expand Up @@ -374,7 +366,7 @@ impl<'tcx> IntoImplExpr<'tcx> for rustc_middle::ty::PolyTraitRef<'tcx> {
.with_args(impl_exprs(s, &nested), trait_ref)
} else {
ImplExprAtom::LocalBound {
clause_id: clause_id_of_predicate(s, apred.predicate),
clause_id: apred.predicate.clause_id(s),
r#trait,
path,
}
Expand Down Expand Up @@ -415,54 +407,21 @@ pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>(
// original clause id (with, i.e., `Self`)
let s = &with_owner_id(s.base(), (), (), impl_trait_ref.def_id());
// We compute the id of the clause without binder.
let clause: Clause = clause.kind().skip_binder().sinto(s);
clause.id
// let clause: Clause = clause.sinto(s);
// clause.id
clause.clause_id(s)
};
let new_clause = clause.subst_supertrait(tcx, &impl_trait_ref);
let impl_expr = new_clause
.as_predicate()
.to_opt_poly_trait_pred()?
.impl_expr(s, get_param_env(s));
// Build the new clause, again without binder.
let mut new_clause_no_binder: Clause = new_clause.kind().skip_binder().sinto(s);
let mut new_clause_no_binder = new_clause.sinto(s);
new_clause_no_binder.id = original_clause_id;
Some((new_clause_no_binder, impl_expr, span.sinto(s)))
}

fn deterministic_hash<T: std::hash::Hash>(x: &T) -> u64 {
use crate::deterministic_hash::DeterministicHasher;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DeterministicHasher::new(DefaultHasher::new());
x.hash(&mut hasher);
hasher.finish()
}

/// Crafts a unique identifier for a predicate by hashing it. The hash
/// is non-trivial because we need stable identifiers: two hax
/// extraction of a same predicate should result in the same
/// identifier. Rustc's stable hash is not doing what we want here: it
/// is sensible to the environment. Instead, we convert the (rustc)
/// predicate to `crate::Predicate` and hash from there.
#[tracing::instrument(level = "trace", skip(s))]
pub fn clause_id_of_predicate<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
predicate: rustc_middle::ty::Predicate<'tcx>,
) -> u64 {
let predicate = predicate.sinto(s);
match &predicate.value {
// Instead of recursively hashing the clause, we reuse the already-computed id.
PredicateKind::Clause(clause) => clause.id,
_ => deterministic_hash(&(1u8, predicate)),
}
}

/// Used when building a `crate::Clause`. See [`clause_id_of_predicate`] for what we're doing here.
#[tracing::instrument(level = "trace")]
pub fn clause_id_of_bound_clause_kind(binder: &Binder<ClauseKind>) -> u64 {
deterministic_hash(&(0u8, binder))
}

#[tracing::instrument(level = "trace", skip(s))]
pub fn select_trait_candidate<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
Expand Down
51 changes: 22 additions & 29 deletions frontend/exporter/src/types/copied.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3275,35 +3275,37 @@ pub enum ClauseKind {
TypeWellFormedFromEnv(Ty),
}

/// Reflects [`rustc_middle::ty::ClauseKind`] and adds a hash-consed clause identifier.
/// Reflects [`rustc_middle::ty::Clause`] and adds a hash-consed clause identifier.
#[derive(
Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord,
)]
pub struct Clause {
pub kind: ClauseKind,
pub id: u64,
pub kind: Binder<ClauseKind>,
pub id: PredicateId,
}

impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, Clause>
for rustc_middle::ty::Binder<'tcx, rustc_middle::ty::ClauseKind<'tcx>>
{
impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, Clause> for rustc_middle::ty::Clause<'tcx> {
fn sinto(&self, s: &S) -> Clause {
// FIXME: `ClauseKind::sinto` uses a dummy binder. We need it because `Predicate::sinto()`
// doesn't propagate the binder to the `ClauseKind`. This might cause inconsistencies. It
// might be that we don't want to hash the binder at all.
let binder: Binder<ClauseKind> = self.sinto(s);
let id = clause_id_of_bound_clause_kind(&binder);
Clause {
kind: binder.value,
id,
}
let kind: Binder<ClauseKind> = self.kind().sinto(s);
let id = self.clause_id(s);
Clause { kind, id }
}
}

impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, Clause> for rustc_middle::ty::ClauseKind<'tcx> {
fn sinto(&self, s: &S) -> Clause {
// FIXME: this is dangerous.
rustc_middle::ty::Binder::dummy(self.clone()).sinto(s)
/// Reflects [`rustc_middle::ty::Predicate`] and adds a hash-consed clause identifier.
#[derive(
Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord,
)]
pub struct Predicate {
pub kind: Binder<PredicateKind>,
pub id: PredicateId,
}

impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, Predicate> for rustc_middle::ty::Predicate<'tcx> {
fn sinto(&self, s: &S) -> Predicate {
let kind: Binder<PredicateKind> = self.kind().sinto(s);
let id = self.clause_id(s);
Predicate { kind, id }
}
}

Expand Down Expand Up @@ -3341,9 +3343,6 @@ pub struct GenericPredicates {
pub predicates: Vec<(Predicate, Span)>,
}

/// Reflects [`rustc_middle::ty::Predicate`]
pub type Predicate = Binder<PredicateKind>;

impl<'tcx, S: UnderOwnerState<'tcx>, T1, T2> SInto<S, Binder<T2>>
for rustc_middle::ty::Binder<'tcx, T1>
where
Expand All @@ -3356,12 +3355,6 @@ where
}
}

impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, Predicate> for rustc_middle::ty::Predicate<'tcx> {
fn sinto(&self, s: &S) -> Predicate {
self.kind().sinto(s)
}
}

/// Reflects [`rustc_middle::ty::SubtypePredicate`]
#[derive(AdtInto)]
#[args(<'tcx, S: UnderOwnerState<'tcx>>, from: rustc_middle::ty::SubtypePredicate<'tcx>, state: S as tcx)]
Expand Down Expand Up @@ -3415,7 +3408,7 @@ pub enum ClosureKind {
Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord,
)]
pub enum PredicateKind {
Clause(Clause),
Clause(ClauseKind),
ObjectSafe(DefId),
ClosureKind(DefId, Vec<GenericArg>, ClosureKind),
Subtype(SubtypePredicate),
Expand Down
60 changes: 60 additions & 0 deletions frontend/exporter/src/types/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,63 @@ impl ItemAttributes {
}
}
}

#[derive(
Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, Hash, PartialEq, Eq, PartialOrd, Ord,
)]
#[serde(transparent)]
/// A `PredicateId` is a unique identifier for a clause or predicate
/// constructing by hashing it.
pub struct PredicateId(u64);

/// `IntoPredicateId` provides a method `clause_id` that dervies a clause
/// identifier by hashing `self`.
pub trait IntoPredicateId<'tcx, S: UnderOwnerState<'tcx>> {
fn clause_id(&self, s: &S) -> PredicateId;
}

const _: () = {
use rustc_middle::ty;

/// The hash is non-trivial because we need stable identifiers:
/// two hax extraction of a same predicate should result in the
/// same identifier. Rustc's stable hash is not doing what we want
/// here: it is sensible to the environment. Instead, we convert
/// the (rustc) Predicate or ClauseKind to the hax versions of
/// Predicate or ClauseKind and compute a deterministic hash from
/// there.
fn deterministic_hash<T: std::hash::Hash>(x: &T) -> u64 {
use crate::deterministic_hash::DeterministicHasher;
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
let mut hasher = DeterministicHasher::new(DefaultHasher::new());
x.hash(&mut hasher);
hasher.finish()
}

impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Clause<'tcx> {
fn clause_id(&self, s: &S) -> PredicateId {
self.as_predicate().clause_id(s)
}
}

impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::Predicate<'tcx> {
fn clause_id(&self, s: &S) -> PredicateId {
PredicateId(deterministic_hash(&self.sinto(s)))
}
}

impl<'tcx, S: UnderOwnerState<'tcx>> IntoPredicateId<'tcx, S> for ty::PolyTraitPredicate<'tcx> {
fn clause_id(&self, s: &S) -> PredicateId {
use crate::rustc_middle::ty::ToPredicate;
let predicate: ty::Predicate<'tcx> = (*self).to_predicate(s.base().tcx);
predicate.clause_id(s)
}
}

impl<'tcx, S: UnderOwnerState<'tcx>> SInto<S, PredicateId> for PredicateId {
fn sinto(&self, _s: &S) -> PredicateId {
*self
}
}
};

0 comments on commit b260c7b

Please sign in to comment.