inference and tests

This commit is contained in:
pca006132 2020-12-28 14:33:18 +08:00 committed by pca006132
parent 7f09596bcb
commit 929b7e1d92
4 changed files with 220 additions and 8 deletions

View File

@ -169,3 +169,208 @@ pub fn resolve_call(
}
}))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::primitives::*;
#[test]
fn test_simple_generic() {
let mut ctx = basic_ctx();
let mut assumptions = HashMap::new();
assert_eq!(
resolve_call(
&ctx,
None,
"int32",
create_tuple(vec![PrimitiveType(FLOAT_TYPE).into()]),
&mut assumptions
),
Ok(Some(PrimitiveType(INT32_TYPE).into()))
);
assert_eq!(
resolve_call(
&ctx,
None,
"int32",
create_tuple(vec![PrimitiveType(INT32_TYPE).into()]),
&mut assumptions
),
Ok(Some(PrimitiveType(INT32_TYPE).into()))
);
assert_eq!(
resolve_call(
&ctx,
None,
"float",
create_tuple(vec![PrimitiveType(INT32_TYPE).into()]),
&mut assumptions
),
Ok(Some(PrimitiveType(FLOAT_TYPE).into()))
);
assert_eq!(
resolve_call(
&ctx,
None,
"float",
create_tuple(vec![PrimitiveType(BOOL_TYPE).into()]),
&mut assumptions
),
Err("different domain".to_string())
);
let v1 = ctx.add_variable(VarDef {
name: "V1",
bound: vec![
PrimitiveType(INT32_TYPE).into(),
PrimitiveType(FLOAT_TYPE).into(),
],
});
assert_eq!(
resolve_call(
&ctx,
None,
"float",
create_tuple(vec![TypeVariable(v1).into()]),
&mut assumptions
),
Ok(Some(PrimitiveType(FLOAT_TYPE).into()))
);
let v2 = ctx.add_variable(VarDef {
name: "V2",
bound: vec![
PrimitiveType(BOOL_TYPE).into(),
PrimitiveType(INT32_TYPE).into(),
PrimitiveType(FLOAT_TYPE).into(),
],
});
assert_eq!(
resolve_call(
&ctx,
None,
"float",
create_tuple(vec![TypeVariable(v2).into()]),
&mut assumptions
),
Err("different domain".to_string())
);
}
#[test]
fn test_methods() {
let mut ctx = basic_ctx();
let mut assumptions = HashMap::new();
let v1 = Rc::new(TypeVariable(ctx.add_variable(VarDef {
name: "V1",
bound: vec![
PrimitiveType(INT32_TYPE).into(),
PrimitiveType(FLOAT_TYPE).into(),
],
})));
let v2 = Rc::new(TypeVariable(ctx.add_variable(VarDef {
name: "V2",
bound: vec![
PrimitiveType(INT32_TYPE).into(),
PrimitiveType(FLOAT_TYPE).into(),
],
})));
let v3 = Rc::new(TypeVariable(ctx.add_variable(VarDef {
name: "V3",
bound: vec![
PrimitiveType(BOOL_TYPE).into(),
PrimitiveType(INT32_TYPE).into(),
PrimitiveType(FLOAT_TYPE).into(),
],
})));
let int32 = Rc::new(PrimitiveType(INT32_TYPE));
let int64 = Rc::new(PrimitiveType(INT64_TYPE));
// simple cases
assert_eq!(
resolve_call(
&ctx,
Some(int32.clone()),
"__add__",
create_tuple(vec![int32.clone()]),
&mut assumptions
),
Ok(Some(int32.clone()))
);
assert_ne!(
resolve_call(
&ctx,
Some(int32.clone()),
"__add__",
create_tuple(vec![int32.clone()]),
&mut assumptions
),
Ok(Some(int64.clone()))
);
assert_eq!(
resolve_call(
&ctx,
Some(int32.clone()),
"__add__",
create_tuple(vec![int64.clone()]),
&mut assumptions
),
Err("not equal".to_string())
);
// with type variables
assert_eq!(
resolve_call(
&ctx,
Some(v1.clone()),
"__add__",
create_tuple(vec![v1.clone()]),
&mut assumptions
),
Ok(Some(v1.clone()))
);
assert_eq!(
resolve_call(
&ctx,
Some(v1.clone()),
"__add__",
create_tuple(vec![v2.clone()]),
&mut assumptions
),
Err("different domain".to_string())
);
assert_eq!(
resolve_call(
&ctx,
Some(v3.clone()),
"__add__",
create_tuple(vec![v1.clone()]),
&mut assumptions
),
Err("no such function".to_string())
);
assert_eq!(
resolve_call(
&ctx,
Some(v3.clone()),
"__add__",
create_tuple(vec![v3.clone()]),
&mut assumptions
),
Err("no such function".to_string())
);
}
}

View File

@ -1,6 +1,6 @@
extern crate rustpython_parser;
mod types;
mod inference;
mod primitives;
pub mod types;
pub mod inference;
pub mod primitives;

View File

@ -13,7 +13,7 @@ pub const FLOAT_TYPE: PrimitiveId = PrimitiveId(3);
fn impl_math(def: &mut TypeDef, ty: &Rc<Type>) {
let bin = Rc::new(ParametricType(
TUPLE_TYPE,
vec![SelfType.into(), ty.clone()],
vec![ty.clone()],
));
let result = Some(ty.clone());
let fun = FnDef {
@ -39,7 +39,7 @@ fn impl_math(def: &mut TypeDef, ty: &Rc<Type>) {
fn impl_bits(def: &mut TypeDef, ty: &Rc<Type>) {
let bin = Rc::new(ParametricType(
TUPLE_TYPE,
vec![SelfType.into(), PrimitiveType(INT32_TYPE).into()],
vec![PrimitiveType(INT32_TYPE).into()],
));
let result = Some(ty.clone());
let fun = FnDef {
@ -52,7 +52,7 @@ fn impl_bits(def: &mut TypeDef, ty: &Rc<Type>) {
def.methods.insert(
"__xor__",
FnDef {
args: ParametricType(TUPLE_TYPE, vec![SelfType.into(), ty.clone()]).into(),
args: ParametricType(TUPLE_TYPE, vec![ty.clone()]).into(),
result: Some(ty.clone()),
},
);
@ -61,7 +61,7 @@ fn impl_bits(def: &mut TypeDef, ty: &Rc<Type>) {
fn impl_eq(def: &mut TypeDef, ty: &Rc<Type>) {
let bin = Rc::new(ParametricType(
TUPLE_TYPE,
vec![SelfType.into(), ty.clone()],
vec![ty.clone()],
));
let fun = FnDef {
args: bin.clone(),
@ -75,7 +75,7 @@ fn impl_eq(def: &mut TypeDef, ty: &Rc<Type>) {
fn impl_order(def: &mut TypeDef, ty: &Rc<Type>) {
let bin = Rc::new(ParametricType(
TUPLE_TYPE,
vec![SelfType.into(), ty.clone()],
vec![ty.clone()],
));
let fun = FnDef {
args: bin.clone(),
@ -88,6 +88,10 @@ fn impl_order(def: &mut TypeDef, ty: &Rc<Type>) {
def.methods.insert("__ge__", fun.clone());
}
pub fn create_tuple(tys: Vec<Rc<Type>>) -> Rc<Type> {
ParametricType(TUPLE_TYPE, tys).into()
}
pub fn basic_ctx() -> GlobalContext<'static> {
let primitives = [
TypeDef {

View File

@ -26,6 +26,8 @@ pub enum Type {
#[derive(Clone)]
pub struct FnDef {
// we assume methods first argument to be SelfType,
// so the first argument is not contained here
pub args: Rc<Type>,
pub result: Option<Rc<Type>>,
}
@ -209,3 +211,4 @@ impl Type {
}
}
}