use crate::clauses::builder::ClauseBuilder;
use crate::rust_ir::*;
use crate::split::Split;
use chalk_ir::cast::{Cast, Caster};
use chalk_ir::interner::Interner;
use chalk_ir::*;
use std::iter;
use tracing::instrument;
pub trait ToProgramClauses<I: Interner> {
fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment<I>);
}
impl<I: Interner> ToProgramClauses<I> for ImplDatum<I> {
fn to_program_clauses(
&self,
builder: &mut ClauseBuilder<'_, I>,
_environment: &Environment<I>,
) {
if self.is_positive() {
let binders = self.binders.clone();
builder.push_binders(
binders,
|builder,
ImplDatumBound {
trait_ref,
where_clauses,
}| {
builder.push_clause(trait_ref, where_clauses);
},
);
}
}
}
impl<I: Interner> ToProgramClauses<I> for AssociatedTyValue<I> {
fn to_program_clauses(
&self,
builder: &mut ClauseBuilder<'_, I>,
_environment: &Environment<I>,
) {
let impl_datum = builder.db.impl_datum(self.impl_id);
let associated_ty = builder.db.associated_ty_data(self.associated_ty_id);
builder.push_binders(self.value.clone(), |builder, assoc_ty_value| {
let all_parameters = builder.placeholders_in_scope().to_vec();
let (impl_params, projection) = builder
.db
.impl_parameters_and_projection_from_associated_ty_value(&all_parameters, self);
let interner = builder.db.interner();
let impl_where_clauses = impl_datum
.binders
.map_ref(|b| &b.where_clauses)
.into_iter()
.map(|wc| wc.cloned().substitute(interner, impl_params));
let assoc_ty_where_clauses = associated_ty
.binders
.map_ref(|b| &b.where_clauses)
.into_iter()
.map(|wc| wc.cloned().substitute(interner, &projection.substitution));
builder.push_clause(
Normalize {
alias: AliasTy::Projection(projection.clone()),
ty: assoc_ty_value.ty,
},
impl_where_clauses.chain(assoc_ty_where_clauses),
);
});
}
}
impl<I: Interner> ToProgramClauses<I> for OpaqueTyDatum<I> {
#[instrument(level = "debug", skip(builder))]
fn to_program_clauses(
&self,
builder: &mut ClauseBuilder<'_, I>,
_environment: &Environment<I>,
) {
builder.push_binders(self.bound.clone(), |builder, opaque_ty_bound| {
let interner = builder.interner();
let substitution = builder.substitution_in_scope();
let alias = AliasTy::Opaque(OpaqueTy {
opaque_ty_id: self.opaque_ty_id,
substitution: substitution.clone(),
});
let alias_placeholder_ty =
TyKind::OpaqueType(self.opaque_ty_id, substitution).intern(interner);
builder.push_clause(
DomainGoal::Holds(
AliasEq {
alias: alias.clone(),
ty: builder.db.hidden_opaque_type(self.opaque_ty_id),
}
.cast(interner),
),
iter::once(DomainGoal::Reveal),
);
builder.push_fact(DomainGoal::Holds(
AliasEq {
alias,
ty: alias_placeholder_ty.clone(),
}
.cast(interner),
));
builder.push_binders(opaque_ty_bound.where_clauses, |builder, where_clauses| {
builder.push_clause(
WellFormed::Ty(alias_placeholder_ty.clone()),
where_clauses
.into_iter()
.map(|wc| wc.into_well_formed_goal(interner)),
);
});
let substitution = Substitution::from1(interner, alias_placeholder_ty);
for bound in opaque_ty_bound.bounds {
let bound_with_placeholder_ty = bound.substitute(interner, &substitution);
builder.push_binders(bound_with_placeholder_ty, |builder, bound| match &bound {
WhereClause::Implemented(trait_ref) => {
super::super_traits::push_trait_super_clauses(
builder.db,
builder,
trait_ref.clone(),
)
}
WhereClause::AliasEq(_) => builder.push_fact(bound),
WhereClause::LifetimeOutlives(..) => {}
WhereClause::TypeOutlives(..) => {}
});
}
});
}
}
fn well_formed_program_clauses<'a, I, Wc>(
builder: &'a mut ClauseBuilder<'_, I>,
ty: Ty<I>,
where_clauses: Wc,
) where
I: Interner,
Wc: Iterator<Item = &'a QuantifiedWhereClause<I>>,
{
let interner = builder.interner();
builder.push_clause(
WellFormed::Ty(ty),
where_clauses
.cloned()
.map(|qwc| qwc.into_well_formed_goal(interner)),
);
}
fn fully_visible_program_clauses<I>(
builder: &mut ClauseBuilder<'_, I>,
ty: Ty<I>,
subst: &Substitution<I>,
) where
I: Interner,
{
let interner = builder.interner();
builder.push_clause(
DomainGoal::IsFullyVisible(ty),
subst
.type_parameters(interner)
.map(|typ| DomainGoal::IsFullyVisible(typ).cast::<Goal<_>>(interner)),
);
}
fn implied_bounds_program_clauses<'a, I, Wc>(
builder: &'a mut ClauseBuilder<'_, I>,
ty: &Ty<I>,
where_clauses: Wc,
) where
I: Interner,
Wc: Iterator<Item = &'a QuantifiedWhereClause<I>>,
{
let interner = builder.interner();
for qwc in where_clauses {
builder.push_binders(qwc.clone(), |builder, wc| {
builder.push_clause(wc.into_from_env_goal(interner), Some(ty.clone().from_env()));
});
}
}
impl<I: Interner> ToProgramClauses<I> for AdtDatum<I> {
#[instrument(level = "debug", skip(builder))]
fn to_program_clauses(
&self,
builder: &mut ClauseBuilder<'_, I>,
_environment: &Environment<I>,
) {
let interner = builder.interner();
let binders = self.binders.map_ref(|b| &b.where_clauses).cloned();
builder.push_binders(binders, |builder, where_clauses| {
let self_ty = TyKind::Adt(self.id, builder.substitution_in_scope()).intern(interner);
well_formed_program_clauses(builder, self_ty.clone(), where_clauses.iter());
implied_bounds_program_clauses(builder, &self_ty, where_clauses.iter());
fully_visible_program_clauses(
builder,
self_ty.clone(),
&builder.substitution_in_scope(),
);
if !self.flags.upstream {
builder.push_fact(DomainGoal::IsLocal(self_ty.clone()));
} else if self.flags.fundamental {
for type_param in builder.substitution_in_scope().type_parameters(interner) {
builder.push_clause(
DomainGoal::IsLocal(self_ty.clone()),
Some(DomainGoal::IsLocal(type_param)),
);
}
builder.push_clause(
DomainGoal::IsUpstream(self_ty.clone()),
builder
.substitution_in_scope()
.type_parameters(interner)
.map(|type_param| DomainGoal::IsUpstream(type_param)),
);
} else {
builder.push_fact(DomainGoal::IsUpstream(self_ty.clone()));
}
if self.flags.fundamental {
assert!(
builder
.substitution_in_scope()
.type_parameters(interner)
.count()
>= 1,
"Only fundamental types with type parameters are supported"
);
for type_param in builder.substitution_in_scope().type_parameters(interner) {
builder.push_clause(
DomainGoal::DownstreamType(self_ty.clone()),
Some(DomainGoal::DownstreamType(type_param)),
);
}
}
});
}
}
impl<I: Interner> ToProgramClauses<I> for FnDefDatum<I> {
#[instrument(level = "debug", skip(builder))]
fn to_program_clauses(
&self,
builder: &mut ClauseBuilder<'_, I>,
_environment: &Environment<I>,
) {
let interner = builder.interner();
let binders = self.binders.map_ref(|b| &b.where_clauses).cloned();
builder.push_binders(binders, |builder, where_clauses| {
let ty = TyKind::FnDef(self.id, builder.substitution_in_scope()).intern(interner);
well_formed_program_clauses(builder, ty.clone(), where_clauses.iter());
implied_bounds_program_clauses(builder, &ty, where_clauses.iter());
fully_visible_program_clauses(builder, ty, &builder.substitution_in_scope());
});
}
}
impl<I: Interner> ToProgramClauses<I> for TraitDatum<I> {
fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment<I>) {
let interner = builder.interner();
let binders = self.binders.map_ref(|b| &b.where_clauses).cloned();
builder.push_binders(binders, |builder, where_clauses| {
let trait_ref = chalk_ir::TraitRef {
trait_id: self.id,
substitution: builder.substitution_in_scope(),
};
builder.push_clause(
trait_ref.clone().well_formed(),
where_clauses
.iter()
.cloned()
.map(|qwc| qwc.into_well_formed_goal(interner))
.casted::<Goal<_>>(interner)
.chain(Some(trait_ref.clone().cast(interner))),
);
let type_parameters: Vec<_> = trait_ref.type_parameters(interner).collect();
if environment.has_compatible_clause(interner) {
if self.well_known != Some(WellKnownTrait::Drop) {
for i in 0..type_parameters.len() {
builder.push_clause(
trait_ref.clone(),
where_clauses
.iter()
.cloned()
.casted(interner)
.chain(iter::once(DomainGoal::Compatible.cast(interner)))
.chain((0..i).map(|j| {
DomainGoal::IsFullyVisible(type_parameters[j].clone())
.cast(interner)
}))
.chain(iter::once(
DomainGoal::DownstreamType(type_parameters[i].clone())
.cast(interner),
))
.chain(iter::once(GoalData::CannotProve.intern(interner))),
);
}
}
if !self.flags.fundamental {
builder.push_clause(
trait_ref.clone(),
where_clauses
.iter()
.cloned()
.casted(interner)
.chain(iter::once(DomainGoal::Compatible.cast(interner)))
.chain(
trait_ref
.type_parameters(interner)
.map(|ty| DomainGoal::IsUpstream(ty).cast(interner)),
)
.chain(iter::once(GoalData::CannotProve.intern(interner))),
);
}
}
if !self.flags.upstream {
builder.push_fact(DomainGoal::LocalImplAllowed(trait_ref.clone()));
} else {
for i in 0..type_parameters.len() {
builder.push_clause(
DomainGoal::LocalImplAllowed(trait_ref.clone()),
(0..i)
.map(|j| DomainGoal::IsFullyVisible(type_parameters[j].clone()))
.chain(Some(DomainGoal::IsLocal(type_parameters[i].clone()))),
);
}
}
for qwc in where_clauses {
builder.push_binders(qwc, |builder, wc| {
builder.push_clause(
wc.into_from_env_goal(interner),
Some(trait_ref.clone().from_env()),
);
});
}
builder.push_clause(trait_ref.clone(), Some(trait_ref.from_env()));
});
}
}
impl<I: Interner> ToProgramClauses<I> for AssociatedTyDatum<I> {
fn to_program_clauses(
&self,
builder: &mut ClauseBuilder<'_, I>,
_environment: &Environment<I>,
) {
let interner = builder.interner();
let binders = self.binders.clone();
builder.push_binders(
binders,
|builder,
AssociatedTyDatumBound {
where_clauses,
bounds,
}| {
let substitution = builder.substitution_in_scope();
let projection = ProjectionTy {
associated_ty_id: self.id,
substitution: substitution.clone(),
};
let projection_ty = AliasTy::Projection(projection.clone()).intern(interner);
let trait_ref = builder.db.trait_ref_from_projection(&projection);
let ty = TyKind::AssociatedType(self.id, substitution).intern(interner);
let projection_eq = AliasEq {
alias: AliasTy::Projection(projection.clone()),
ty: ty.clone(),
};
builder.push_fact_with_priority(projection_eq, None, ClausePriority::Low);
builder.push_clause(
WellFormed::Ty(ty.clone()),
iter::once(WellFormed::Trait(trait_ref.clone()).cast::<Goal<_>>(interner))
.chain(
where_clauses
.iter()
.cloned()
.map(|qwc| qwc.into_well_formed_goal(interner))
.casted(interner),
),
);
builder.push_clause(FromEnv::Trait(trait_ref.clone()), Some(ty.from_env()));
for qwc in &where_clauses {
builder.push_binders(qwc.clone(), |builder, wc| {
builder.push_clause(
wc.into_from_env_goal(interner),
Some(FromEnv::Ty(ty.clone())),
);
});
}
for quantified_bound in bounds {
builder.push_binders(quantified_bound, |builder, bound| {
for wc in bound.into_where_clauses(interner, projection_ty.clone()) {
builder.push_clause(
wc.into_from_env_goal(interner),
iter::once(
FromEnv::Trait(trait_ref.clone()).cast::<Goal<_>>(interner),
)
.chain(where_clauses.iter().cloned().casted(interner)),
);
}
});
}
builder.push_bound_ty(|builder, ty| {
let normalize = Normalize {
alias: AliasTy::Projection(projection.clone()),
ty: ty.clone(),
};
let projection_eq = AliasEq {
alias: AliasTy::Projection(projection),
ty,
};
builder.push_clause(projection_eq, Some(normalize));
});
},
);
}
}