aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/checker_signature.rs191
-rw-r--r--src/parser.rs18
2 files changed, 138 insertions, 71 deletions
diff --git a/src/checker_signature.rs b/src/checker_signature.rs
index 2d5057f..42a581f 100644
--- a/src/checker_signature.rs
+++ b/src/checker_signature.rs
@@ -394,88 +394,143 @@ impl CheckerState {
// signature = None, and in this mode all we want is to put
// inner into a canonical form pushing stuck terms to the leaves
// and simplifying everything else.
- let inner = self.check_instance(inner, None)?;
- println!("HERE {:?}, {:?}", inner, args);
- match &inner {
- Instance::Var(v) => {
- println!("VAR {}", v);
- let field = self.lookup_signature_field(&v)?;
- let Signature::Ext {
- ref params,
- ref codomain,
- } = field.field
- else {
+ let subject = self.check_instance(inner, None)?;
+
+ // the whole game here is to make sure that we have no left
+ // nesting, and that we're fully evaluated. If that's true then
+ // we don't need to come up with signatures for partial
+ // application. The parser already enforces this, but the
+ // cunning user may supply ASTs directly so we do this here as
+ // well.
+ let (subject, args) = match subject {
+ Instance::App {
+ instance: inner_inner,
+ args: inner_args,
+ } => {
+ let mut merged = inner_args;
+ merged.extend(args.iter().cloned());
+ return self.check_instance(
+ &Instance::App {
+ instance: inner_inner,
+ args: merged,
+ },
+ signature,
+ );
+ }
+ other => (other, args.clone()),
+ };
+
+ let subject_sig: Option<Signature> = match &subject {
+ Instance::Var(v) => Some(self.lookup_instance(v)?.container.clone()),
+ Instance::Project { field, .. } => {
+ Some(self.lookup_signature_field(field)?.field.clone())
+ }
+ // TODO: i think we need to handle case here
+ Instance::App { .. }
+ | Instance::Record(_)
+ | Instance::SetCoerce(_)
+ | Instance::For { .. }
+ | Instance::Case { .. } => None,
+ };
+
+ if let Some(subject_sig) = subject_sig {
+ let Signature::Ext { params, codomain } = subject_sig else {
+ return Err(CheckerError::NonFunctionalInstance {
+ instance: subject,
+ elements: args,
+ });
+ };
+ let (ctx, checked_args) = self._bind_args(&params, &args)?;
+
+ if let Some(expected) = signature {
+ let result_sig = if args.len() == params.len() {
+ ctx.check_signature(&codomain)?
+ } else {
+ let remaining: Vec<Param> = params[args.len()..]
+ .iter()
+ .map(|p| {
+ let s = ctx.check_set(&p.set)?;
+ Ok(Param {
+ name: p.name.clone(),
+ set: s,
+ })
+ })
+ .collect::<Result<_, CheckerError>>()?;
+ let cod = ctx.check_signature(&codomain)?;
+ Signature::Ext {
+ params: remaining,
+ codomain: Box::new(cod),
+ }
+ };
+ if !self.equal(expected, &result_sig) {
return Err(CheckerError::WrongSignatureForInstance {
- value: inner.clone().into(),
- claimed: Signature::Ext {
- params: vec![Param {
- name: "...".to_string(),
- set: Set::Var("...".to_string()),
- }],
- codomain: Box::new(Signature::Var("...".to_string())),
- },
- real: field.owner.clone(),
+ value: subject.clone().into(),
+ claimed: expected.clone(),
+ real: result_sig,
});
- };
- if params.is_empty() {
- panic!(
- "It should have been impossible to construct an Ext with no params, but here we are"
- );
- }
- if let Some(signature) = signature {
- if !self.equal(&**codomain, signature) {
- return Err(CheckerError::WrongSignatureForInstance {
- value: instance.clone().into(),
- claimed: signature.clone(),
- real: *codomain.clone(),
- });
- }
}
- todo!("finish")
- // let element = self.check_element(args, &params[0].set)?;
- // Ok(Instance::App(
- // Box::new(Instance::Var(v.clone())),
- // Box::new(element),
- // ))
}
+
+ return Ok(Instance::App {
+ instance: Box::new(subject),
+ args: checked_args,
+ });
+ }
+
+ match subject {
Instance::For { params, body } => {
- if params.is_empty() {
- panic!(
- "it should have been impossible to construct a for with no parameters, but here we are"
- );
+ let (ctx, _checked) = self._bind_args(&params, &args)?;
+ if args.len() == params.len() {
+ ctx.check_instance(&body, signature)
+ } else {
+ let residual = Instance::For {
+ params: params[args.len()..].to_vec(),
+ body,
+ };
+ ctx.check_instance(&residual, signature)
}
- let mut ctx = self.clone();
- let first_set = ctx.check_set(&params[0].set)?;
- todo!("finish this")
- // let element_checked = self.check_element(args, &first_set)?;
- // ctx.add_element(params[0].name.clone(), element_checked.into(), first_set)?;
- // if params.len() == 1 {
- // ctx.check_instance(body, signature)
- // } else {
- // let residual = Instance::For {
- // params: params[1..].to_vec(),
- // body: body.clone(),
- // };
- // ctx.check_instance(&residual, signature)
- // }
}
Instance::Record(_) | Instance::SetCoerce(_) => {
Err(CheckerError::NonFunctionalInstance {
- instance: inner,
- elements: args.clone(),
+ instance: subject,
+ elements: args,
})
}
- Instance::Project { .. } | Instance::App { .. } | Instance::Case { .. } => {
- println!("Stuck");
- // it would appear that we are stuck here, so our only
- // choice is to continue to be so
- Ok(Instance::App {
- instance: Box::new(inner),
- args: args.clone(),
- })
+ Instance::Case { .. } => {
+ todo!("App applied to a Case instance?");
+ }
+ Instance::Var(_) | Instance::Project { .. } => {
+ unreachable!("handled in the stuck-head branch above")
+ }
+ Instance::App { .. } => {
+ unreachable!("handled by the merge-and-recurse branch above")
}
}
}
}
}
+
+ fn _bind_args(
+ &self,
+ params: &[Param],
+ args: &[Element],
+ ) -> Result<(CheckerState, Vec<Element>), CheckerError> {
+ if args.len() > params.len() {
+ todo!(
+ "over-application: {} args to a function of arity {}",
+ args.len(),
+ params.len()
+ );
+ }
+ let mut ctx = self.clone();
+ let checked = zip(params.iter(), args.iter())
+ .map(|(p, a)| {
+ let p_set = ctx.check_set(&p.set)?;
+ let a = ctx.check_element(a, &p_set)?;
+ ctx.add_element(p.name.clone(), a.clone().into(), p_set)?;
+ Ok(a)
+ })
+ .collect::<Result<Vec<_>, _>>()?;
+ Ok((ctx, checked))
+ }
}
diff --git a/src/parser.rs b/src/parser.rs
index ecf6ab3..285bb84 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -227,9 +227,21 @@ parser! {
}
rule app_inst() -> Instance
- = head:dot_inst() args:(__ a:dot_elem() { a })*
- { if args.is_empty() { head } else { Instance::App{instance: Box::new(head), args } }}
-
+ = subject:dot_inst() args:(__ a:dot_elem() { a })*
+ {
+ if args.is_empty() {
+ subject
+ } else {
+ match subject {
+ Instance::App { instance: inner_head, args: inner_args } => {
+ let mut all_args = inner_args;
+ all_args.extend(args);
+ Instance::App { instance: inner_head, args: all_args }
+ }
+ other => Instance::App { instance: Box::new(other), args },
+ }
+ }
+ }
rule instance() -> Instance
= kw_for() _ ps:param_list() _ "," _ body:instance()