2021-07-21 15:36:35 +08:00
|
|
|
use super::super::typedef::*;
|
|
|
|
use super::*;
|
2021-08-07 10:28:41 +08:00
|
|
|
use crate::symbol_resolver::*;
|
2021-08-24 17:43:41 +08:00
|
|
|
use crate::{
|
|
|
|
location::Location,
|
|
|
|
toplevel::{DefinitionId, TopLevelDef},
|
|
|
|
};
|
2021-07-21 15:36:35 +08:00
|
|
|
use indoc::indoc;
|
2021-07-27 11:58:35 +08:00
|
|
|
use itertools::zip;
|
2021-08-11 17:28:29 +08:00
|
|
|
use parking_lot::RwLock;
|
2021-07-21 15:36:35 +08:00
|
|
|
use rustpython_parser::parser::parse_program;
|
|
|
|
use test_case::test_case;
|
|
|
|
|
|
|
|
struct Resolver {
|
2021-08-11 17:28:29 +08:00
|
|
|
id_to_type: HashMap<String, Type>,
|
|
|
|
id_to_def: HashMap<String, DefinitionId>,
|
2021-07-27 11:58:35 +08:00
|
|
|
class_names: HashMap<String, Type>,
|
2021-07-21 15:36:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SymbolResolver for Resolver {
|
2021-08-11 17:28:29 +08:00
|
|
|
fn get_symbol_type(&self, _: &mut Unifier, _: &PrimitiveStore, str: &str) -> Option<Type> {
|
|
|
|
self.id_to_type.get(str).cloned()
|
2021-07-21 15:36:35 +08:00
|
|
|
}
|
|
|
|
|
2021-08-10 10:33:18 +08:00
|
|
|
fn get_symbol_value(&self, _: &str) -> Option<SymbolValue> {
|
2021-07-21 15:36:35 +08:00
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
|
2021-08-10 10:33:18 +08:00
|
|
|
fn get_symbol_location(&self, _: &str) -> Option<Location> {
|
2021-07-21 15:36:35 +08:00
|
|
|
unimplemented!()
|
|
|
|
}
|
2021-08-03 13:38:27 +08:00
|
|
|
|
2021-08-12 10:25:32 +08:00
|
|
|
fn get_identifier_def(&self, id: &str) -> Option<DefinitionId> {
|
|
|
|
self.id_to_def.get(id).cloned()
|
2021-08-03 13:38:27 +08:00
|
|
|
}
|
2021-07-21 15:36:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
struct TestEnvironment {
|
|
|
|
pub unifier: Unifier,
|
2021-07-28 17:25:19 +08:00
|
|
|
pub function_data: FunctionData,
|
2021-07-21 15:36:35 +08:00
|
|
|
pub primitives: PrimitiveStore,
|
|
|
|
pub id_to_name: HashMap<usize, String>,
|
2021-07-22 17:07:49 +08:00
|
|
|
pub identifier_mapping: HashMap<String, Type>,
|
2021-07-27 11:58:35 +08:00
|
|
|
pub virtual_checks: Vec<(Type, Type)>,
|
2021-08-13 13:33:59 +08:00
|
|
|
pub calls: HashMap<CodeLocation, CallId>,
|
2021-08-11 17:28:29 +08:00
|
|
|
pub top_level: TopLevelContext,
|
2021-07-21 15:36:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl TestEnvironment {
|
2021-07-30 15:40:14 +08:00
|
|
|
pub fn basic_test_env() -> TestEnvironment {
|
2021-07-29 15:36:19 +08:00
|
|
|
let mut unifier = Unifier::new();
|
2021-08-03 13:38:27 +08:00
|
|
|
|
2021-07-29 15:36:19 +08:00
|
|
|
let int32 = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(0),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-29 15:36:19 +08:00
|
|
|
});
|
|
|
|
let int64 = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(1),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-29 15:36:19 +08:00
|
|
|
});
|
|
|
|
let float = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(2),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-29 15:36:19 +08:00
|
|
|
});
|
|
|
|
let bool = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(3),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-29 15:36:19 +08:00
|
|
|
});
|
|
|
|
let none = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(4),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-29 15:36:19 +08:00
|
|
|
});
|
|
|
|
let primitives = PrimitiveStore { int32, int64, float, bool, none };
|
2021-08-04 12:03:56 +08:00
|
|
|
set_primitives_magic_methods(&primitives, &mut unifier);
|
2021-08-03 13:38:27 +08:00
|
|
|
|
2021-07-30 15:40:14 +08:00
|
|
|
let id_to_name = [
|
|
|
|
(0, "int32".to_string()),
|
|
|
|
(1, "int64".to_string()),
|
|
|
|
(2, "float".to_string()),
|
|
|
|
(3, "bool".to_string()),
|
|
|
|
(4, "none".to_string()),
|
|
|
|
]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let mut identifier_mapping = HashMap::new();
|
|
|
|
identifier_mapping.insert("None".into(), none);
|
2021-08-03 13:38:27 +08:00
|
|
|
|
2021-08-25 15:30:36 +08:00
|
|
|
let resolver = Arc::new(Box::new(Resolver {
|
2021-08-11 17:28:29 +08:00
|
|
|
id_to_type: identifier_mapping.clone(),
|
|
|
|
id_to_def: Default::default(),
|
2021-08-03 13:38:27 +08:00
|
|
|
class_names: Default::default(),
|
2021-08-25 15:30:36 +08:00
|
|
|
}) as Box<dyn SymbolResolver + Send + Sync>);
|
2021-07-29 15:36:19 +08:00
|
|
|
|
2021-07-30 15:40:14 +08:00
|
|
|
TestEnvironment {
|
2021-08-11 17:28:29 +08:00
|
|
|
top_level: TopLevelContext {
|
|
|
|
definitions: Default::default(),
|
|
|
|
unifiers: Default::default(),
|
|
|
|
},
|
2021-07-30 15:40:14 +08:00
|
|
|
unifier,
|
|
|
|
function_data: FunctionData {
|
|
|
|
resolver,
|
|
|
|
bound_variables: Vec::new(),
|
2021-08-03 13:38:27 +08:00
|
|
|
return_type: None,
|
2021-07-30 15:40:14 +08:00
|
|
|
},
|
|
|
|
primitives,
|
|
|
|
id_to_name,
|
|
|
|
identifier_mapping,
|
|
|
|
virtual_checks: Vec::new(),
|
2021-07-30 15:46:57 +08:00
|
|
|
calls: HashMap::new(),
|
2021-07-30 15:40:14 +08:00
|
|
|
}
|
2021-07-29 15:36:19 +08:00
|
|
|
}
|
|
|
|
|
2021-07-21 15:36:35 +08:00
|
|
|
fn new() -> TestEnvironment {
|
|
|
|
let mut unifier = Unifier::new();
|
2021-07-22 17:07:49 +08:00
|
|
|
let mut identifier_mapping = HashMap::new();
|
2021-08-18 10:01:11 +08:00
|
|
|
let mut top_level_defs: Vec<Arc<RwLock<TopLevelDef>>> = Vec::new();
|
2021-07-21 15:36:35 +08:00
|
|
|
let int32 = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(0),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-21 15:36:35 +08:00
|
|
|
});
|
|
|
|
let int64 = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(1),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-21 15:36:35 +08:00
|
|
|
});
|
|
|
|
let float = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(2),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-21 15:36:35 +08:00
|
|
|
});
|
|
|
|
let bool = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(3),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-21 15:36:35 +08:00
|
|
|
});
|
|
|
|
let none = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(4),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: HashMap::new().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: HashMap::new().into(),
|
2021-07-21 15:36:35 +08:00
|
|
|
});
|
2021-07-22 17:07:49 +08:00
|
|
|
identifier_mapping.insert("None".into(), none);
|
2021-08-21 14:51:46 +08:00
|
|
|
for (i, name) in ["int32", "int64", "float", "bool", "none"].iter().enumerate() {
|
2021-08-18 16:33:50 +08:00
|
|
|
top_level_defs.push(
|
|
|
|
RwLock::new(TopLevelDef::Class {
|
2021-08-25 15:30:36 +08:00
|
|
|
name: name.to_string(),
|
2021-08-18 16:33:50 +08:00
|
|
|
object_id: DefinitionId(i),
|
|
|
|
type_vars: Default::default(),
|
|
|
|
fields: Default::default(),
|
|
|
|
methods: Default::default(),
|
|
|
|
ancestors: Default::default(),
|
|
|
|
resolver: None,
|
|
|
|
})
|
|
|
|
.into(),
|
|
|
|
);
|
2021-08-11 17:28:29 +08:00
|
|
|
}
|
2021-07-21 15:36:35 +08:00
|
|
|
|
2021-07-27 11:58:35 +08:00
|
|
|
let primitives = PrimitiveStore { int32, int64, float, bool, none };
|
2021-07-21 15:36:35 +08:00
|
|
|
|
|
|
|
let (v0, id) = unifier.get_fresh_var();
|
2021-07-21 15:59:01 +08:00
|
|
|
|
|
|
|
let foo_ty = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(5),
|
2021-08-02 17:36:37 +08:00
|
|
|
fields: [("a".into(), v0)].iter().cloned().collect::<HashMap<_, _>>().into(),
|
2021-08-12 13:17:51 +08:00
|
|
|
params: [(id, v0)].iter().cloned().collect::<HashMap<_, _>>().into(),
|
2021-07-21 15:59:01 +08:00
|
|
|
});
|
2021-08-18 16:33:50 +08:00
|
|
|
top_level_defs.push(
|
|
|
|
RwLock::new(TopLevelDef::Class {
|
2021-08-21 14:51:46 +08:00
|
|
|
name: "Foo".to_string(),
|
2021-08-18 16:33:50 +08:00
|
|
|
object_id: DefinitionId(5),
|
2021-08-23 16:57:50 +08:00
|
|
|
type_vars: vec![(id, v0)],
|
2021-08-18 16:33:50 +08:00
|
|
|
fields: [("a".into(), v0)].into(),
|
|
|
|
methods: Default::default(),
|
|
|
|
ancestors: Default::default(),
|
|
|
|
resolver: None,
|
|
|
|
})
|
|
|
|
.into(),
|
|
|
|
);
|
2021-07-21 15:59:01 +08:00
|
|
|
|
2021-07-22 17:07:49 +08:00
|
|
|
identifier_mapping.insert(
|
2021-07-21 15:59:01 +08:00
|
|
|
"Foo".into(),
|
2021-08-16 20:17:08 +08:00
|
|
|
unifier.add_ty(TypeEnum::TFunc(
|
|
|
|
FunSignature {
|
|
|
|
args: vec![],
|
|
|
|
ret: foo_ty,
|
|
|
|
vars: [(id, v0)].iter().cloned().collect(),
|
|
|
|
}
|
|
|
|
.into(),
|
|
|
|
)),
|
2021-07-21 15:36:35 +08:00
|
|
|
);
|
|
|
|
|
2021-08-16 20:17:08 +08:00
|
|
|
let fun = unifier.add_ty(TypeEnum::TFunc(
|
|
|
|
FunSignature { args: vec![], ret: int32, vars: Default::default() }.into(),
|
|
|
|
));
|
2021-07-27 11:58:35 +08:00
|
|
|
let bar = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(6),
|
2021-08-03 13:38:27 +08:00
|
|
|
fields: [("a".into(), int32), ("b".into(), fun)]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect::<HashMap<_, _>>()
|
|
|
|
.into(),
|
2021-07-27 11:58:35 +08:00
|
|
|
params: Default::default(),
|
|
|
|
});
|
2021-08-18 16:33:50 +08:00
|
|
|
top_level_defs.push(
|
|
|
|
RwLock::new(TopLevelDef::Class {
|
2021-08-21 14:51:46 +08:00
|
|
|
name: "Bar".to_string(),
|
2021-08-18 16:33:50 +08:00
|
|
|
object_id: DefinitionId(6),
|
|
|
|
type_vars: Default::default(),
|
|
|
|
fields: [("a".into(), int32), ("b".into(), fun)].into(),
|
|
|
|
methods: Default::default(),
|
|
|
|
ancestors: Default::default(),
|
|
|
|
resolver: None,
|
|
|
|
})
|
|
|
|
.into(),
|
|
|
|
);
|
2021-07-27 11:58:35 +08:00
|
|
|
identifier_mapping.insert(
|
|
|
|
"Bar".into(),
|
2021-08-16 20:17:08 +08:00
|
|
|
unifier.add_ty(TypeEnum::TFunc(
|
|
|
|
FunSignature { args: vec![], ret: bar, vars: Default::default() }.into(),
|
|
|
|
)),
|
2021-07-27 11:58:35 +08:00
|
|
|
);
|
|
|
|
|
|
|
|
let bar2 = unifier.add_ty(TypeEnum::TObj {
|
2021-08-06 10:30:57 +08:00
|
|
|
obj_id: DefinitionId(7),
|
2021-08-03 13:38:27 +08:00
|
|
|
fields: [("a".into(), bool), ("b".into(), fun)]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect::<HashMap<_, _>>()
|
|
|
|
.into(),
|
2021-07-27 11:58:35 +08:00
|
|
|
params: Default::default(),
|
|
|
|
});
|
2021-08-18 16:33:50 +08:00
|
|
|
top_level_defs.push(
|
|
|
|
RwLock::new(TopLevelDef::Class {
|
2021-08-21 14:51:46 +08:00
|
|
|
name: "Bar2".to_string(),
|
2021-08-18 16:33:50 +08:00
|
|
|
object_id: DefinitionId(7),
|
|
|
|
type_vars: Default::default(),
|
|
|
|
fields: [("a".into(), bool), ("b".into(), fun)].into(),
|
|
|
|
methods: Default::default(),
|
|
|
|
ancestors: Default::default(),
|
|
|
|
resolver: None,
|
|
|
|
})
|
|
|
|
.into(),
|
|
|
|
);
|
2021-07-27 11:58:35 +08:00
|
|
|
identifier_mapping.insert(
|
|
|
|
"Bar2".into(),
|
2021-08-16 20:17:08 +08:00
|
|
|
unifier.add_ty(TypeEnum::TFunc(
|
|
|
|
FunSignature { args: vec![], ret: bar2, vars: Default::default() }.into(),
|
|
|
|
)),
|
2021-07-27 11:58:35 +08:00
|
|
|
);
|
|
|
|
let class_names = [("Bar".into(), bar), ("Bar2".into(), bar2)].iter().cloned().collect();
|
|
|
|
|
2021-07-21 15:36:35 +08:00
|
|
|
let id_to_name = [
|
|
|
|
(0, "int32".to_string()),
|
|
|
|
(1, "int64".to_string()),
|
|
|
|
(2, "float".to_string()),
|
|
|
|
(3, "bool".to_string()),
|
|
|
|
(4, "none".to_string()),
|
|
|
|
(5, "Foo".to_string()),
|
2021-07-27 11:58:35 +08:00
|
|
|
(6, "Bar".to_string()),
|
|
|
|
(7, "Bar2".to_string()),
|
2021-07-21 15:36:35 +08:00
|
|
|
]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
|
2021-08-11 17:28:29 +08:00
|
|
|
let top_level = TopLevelContext {
|
2021-08-23 10:34:11 +08:00
|
|
|
definitions: Arc::new(top_level_defs.into()),
|
2021-08-11 17:28:29 +08:00
|
|
|
unifiers: Default::default(),
|
|
|
|
};
|
|
|
|
|
2021-08-25 15:30:36 +08:00
|
|
|
let resolver = Arc::new(Box::new(Resolver {
|
2021-08-11 17:28:29 +08:00
|
|
|
id_to_type: identifier_mapping.clone(),
|
|
|
|
id_to_def: [
|
|
|
|
("Foo".into(), DefinitionId(5)),
|
|
|
|
("Bar".into(), DefinitionId(6)),
|
|
|
|
("Bar2".into(), DefinitionId(7)),
|
|
|
|
]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect(),
|
|
|
|
class_names,
|
2021-08-25 15:30:36 +08:00
|
|
|
}) as Box<dyn SymbolResolver + Send + Sync>);
|
2021-07-21 15:36:35 +08:00
|
|
|
|
|
|
|
TestEnvironment {
|
|
|
|
unifier,
|
2021-08-11 17:28:29 +08:00
|
|
|
top_level,
|
2021-07-28 17:25:19 +08:00
|
|
|
function_data: FunctionData {
|
|
|
|
resolver,
|
|
|
|
bound_variables: Vec::new(),
|
2021-07-30 11:01:11 +08:00
|
|
|
return_type: None,
|
2021-07-28 17:25:19 +08:00
|
|
|
},
|
2021-07-21 15:36:35 +08:00
|
|
|
primitives,
|
|
|
|
id_to_name,
|
2021-07-22 17:07:49 +08:00
|
|
|
identifier_mapping,
|
2021-07-27 11:58:35 +08:00
|
|
|
virtual_checks: Vec::new(),
|
2021-07-30 11:01:11 +08:00
|
|
|
calls: HashMap::new(),
|
2021-07-21 15:36:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_inferencer(&mut self) -> Inferencer {
|
|
|
|
Inferencer {
|
2021-08-11 17:28:29 +08:00
|
|
|
top_level: &self.top_level,
|
2021-07-28 17:25:19 +08:00
|
|
|
function_data: &mut self.function_data,
|
2021-07-21 15:36:35 +08:00
|
|
|
unifier: &mut self.unifier,
|
|
|
|
variable_mapping: Default::default(),
|
|
|
|
primitives: &mut self.primitives,
|
2021-07-27 11:58:35 +08:00
|
|
|
virtual_checks: &mut self.virtual_checks,
|
2021-07-30 11:01:11 +08:00
|
|
|
calls: &mut self.calls,
|
2021-08-27 11:13:43 +08:00
|
|
|
defined_identifiers: vec![]
|
2021-07-21 15:36:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test_case(indoc! {"
|
|
|
|
a = 1234
|
|
|
|
b = int64(2147483648)
|
|
|
|
c = 1.234
|
|
|
|
d = True
|
|
|
|
"},
|
2021-07-27 11:58:35 +08:00
|
|
|
[("a", "int32"), ("b", "int64"), ("c", "float"), ("d", "bool")].iter().cloned().collect(),
|
|
|
|
&[]
|
2021-07-21 15:36:35 +08:00
|
|
|
; "primitives test")]
|
|
|
|
#[test_case(indoc! {"
|
|
|
|
a = lambda x, y: x
|
|
|
|
b = lambda x: a(x, x)
|
|
|
|
c = 1.234
|
|
|
|
d = b(c)
|
|
|
|
"},
|
2021-07-27 11:58:35 +08:00
|
|
|
[("a", "fn[[x=float, y=float], float]"), ("b", "fn[[x=float], float]"), ("c", "float"), ("d", "float")].iter().cloned().collect(),
|
|
|
|
&[]
|
2021-07-21 15:36:35 +08:00
|
|
|
; "lambda test")]
|
2021-07-21 15:59:01 +08:00
|
|
|
#[test_case(indoc! {"
|
|
|
|
a = lambda x: x
|
|
|
|
b = lambda x: x
|
|
|
|
|
|
|
|
foo1 = Foo()
|
|
|
|
foo2 = Foo()
|
|
|
|
c = a(foo1.a)
|
|
|
|
d = b(foo2.a)
|
|
|
|
|
|
|
|
a(True)
|
|
|
|
b(123)
|
|
|
|
|
|
|
|
"},
|
|
|
|
[("a", "fn[[x=bool], bool]"), ("b", "fn[[x=int32], int32]"), ("c", "bool"),
|
2021-07-27 11:58:35 +08:00
|
|
|
("d", "int32"), ("foo1", "Foo[bool]"), ("foo2", "Foo[int32]")].iter().cloned().collect(),
|
|
|
|
&[]
|
2021-07-21 15:59:01 +08:00
|
|
|
; "obj test")]
|
2021-07-21 16:06:06 +08:00
|
|
|
#[test_case(indoc! {"
|
|
|
|
f = lambda x: True
|
|
|
|
a = [1, 2, 3]
|
2021-07-21 16:10:11 +08:00
|
|
|
b = [f(x) for x in a if f(x)]
|
2021-07-21 16:06:06 +08:00
|
|
|
"},
|
2021-07-27 11:58:35 +08:00
|
|
|
[("a", "list[int32]"), ("b", "list[bool]"), ("f", "fn[[x=int32], bool]")].iter().cloned().collect(),
|
|
|
|
&[]
|
2021-07-21 16:06:06 +08:00
|
|
|
; "listcomp test")]
|
2021-07-27 11:58:35 +08:00
|
|
|
#[test_case(indoc! {"
|
|
|
|
a = virtual(Bar(), Bar)
|
|
|
|
b = a.b()
|
|
|
|
a = virtual(Bar2())
|
|
|
|
"},
|
|
|
|
[("a", "virtual[Bar]"), ("b", "int32")].iter().cloned().collect(),
|
|
|
|
&[("Bar", "Bar"), ("Bar2", "Bar")]
|
|
|
|
; "virtual test")]
|
2021-07-27 14:39:53 +08:00
|
|
|
#[test_case(indoc! {"
|
|
|
|
a = [virtual(Bar(), Bar), virtual(Bar2())]
|
|
|
|
b = [x.b() for x in a]
|
|
|
|
"},
|
|
|
|
[("a", "list[virtual[Bar]]"), ("b", "list[int32]")].iter().cloned().collect(),
|
|
|
|
&[("Bar", "Bar"), ("Bar2", "Bar")]
|
|
|
|
; "virtual list test")]
|
2021-07-27 11:58:35 +08:00
|
|
|
fn test_basic(source: &str, mapping: HashMap<&str, &str>, virtuals: &[(&str, &str)]) {
|
2021-07-22 17:07:49 +08:00
|
|
|
println!("source:\n{}", source);
|
2021-07-21 15:36:35 +08:00
|
|
|
let mut env = TestEnvironment::new();
|
|
|
|
let id_to_name = std::mem::take(&mut env.id_to_name);
|
2021-07-27 11:58:35 +08:00
|
|
|
let mut defined_identifiers: Vec<_> = env.identifier_mapping.keys().cloned().collect();
|
|
|
|
defined_identifiers.push("virtual".to_string());
|
2021-07-21 15:36:35 +08:00
|
|
|
let mut inferencer = env.get_inferencer();
|
2021-08-27 11:13:43 +08:00
|
|
|
inferencer.defined_identifiers = defined_identifiers.clone();
|
2021-07-21 15:36:35 +08:00
|
|
|
let statements = parse_program(source).unwrap();
|
2021-07-22 17:07:49 +08:00
|
|
|
let statements = statements
|
2021-07-21 15:36:35 +08:00
|
|
|
.into_iter()
|
|
|
|
.map(|v| inferencer.fold_stmt(v))
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
.unwrap();
|
2021-07-22 17:07:49 +08:00
|
|
|
|
|
|
|
inferencer.check_block(&statements, &mut defined_identifiers).unwrap();
|
|
|
|
|
2021-07-21 15:59:01 +08:00
|
|
|
for (k, v) in inferencer.variable_mapping.iter() {
|
|
|
|
let name = inferencer.unifier.stringify(
|
|
|
|
*v,
|
|
|
|
&mut |v| id_to_name.get(&v).unwrap().clone(),
|
|
|
|
&mut |v| format!("v{}", v),
|
|
|
|
);
|
|
|
|
println!("{}: {}", k, name);
|
|
|
|
}
|
2021-07-21 15:36:35 +08:00
|
|
|
for (k, v) in mapping.iter() {
|
|
|
|
let ty = inferencer.variable_mapping.get(*k).unwrap();
|
|
|
|
let name = inferencer.unifier.stringify(
|
|
|
|
*ty,
|
|
|
|
&mut |v| id_to_name.get(&v).unwrap().clone(),
|
|
|
|
&mut |v| format!("v{}", v),
|
|
|
|
);
|
|
|
|
assert_eq!(format!("{}: {}", k, v), format!("{}: {}", k, name));
|
|
|
|
}
|
2021-07-27 11:58:35 +08:00
|
|
|
assert_eq!(inferencer.virtual_checks.len(), virtuals.len());
|
|
|
|
for ((a, b), (x, y)) in zip(inferencer.virtual_checks.iter(), virtuals) {
|
|
|
|
let a = inferencer.unifier.stringify(
|
|
|
|
*a,
|
|
|
|
&mut |v| id_to_name.get(&v).unwrap().clone(),
|
|
|
|
&mut |v| format!("v{}", v),
|
|
|
|
);
|
|
|
|
let b = inferencer.unifier.stringify(
|
|
|
|
*b,
|
|
|
|
&mut |v| id_to_name.get(&v).unwrap().clone(),
|
|
|
|
&mut |v| format!("v{}", v),
|
|
|
|
);
|
|
|
|
|
|
|
|
assert_eq!(&a, x);
|
|
|
|
assert_eq!(&b, y);
|
|
|
|
}
|
2021-07-21 15:36:35 +08:00
|
|
|
}
|
2021-08-02 17:36:37 +08:00
|
|
|
|
|
|
|
#[test_case(indoc! {"
|
|
|
|
a = 2
|
|
|
|
b = 2
|
|
|
|
c = a + b
|
|
|
|
d = a - b
|
|
|
|
e = a * b
|
|
|
|
f = a / b
|
|
|
|
g = a // b
|
|
|
|
h = a % b
|
|
|
|
"},
|
2021-08-03 13:38:27 +08:00
|
|
|
[("a", "int32"),
|
|
|
|
("b", "int32"),
|
|
|
|
("c", "int32"),
|
|
|
|
("d", "int32"),
|
|
|
|
("e", "int32"),
|
|
|
|
("f", "float"),
|
|
|
|
("g", "int32"),
|
2021-08-02 17:36:37 +08:00
|
|
|
("h", "int32")].iter().cloned().collect()
|
|
|
|
; "int32")]
|
|
|
|
#[test_case(
|
|
|
|
indoc! {"
|
|
|
|
a = 2.4
|
|
|
|
b = 3.6
|
|
|
|
c = a + b
|
|
|
|
d = a - b
|
|
|
|
e = a * b
|
|
|
|
f = a / b
|
|
|
|
g = a // b
|
|
|
|
h = a % b
|
2021-08-05 11:55:46 +08:00
|
|
|
i = a ** b
|
|
|
|
ii = 3
|
|
|
|
j = a ** b
|
2021-08-02 17:36:37 +08:00
|
|
|
"},
|
2021-08-03 13:38:27 +08:00
|
|
|
[("a", "float"),
|
|
|
|
("b", "float"),
|
|
|
|
("c", "float"),
|
|
|
|
("d", "float"),
|
|
|
|
("e", "float"),
|
|
|
|
("f", "float"),
|
|
|
|
("g", "float"),
|
2021-08-05 11:55:46 +08:00
|
|
|
("h", "float"),
|
|
|
|
("i", "float"),
|
|
|
|
("ii", "int32"),
|
|
|
|
("j", "float")].iter().cloned().collect()
|
2021-08-02 17:36:37 +08:00
|
|
|
; "float"
|
|
|
|
)]
|
|
|
|
#[test_case(
|
|
|
|
indoc! {"
|
|
|
|
a = int64(12312312312)
|
|
|
|
b = int64(24242424424)
|
|
|
|
c = a + b
|
|
|
|
d = a - b
|
|
|
|
e = a * b
|
|
|
|
f = a / b
|
|
|
|
g = a // b
|
|
|
|
h = a % b
|
|
|
|
i = a == b
|
|
|
|
j = a > b
|
|
|
|
k = a < b
|
|
|
|
l = a != b
|
|
|
|
"},
|
2021-08-03 13:38:27 +08:00
|
|
|
[("a", "int64"),
|
|
|
|
("b", "int64"),
|
|
|
|
("c", "int64"),
|
|
|
|
("d", "int64"),
|
|
|
|
("e", "int64"),
|
|
|
|
("f", "float"),
|
|
|
|
("g", "int64"),
|
2021-08-02 17:36:37 +08:00
|
|
|
("h", "int64"),
|
|
|
|
("i", "bool"),
|
|
|
|
("j", "bool"),
|
|
|
|
("k", "bool"),
|
|
|
|
("l", "bool")].iter().cloned().collect()
|
|
|
|
; "int64"
|
|
|
|
)]
|
|
|
|
#[test_case(
|
|
|
|
indoc! {"
|
|
|
|
a = True
|
|
|
|
b = False
|
|
|
|
c = a == b
|
|
|
|
d = not a
|
|
|
|
e = a != b
|
|
|
|
"},
|
2021-08-03 13:38:27 +08:00
|
|
|
[("a", "bool"),
|
|
|
|
("b", "bool"),
|
|
|
|
("c", "bool"),
|
|
|
|
("d", "bool"),
|
2021-08-02 17:36:37 +08:00
|
|
|
("e", "bool")].iter().cloned().collect()
|
|
|
|
; "boolean"
|
|
|
|
)]
|
|
|
|
fn test_primitive_magic_methods(source: &str, mapping: HashMap<&str, &str>) {
|
|
|
|
println!("source:\n{}", source);
|
|
|
|
let mut env = TestEnvironment::basic_test_env();
|
|
|
|
let id_to_name = std::mem::take(&mut env.id_to_name);
|
|
|
|
let mut defined_identifiers: Vec<_> = env.identifier_mapping.keys().cloned().collect();
|
|
|
|
defined_identifiers.push("virtual".to_string());
|
|
|
|
let mut inferencer = env.get_inferencer();
|
2021-08-27 11:13:43 +08:00
|
|
|
inferencer.defined_identifiers = defined_identifiers.clone();
|
2021-08-02 17:36:37 +08:00
|
|
|
let statements = parse_program(source).unwrap();
|
|
|
|
let statements = statements
|
|
|
|
.into_iter()
|
|
|
|
.map(|v| inferencer.fold_stmt(v))
|
|
|
|
.collect::<Result<Vec<_>, _>>()
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
inferencer.check_block(&statements, &mut defined_identifiers).unwrap();
|
|
|
|
|
|
|
|
for (k, v) in inferencer.variable_mapping.iter() {
|
|
|
|
let name = inferencer.unifier.stringify(
|
|
|
|
*v,
|
|
|
|
&mut |v| id_to_name.get(&v).unwrap().clone(),
|
|
|
|
&mut |v| format!("v{}", v),
|
|
|
|
);
|
|
|
|
println!("{}: {}", k, name);
|
|
|
|
}
|
|
|
|
for (k, v) in mapping.iter() {
|
|
|
|
let ty = inferencer.variable_mapping.get(*k).unwrap();
|
|
|
|
let name = inferencer.unifier.stringify(
|
|
|
|
*ty,
|
|
|
|
&mut |v| id_to_name.get(&v).unwrap().clone(),
|
|
|
|
&mut |v| format!("v{}", v),
|
|
|
|
);
|
|
|
|
assert_eq!(format!("{}: {}", k, v), format!("{}: {}", k, name));
|
|
|
|
}
|
2021-08-03 13:38:27 +08:00
|
|
|
}
|