@@ -32,6 +32,10 @@ impl Type {
32
32
Type :: Variable ( Rc :: new ( RefCell :: new ( Variable :: fresh ( level) ) ) )
33
33
}
34
34
35
+ pub fn unbound_variable ( id : usize , level : Level ) -> Type {
36
+ Type :: Variable ( Rc :: new ( RefCell :: new ( Variable :: Unbound ( id, level) ) ) )
37
+ }
38
+
35
39
// この型に含まれる current_level より大きいレベルの Variable を Quantified に変換した型を返す
36
40
pub fn generalize ( & self , current_level : Level ) -> Type {
37
41
match self {
@@ -116,14 +120,20 @@ impl Display for Type {
116
120
format ( b, f, false , names)
117
121
}
118
122
}
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) ,
124
135
}
125
- Variable :: Bound ( ref t) => format ( t, f, paren, names) ,
126
- } ,
136
+ }
127
137
Type :: Quantified ( id) => write ! ( f, "α{id}" ) ,
128
138
}
129
139
}
@@ -154,7 +164,7 @@ pub type Environment = im::HashMap<Symbol, Type>;
154
164
#[ derive( Debug , Clone , PartialEq , Eq , thiserror:: Error ) ]
155
165
pub enum TypeError {
156
166
#[ error( "failed to unify: {0} and {1}" ) ]
157
- FailedToUnify ( Type , Type ) ,
167
+ FailedToUnify ( String , String ) ,
158
168
159
169
#[ error( "undefined variable: {0}" ) ]
160
170
UndefinedVariable ( Symbol ) ,
@@ -190,7 +200,7 @@ pub fn unify(t1: &Type, t2: &Type) -> Result<(), TypeError> {
190
200
return Ok ( ( ) ) ;
191
201
}
192
202
193
- _ => return Err ( TypeError :: FailedToUnify ( t1. clone ( ) , t2. clone ( ) ) ) ,
203
+ _ => return Err ( TypeError :: FailedToUnify ( t1. to_string ( ) , t2. to_string ( ) ) ) ,
194
204
}
195
205
}
196
206
@@ -269,21 +279,65 @@ pub fn type_of(env: &Environment, expr: &Expr, level: Level) -> Result<Type, Typ
269
279
unify ( & fun_type1, & fun_type2) ?;
270
280
Ok ( ret_type)
271
281
}
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)
286
287
}
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
288
342
}
289
343
}
0 commit comments