Skip to content

Commit

Permalink
Detect cycles in a substitution
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordan Mackie committed Jan 3, 2023
1 parent 0927d59 commit 76f8ad3
Showing 1 changed file with 20 additions and 2 deletions.
22 changes: 20 additions & 2 deletions crates/ditto-checker/src/typechecker/substitution.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::common::type_variables;
use ditto_ast::{Argument, Effect, Expression, Kind, LetValueDeclaration, Type};
use ditto_ast::{graph, Argument, Effect, Expression, Kind, LetValueDeclaration, Type};
use non_empty_vec::NonEmpty;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};

#[derive(Debug, Default)]
#[repr(transparent)]
Expand All @@ -12,6 +12,9 @@ impl Substitution {
self.0.insert(var, ast_type);
}
pub fn apply(&self, ast_type: Type) -> Type {
if self.has_cycles() {
panic!("Cycles detected in substitution: {:#?}", self)
}
self.apply_rec(ast_type, 0)
}
fn apply_rec(&self, ast_type: Type, depth: usize) -> Type {
Expand Down Expand Up @@ -486,4 +489,19 @@ impl Substitution {
_ => var,
}
}
fn has_cycles(&self) -> bool {
let sccs = graph::toposort(
self.0.values().flat_map(type_variables).collect(),
|var| *var, // Copy
|var| {
if let Some(t) = self.0.get(var) {
type_variables(t).into_iter().collect::<HashSet<_>>()
} else {
HashSet::new()
}
},
);
sccs.into_iter()
.any(|scc| matches!(scc, graph::Scc::Cyclic(_)))
}
}

0 comments on commit 76f8ad3

Please sign in to comment.