diff --git a/nac3type/src/inference.rs b/nac3type/src/inference.rs index f37c383570..0cd2270070 100644 --- a/nac3type/src/inference.rs +++ b/nac3type/src/inference.rs @@ -77,8 +77,7 @@ fn find_subst( parents = [*id_a].to_vec(); } VirtualClassType(id_a) => { - let a = ctx.get_class(*id_a); - parents = a.parents.clone(); + parents = [*id_a].to_vec(); } _ => { return Err("cannot substitute non-class type into virtual class".to_string()); @@ -486,4 +485,232 @@ mod tests { Err("different variables".to_string()) ); } + + #[test] + fn test_class_generics() { + let mut ctx = basic_ctx(); + let mut assumptions = HashMap::new(); + + let list = ctx.get_parametric_mut(LIST_TYPE); + let t = Rc::new(TypeVariable(list.params[0])); + list.base.methods.insert("head", FnDef { + args: create_tuple(vec![]), + result: Some(t.clone()) + }); + list.base.methods.insert("append", FnDef { + args: create_tuple(vec![t.clone()]), + result: None + }); + + let v0 = Rc::new(TypeVariable(ctx.add_variable(VarDef { + name: "V0", + bound: vec![], + }))); + let v1 = Rc::new(TypeVariable(ctx.add_variable(VarDef { + name: "V1", + bound: vec![], + }))); + + assert_eq!( + resolve_call( + &ctx, + Some(ParametricType(LIST_TYPE, vec![v0.clone()]).into()), + "head", + create_tuple(vec![]), + &mut assumptions + ), + Ok(Some(v0.clone())) + ); + assert_eq!( + resolve_call( + &ctx, + Some(ParametricType(LIST_TYPE, vec![v0.clone()]).into()), + "append", + create_tuple(vec![v0.clone()]), + &mut assumptions + ), + Ok(None) + ); + assert_eq!( + resolve_call( + &ctx, + Some(ParametricType(LIST_TYPE, vec![v0.clone()]).into()), + "append", + create_tuple(vec![v1.clone()]), + &mut assumptions + ), + Err("different variables".to_string()) + ); + + } + + #[test] + fn test_virtual_class() { + let mut ctx = basic_ctx(); + let mut assumptions = HashMap::new(); + + let foo = ctx.add_class(ClassDef { + base: TypeDef { + name: "Foo", + methods: HashMap::new(), + fields: HashMap::new() + }, + parents: vec![] + }); + + let foo1 = ctx.add_class(ClassDef { + base: TypeDef { + name: "Foo1", + methods: HashMap::new(), + fields: HashMap::new() + }, + parents: vec![foo] + }); + + let foo2 = ctx.add_class(ClassDef { + base: TypeDef { + name: "Foo2", + methods: HashMap::new(), + fields: HashMap::new() + }, + parents: vec![foo1] + }); + + let bar = ctx.add_class(ClassDef { + base: TypeDef { + name: "bar", + methods: HashMap::new(), + fields: HashMap::new() + }, + parents: vec![] + }); + + ctx.add_fn("foo", FnDef { + args: create_tuple(vec![VirtualClassType(foo).into()]), + result: None + }); + ctx.add_fn("foo1", FnDef { + args: create_tuple(vec![VirtualClassType(foo1).into()]), + result: None + }); + + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![ClassType(foo).into()]), + &mut assumptions + ), + Ok(None) + ); + + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![ClassType(foo1).into()]), + &mut assumptions + ), + Ok(None) + ); + + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![ClassType(foo2).into()]), + &mut assumptions + ), + Ok(None) + ); + + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![ClassType(bar).into()]), + &mut assumptions + ), + Err("not subtype".to_string()) + ); + + assert_eq!( + resolve_call( + &ctx, + None, + "foo1", + create_tuple(vec![ClassType(foo1).into()]), + &mut assumptions + ), + Ok(None) + ); + + assert_eq!( + resolve_call( + &ctx, + None, + "foo1", + create_tuple(vec![ClassType(foo2).into()]), + &mut assumptions + ), + Ok(None) + ); + + assert_eq!( + resolve_call( + &ctx, + None, + "foo1", + create_tuple(vec![ClassType(foo).into()]), + &mut assumptions + ), + Err("not subtype".to_string()) + ); + + // virtual class substitution + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![VirtualClassType(foo).into()]), + &mut assumptions + ), + Ok(None) + ); + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![VirtualClassType(foo1).into()]), + &mut assumptions + ), + Ok(None) + ); + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![VirtualClassType(foo2).into()]), + &mut assumptions + ), + Ok(None) + ); + assert_eq!( + resolve_call( + &ctx, + None, + "foo", + create_tuple(vec![VirtualClassType(bar).into()]), + &mut assumptions + ), + Err("not subtype".to_string()) + ); + } }