aboutsummaryrefslogtreecommitdiff
path: root/src/checker_signature.rs
diff options
context:
space:
mode:
authortslil <tslil@posteo.de>2026-04-30 16:53:14 +0100
committertslil <tslil@posteo.de>2026-04-30 17:30:22 +0100
commit0f7efe7518b925d9688dad4c6f6e87f84015e2c1 (patch)
treef4cdfa08c7d3e7a69860570f3f7826119f3bcdef /src/checker_signature.rs
parentd57f1d3c845220c741db73c1fada017a75b11992 (diff)
wip case for instances
Diffstat (limited to 'src/checker_signature.rs')
-rw-r--r--src/checker_signature.rs97
1 files changed, 95 insertions, 2 deletions
diff --git a/src/checker_signature.rs b/src/checker_signature.rs
index 89f4441..17154dd 100644
--- a/src/checker_signature.rs
+++ b/src/checker_signature.rs
@@ -1,3 +1,5 @@
+// Time-stamp: <2026-04-30 17h19 BST (9561bc0c)>
+
use crate::ast::*;
use crate::checker_state::*;
use std::collections::HashMap;
@@ -101,7 +103,6 @@ impl CheckerState {
Ok(Instance::Var(v.clone()))
}
}
-
Instance::Record(assignations) => {
if let Some(signature) = signature {
let rej = |reason| CheckerError::InstanceDoesNotBelong {
@@ -219,6 +220,98 @@ impl CheckerState {
),
}
}
+ Instance::Case { scrutinee, arms } => {
+ if arms.is_empty() {
+ return Err(CheckerError::Unimplemented(
+ "mapping out of bottom types".to_string(),
+ ));
+ }
+
+ let arm_owners = arms
+ .iter()
+ .map(|ca| self.lookup_variant_field(&ca.tag).map(|sf| &sf.owner))
+ .collect::<Result<Vec<_>, _>>()?;
+ let owner = arm_owners[0];
+
+ if !arm_owners.into_iter().all(|o| self.equal(owner, o)) {
+ todo!("inconsistent case scrutinee set");
+ }
+
+ let Set::Variant(fields) = owner else {
+ panic!(
+ "invariant violation: looking up the owner of a variant field resulted in a non-variant set",
+ )
+ };
+ let mut required_field_names_sorted: Vec<String> =
+ fields.iter().map(|vf| vf.name.clone()).collect();
+ required_field_names_sorted.sort();
+ let mut covered_field_names_sorted: Vec<String> =
+ arms.iter().map(|ca| ca.tag.clone()).collect();
+ covered_field_names_sorted.sort();
+ if required_field_names_sorted != covered_field_names_sorted {
+ return Err(CheckerError::IncompleteCaseAnalysis {
+ found: covered_field_names_sorted,
+ required: required_field_names_sorted,
+ });
+ }
+ let scrutinee = self.check_element(scrutinee, owner)?;
+
+ let matching: Option<(String, Element)> = match scrutinee {
+ Element::Inject {
+ ref field,
+ element: ref inner,
+ } => Some((field.clone(), *inner.clone())),
+ Element::Var(_) | Element::Project { .. } | Element::Case { .. } => None,
+ Element::Literal(_) | Element::Record(_) => panic!(
+ "invariant violation: scrutinee is a non-variant value at variant set"
+ ),
+ };
+
+ let mut computed_output = None;
+ let mut processed_arms = Vec::new();
+ for arm in arms {
+ let Field {
+ field: field_set, ..
+ } = self.lookup_variant_field(&arm.tag)?;
+
+ let mut ctx = self.clone();
+ let binding_name = arm.bound.clone();
+ let binding_set = field_set.clone();
+
+ let case_arm = if let Some((tag, inner)) = &matching
+ && *tag == arm.tag
+ {
+ let canonical =
+ ctx.make_element_definition(binding_name, inner.clone(), binding_set)?;
+ let output = ctx.check_instance((&arm.body).into(), signature)?;
+ if matches!(computed_output, Some(_)) {
+ panic!(
+ "invariant violation: we somehow matched multiple arms in case analysis"
+ )
+ }
+ computed_output = Some(output.clone());
+ InstCaseArm {
+ tag: arm.tag.clone(),
+ bound: canonical,
+ body: output,
+ }
+ } else {
+ let canonical = ctx.make_element_binding(binding_name, binding_set)?;
+ let body = ctx.check_instance((&arm.body).into(), signature)?;
+ InstCaseArm {
+ tag: arm.tag.clone(),
+ bound: canonical,
+ body,
+ }
+ };
+
+ processed_arms.push(case_arm);
+ }
+ Ok(computed_output.unwrap_or(Instance::Case {
+ scrutinee: Box::new(scrutinee),
+ arms: processed_arms,
+ }))
+ }
Instance::For {
params: inst_params,
body,
@@ -372,7 +465,7 @@ impl CheckerState {
element: *element.clone(),
})
}
- Instance::Project { .. } | Instance::App(_, _) => {
+ Instance::Project { .. } | Instance::App(_, _) | Instance::Case { .. } => {
// it would appear that we are stuck here, so our only
// choice is to continue to be so
Ok(Instance::App(Box::new(inner), element.clone()))