Make Clause typing clearer
@@ -1768,10 +1768,13 @@ pub fn infer(expr: UntypedExpr, level: usize, env: &mut Env) -> Result<TypedExpr
fn infer_clause(
clause: UntypedClause,
- subject_types: &Vec<Type>,
+ subjects: &Vec<Type>,
level: usize,
env: &mut Env,
) -> Result<TypedClause, Error> {
+ // TODO: ensure variables used in the guard are defined in each every pattern
+ // TODO: ensure all defined variables have the same type
+
let Clause {
patterns: alternatives,
guard,
@@ -1779,40 +1782,15 @@ fn infer_clause(
meta,
} = clause;
- // TODO: ensure variables used in the guard are defined in each every pattern
- // TODO: ensure all defined variables have the same type
-
// Store the local scope so it can be reset after the clause
let vars = env.local_values.clone();
let mut typed_alternatives = Vec::new();
-
- for patterns in alternatives {
- if subject_types.len() != patterns.len() {
- return Err(Error::IncorrectNumClausePatterns {
- meta: meta,
- expected: subject_types.len(),
- given: patterns.len(),
- });
- }
-
- let mut typed_patterns = Vec::new();
- for (pattern, subject_type) in patterns.into_iter().zip(subject_types.iter()) {
- let pattern = unify_pattern(pattern, &subject_type, level, env)?;
- typed_patterns.push(pattern);
- }
-
- typed_alternatives.push(typed_patterns);
+ for m in alternatives {
+ typed_alternatives.push(infer_multi_pattern(m, subjects, level, &meta, env)?);
}
- let guard = guard
- .map(|guard| {
- let guard = infer_clause_guard(guard, level, env)?;
- unify(&bool(), guard.typ(), env).map_err(|e| convert_unify_error(e, guard.meta()))?;
- Ok(guard)
- })
- .transpose()?;
-
+ let guard = infer_guard(guard, level, env)?;
let then = infer(then, level, env)?;
// Reset the local vars now the clause scope is done
@@ -1826,6 +1804,44 @@ fn infer_clause(
})
}
+fn infer_guard(
+ guard: Option<UntypedClauseGuard>,
+ level: usize,
+ env: &mut Env,
+) -> Result<Option<TypedClauseGuard>, Error> {
+ match guard {
+ None => Ok(None),
+ Some(guard) => {
+ let guard = infer_clause_guard(guard, level, env)?;
+ unify(&bool(), guard.typ(), env).map_err(|e| convert_unify_error(e, guard.meta()))?;
+ Ok(Some(guard))
+ }
+ }
+}
+
+fn infer_multi_pattern(
+ multi_pattern: Vec<UntypedPattern>,
+ subjects: &Vec<Type>,
+ level: usize,
+ meta: &Meta,
+ env: &mut Env,
+) -> Result<Vec<TypedPattern>, Error> {
+ if subjects.len() != multi_pattern.len() {
+ return Err(Error::IncorrectNumClausePatterns {
+ meta: meta.clone(),
+ expected: subjects.len(),
+ given: multi_pattern.len(),
+ });
+ }
+
+ let mut typed_patterns = Vec::new();
+ for (pattern, subject_type) in multi_pattern.into_iter().zip(subjects.iter()) {
+ let pattern = unify_pattern(pattern, &subject_type, level, env)?;
+ typed_patterns.push(pattern);
+ }
+ Ok(typed_patterns)
+}
+
fn infer_clause_guard(
guard: UntypedClauseGuard,
level: usize,
