use super::types::TypeChecker;
use crate::declaration::InductiveVal;
use crate::error::KernelError;
use crate::instantiate::instantiate_type_lparams;
use crate::subst::instantiate;
use crate::{Expr, Level};
pub(crate) fn is_prop_sort(sort: &Expr) -> Option<bool> {
match sort {
Expr::Sort(l) => Some(crate::level::is_equivalent(l, &Level::zero())),
_ => None,
}
}
pub(crate) fn structure_type_sort(
ind_val: &InductiveVal,
levels: &[Level],
args: &[Expr],
mut whnf: impl FnMut(&Expr) -> Expr,
) -> Expr {
let level_params = &ind_val.common.level_params;
let mut ty = if level_params.is_empty() || levels.is_empty() {
ind_val.common.ty.clone()
} else {
instantiate_type_lparams(&ind_val.common.ty, level_params, levels)
};
for arg in args {
if !matches!(ty, Expr::Pi(_, _, _, _)) {
ty = whnf(&ty);
}
match ty {
Expr::Pi(_, _, _, body) => ty = instantiate(&body, arg),
not_a_binder => return not_a_binder,
}
}
whnf(&ty)
}
impl TypeChecker<'_> {
#[allow(clippy::result_large_err)]
pub(super) fn proj_struct_is_prop(
&mut self,
ind_val: &InductiveVal,
levels: &[Level],
args: &[Expr],
) -> Result<bool, KernelError> {
let sort = structure_type_sort(ind_val, levels, args, |e| self.whnf(e));
is_prop_sort(&sort).ok_or_else(|| {
KernelError::Other(format!(
"invalid projection: cannot tell whether {} is a proposition \
(its type ends in {}, not in a sort)",
ind_val.common.name, sort
))
})
}
#[allow(clippy::result_large_err)]
pub(super) fn ensure_prop_field(
&mut self,
ind_val: &InductiveVal,
field: u32,
field_ty: &Expr,
) -> Result<(), KernelError> {
let sort = self.infer_type(field_ty)?;
let sort = self.whnf(&sort);
if is_prop_sort(&sort) == Some(true) {
return Ok(());
}
Err(KernelError::Other(format!(
"invalid projection: {} is a proposition and the type of its field {}, {}, \
is not; data cannot be projected out of a proof",
ind_val.common.name, field, field_ty
)))
}
}