use crate::declaration::{ConstructorVal, InductiveVal};
use crate::error::KernelError;
use crate::{Environment, Expr, Name};
#[allow(clippy::result_large_err)]
pub(crate) fn proj_target<'env>(
env: &'env Environment,
struct_name: &Name,
idx: u32,
) -> Result<(&'env InductiveVal, &'env ConstructorVal), KernelError> {
let ind_val = env.get_inductive_val(struct_name).ok_or_else(|| {
KernelError::Other(format!(
"invalid projection: {} is not an inductive type",
struct_name
))
})?;
let [ctor_name] = ind_val.ctors.as_slice() else {
return Err(KernelError::Other(format!(
"invalid projection: {} has {} constructors; \
a projection reads an inductive type with exactly one",
struct_name,
ind_val.ctors.len()
)));
};
let ctor_val = env
.get_constructor_val(ctor_name)
.ok_or_else(|| KernelError::Other(format!("constructor not found: {}", ctor_name)))?;
if idx >= ctor_val.num_fields {
return Err(KernelError::Other(format!(
"field index {} out of range for {} (has {} fields)",
idx, struct_name, ctor_val.num_fields
)));
}
Ok((ind_val, ctor_val))
}
pub(crate) fn proj_type_params<'a>(
ind_val: &InductiveVal,
type_args: &'a [Expr],
) -> Option<&'a [Expr]> {
let num_params = ind_val.num_params as usize;
if type_args.len() != num_params + ind_val.num_indices as usize {
return None;
}
type_args.get(..num_params)
}
#[cfg(test)]
mod tests {
use super::proj_type_params;
use crate::declaration::{ConstantVal, InductiveVal};
use crate::{Expr, Level, Name};
fn family(num_params: u32, num_indices: u32) -> InductiveVal {
InductiveVal {
common: ConstantVal {
name: Name::str("S"),
level_params: vec![],
ty: Expr::Sort(Level::succ(Level::zero())),
},
num_params,
num_indices,
all: vec![Name::str("S")],
ctors: vec![Name::str("S.mk")],
num_nested: 0,
is_rec: false,
is_unsafe: false,
is_reflexive: false,
is_prop: false,
}
}
fn args() -> [Expr; 4] {
[Expr::BVar(0), Expr::BVar(1), Expr::BVar(2), Expr::BVar(3)]
}
#[test]
fn the_operand_type_carries_exactly_the_parameters_and_the_indices() {
let a = args();
let s = family(2, 1);
assert_eq!(proj_type_params(&s, &a[..3]), Some(&a[..2]));
assert_eq!(proj_type_params(&s, &a[..2]), None);
assert_eq!(proj_type_params(&s, &a[..1]), None);
assert_eq!(proj_type_params(&s, &a[..0]), None);
assert_eq!(proj_type_params(&s, &a[..4]), None);
}
#[test]
fn without_an_index_the_arguments_are_the_parameters() {
let a = args();
let s = family(2, 0);
assert_eq!(proj_type_params(&s, &a[..2]), Some(&a[..2]));
assert_eq!(proj_type_params(&s, &a[..1]), None);
assert_eq!(proj_type_params(&s, &a[..3]), None);
}
#[test]
fn without_a_parameter_no_argument_instantiates_the_constructor() {
let a = args();
let s = family(0, 2);
assert_eq!(proj_type_params(&s, &a[..2]), Some(&a[..0]));
assert_eq!(proj_type_params(&s, &a[..1]), None);
assert_eq!(proj_type_params(&s, &a[..3]), None);
let unit = family(0, 0);
assert_eq!(proj_type_params(&unit, &a[..0]), Some(&a[..0]));
assert_eq!(proj_type_params(&unit, &a[..1]), None);
}
}