virtual class tests

This commit is contained in:
pca006132 2020-12-28 15:58:28 +08:00 committed by pca006132
parent 87dd0ee3cb
commit 75183c39fd

View File

@ -77,8 +77,7 @@ fn find_subst(
parents = [*id_a].to_vec(); parents = [*id_a].to_vec();
} }
VirtualClassType(id_a) => { VirtualClassType(id_a) => {
let a = ctx.get_class(*id_a); parents = [*id_a].to_vec();
parents = a.parents.clone();
} }
_ => { _ => {
return Err("cannot substitute non-class type into virtual class".to_string()); return Err("cannot substitute non-class type into virtual class".to_string());
@ -486,4 +485,232 @@ mod tests {
Err("different variables".to_string()) 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())
);
}
} }