Skip to content

Commit f5ed236

Browse files
committed
Bug fix
1 parent 6a850c5 commit f5ed236

File tree

1 file changed

+78
-24
lines changed

1 file changed

+78
-24
lines changed

algorithm-w/src/typing.rs

+78-24
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ impl Type {
3232
Type::Variable(Rc::new(RefCell::new(Variable::fresh(level))))
3333
}
3434

35+
pub fn unbound_variable(id: usize, level: Level) -> Type {
36+
Type::Variable(Rc::new(RefCell::new(Variable::Unbound(id, level))))
37+
}
38+
3539
// この型に含まれる current_level より大きいレベルの Variable を Quantified に変換した型を返す
3640
pub fn generalize(&self, current_level: Level) -> Type {
3741
match self {
@@ -116,14 +120,20 @@ impl Display for Type {
116120
format(b, f, false, names)
117121
}
118122
}
119-
Type::Variable(v) => match *v.borrow() {
120-
Variable::Unbound(id, _) => {
121-
let name = generate_name(names.len());
122-
names.insert(id, name.clone());
123-
name.fmt(f)
123+
Type::Variable(v) => {
124+
let n = names.len();
125+
match *v.borrow() {
126+
Variable::Unbound(id, _) => match names.entry(id) {
127+
Entry::Occupied(entry) => entry.get().fmt(f),
128+
Entry::Vacant(entry) => {
129+
let name = generate_name(n);
130+
entry.insert(name.clone());
131+
name.fmt(f)
132+
}
133+
},
134+
Variable::Bound(ref t) => format(t, f, paren, names),
124135
}
125-
Variable::Bound(ref t) => format(t, f, paren, names),
126-
},
136+
}
127137
Type::Quantified(id) => write!(f, "α{id}"),
128138
}
129139
}
@@ -154,7 +164,7 @@ pub type Environment = im::HashMap<Symbol, Type>;
154164
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
155165
pub enum TypeError {
156166
#[error("failed to unify: {0} and {1}")]
157-
FailedToUnify(Type, Type),
167+
FailedToUnify(String, String),
158168

159169
#[error("undefined variable: {0}")]
160170
UndefinedVariable(Symbol),
@@ -190,7 +200,7 @@ pub fn unify(t1: &Type, t2: &Type) -> Result<(), TypeError> {
190200
return Ok(());
191201
}
192202

193-
_ => return Err(TypeError::FailedToUnify(t1.clone(), t2.clone())),
203+
_ => return Err(TypeError::FailedToUnify(t1.to_string(), t2.to_string())),
194204
}
195205
}
196206

@@ -269,21 +279,65 @@ pub fn type_of(env: &Environment, expr: &Expr, level: Level) -> Result<Type, Typ
269279
unify(&fun_type1, &fun_type2)?;
270280
Ok(ret_type)
271281
}
272-
Expr::Let(name, expr1, expr2, let_type) => {
273-
match let_type {
274-
LetType::Normal => {
275-
let expr1_type = type_of(env, expr1, level + 1)?;
276-
let expr2_env = env.update(*name, expr1_type.generalize(level));
277-
type_of(&expr2_env, expr2, level)
278-
}
279-
LetType::Rec => {
280-
let t = Type::fresh(level);
281-
let expr1_env = env.update(*name, t.clone());
282-
let expr1_type = type_of(&expr1_env, expr1, level + 1)?;
283-
unify(&t, &expr1_type)?;
284-
type_of(&expr1_env, expr2, level)
285-
}
282+
Expr::Let(name, expr1, expr2, let_type) => match let_type {
283+
LetType::Normal => {
284+
let expr1_type = type_of(env, expr1, level + 1)?;
285+
let expr2_env = env.update(*name, expr1_type.generalize(level));
286+
type_of(&expr2_env, expr2, level)
286287
}
287-
}
288+
LetType::Rec => {
289+
let t = Type::fresh(level);
290+
let expr1_env = env.update(*name, t.clone());
291+
let expr1_type = type_of(&expr1_env, expr1, level + 1)?;
292+
unify(&t, &expr1_type)?;
293+
type_of(&expr1_env, expr2, level)
294+
}
295+
},
296+
}
297+
}
298+
299+
#[cfg(test)]
300+
mod tests {
301+
use crate::typing::{bool, int, Type};
302+
303+
use super::type_of;
304+
305+
fn check(input: &str, expected: &str) -> anyhow::Result<()> {
306+
let env = im::hashmap! {
307+
"succ".into() => Type::Function(Box::new(int()), Box::new(int())),
308+
"iszero".into() => Type::Function(Box::new(int()), Box::new(bool())),
309+
};
310+
let token_and_spans = crate::lexer::lex(input)?;
311+
let tokens: Vec<_> = token_and_spans.into_iter().map(|(t, _)| t).collect();
312+
let ast = crate::parser::parse(&tokens)?;
313+
let t = type_of(&env, &ast, 0)?;
314+
assert_eq!(t.to_string(), expected, "input: {input}");
315+
Ok(())
316+
}
317+
318+
#[test]
319+
fn test_type_of() -> anyhow::Result<()> {
320+
check("0", "Int")?;
321+
check("true", "Bool")?;
322+
check("1 + 2", "Int")?;
323+
check("0 == 0", "Bool")?;
324+
check("if 0 == 0 then 1 else 0", "Int")?;
325+
check("if iszero 0 then 1 else 0", "Int")?;
326+
check("[x] x", "a -> a")?;
327+
Ok(())
328+
}
329+
330+
#[test]
331+
fn test_type_generalize() {
332+
let t = Type::unbound_variable(42, 1);
333+
assert_eq!(t.generalize(0), Type::Quantified(42));
334+
// TODO
335+
}
336+
337+
#[test]
338+
fn test_type_instanciate() {
339+
let t = Type::Quantified(42);
340+
assert_eq!(t.instanciate(0).to_string(), "a");
341+
// TODO
288342
}
289343
}

0 commit comments

Comments
 (0)