forked from M-Labs/nac3
1
0
Fork 0

nac3core: top level simple type var handled

This commit is contained in:
ychenfo 2021-09-08 02:27:12 +08:00
parent 247b364191
commit 55335fc05d
7 changed files with 117 additions and 74 deletions

View File

@ -609,7 +609,8 @@ impl<'ctx, 'a> CodeGenContext<'ctx, 'a> {
ExprKind::Call { func, args, keywords } => { ExprKind::Call { func, args, keywords } => {
if let ExprKind::Name { id, .. } = &func.as_ref().node { if let ExprKind::Name { id, .. } = &func.as_ref().node {
// TODO: handle primitive casts and function pointers // TODO: handle primitive casts and function pointers
let fun = self.resolver.lock().get_identifier_def(&id).expect("Unknown identifier"); let fun =
self.resolver.lock().get_identifier_def(&id).expect("Unknown identifier");
let mut params = let mut params =
args.iter().map(|arg| (None, self.gen_expr(arg).unwrap())).collect_vec(); args.iter().map(|arg| (None, self.gen_expr(arg).unwrap())).collect_vec();
let kw_iter = keywords.iter().map(|kw| { let kw_iter = keywords.iter().map(|kw| {

View File

@ -225,4 +225,4 @@ impl Debug for dyn SymbolResolver + Send + Sync {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "") write!(f, "")
} }
} }

View File

@ -1,33 +1,34 @@
use super::*; use super::*;
impl TopLevelDef { impl TopLevelDef {
pub fn to_string<F, G>(&self, unifier: &mut Unifier, obj_to_name: &mut F, var_to_name: &mut G) -> String pub fn to_string<F, G>(
&self,
unifier: &mut Unifier,
obj_to_name: &mut F,
var_to_name: &mut G,
) -> String
where where
F: FnMut(usize) -> String, F: FnMut(usize) -> String,
G: FnMut(u32) -> String, G: FnMut(u32) -> String,
{ {
match self { match self {
TopLevelDef::Class { TopLevelDef::Class {
name, name, ancestors, fields, methods, object_id, type_vars, ..
ancestors, } => {
fields,
methods,
object_id,
type_vars,
..
} =>{
let fields_str = fields let fields_str = fields
.iter() .iter()
.map(|(n, ty)| (n.to_string(), unifier.stringify(*ty, obj_to_name, var_to_name))) .map(|(n, ty)| {
(n.to_string(), unifier.stringify(*ty, obj_to_name, var_to_name))
})
.collect_vec(); .collect_vec();
let methods_str = methods let methods_str = methods
.iter() .iter()
.map(|(n, ty, id)| .map(|(n, ty, id)| {
(n.to_string(), unifier.stringify(*ty, obj_to_name, var_to_name), *id) (n.to_string(), unifier.stringify(*ty, obj_to_name, var_to_name), *id)
) })
.collect_vec(); .collect_vec();
format!( format!(
"Class {{\nname: {:?},\ndef_id: {:?},\nancestors: {:?},\nfields: {:?},\nmethods: {:?},\ntype_vars: {:?}\n}}", "Class {{\nname: {:?},\ndef_id: {:?},\nancestors: {:?},\nfields: {:?},\nmethods: {:?},\ntype_vars: {:?}\n}}",
name, name,
@ -38,14 +39,13 @@ impl TopLevelDef {
type_vars, type_vars,
) )
} }
TopLevelDef::Function { name, signature, var_id, .. } => TopLevelDef::Function { name, signature, var_id, .. } => format!(
format!( "Function {{\nname: {:?},\nsig: {:?},\nvar_id: {:?}\n}}",
"Function {{\nname: {:?},\nsig: {:?},\nvar_id: {:?}\n}}", name,
name, unifier.stringify(*signature, obj_to_name, var_to_name),
unifier.stringify(*signature, obj_to_name, var_to_name), var_id
var_id ),
), TopLevelDef::Initializer { class_id } => format!("Initializer {{ {:?} }}", class_id),
TopLevelDef::Initializer { class_id } => format!("Initializer {{ {:?} }}", class_id)
} }
} }
} }

View File

@ -1,4 +1,11 @@
use std::{borrow::BorrowMut, collections::{HashMap, HashSet}, fmt::Debug, iter::FromIterator, ops::{Deref, DerefMut}, sync::Arc}; use std::{
borrow::BorrowMut,
collections::{HashMap, HashSet},
fmt::Debug,
iter::FromIterator,
ops::{Deref, DerefMut},
sync::Arc,
};
use super::typecheck::type_inferencer::PrimitiveStore; use super::typecheck::type_inferencer::PrimitiveStore;
use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier}; use super::typecheck::typedef::{FunSignature, FuncArg, SharedUnifier, Type, TypeEnum, Unifier};
@ -6,7 +13,7 @@ use crate::{
symbol_resolver::SymbolResolver, symbol_resolver::SymbolResolver,
typecheck::{type_inferencer::CodeLocation, typedef::CallId}, typecheck::{type_inferencer::CodeLocation, typedef::CallId},
}; };
use itertools::{Itertools, izip}; use itertools::{izip, Itertools};
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use rustpython_parser::ast::{self, Stmt}; use rustpython_parser::ast::{self, Stmt};
@ -499,7 +506,9 @@ impl TopLevelComposer {
for (class_def, _) in self.definition_ast_list.iter_mut().skip(5) { for (class_def, _) in self.definition_ast_list.iter_mut().skip(5) {
let mut class_def = class_def.write(); let mut class_def = class_def.write();
let (class_ancestors, class_id, class_type_vars) = { let (class_ancestors, class_id, class_type_vars) = {
if let TopLevelDef::Class { ancestors, object_id, type_vars, .. } = class_def.deref_mut() { if let TopLevelDef::Class { ancestors, object_id, type_vars, .. } =
class_def.deref_mut()
{
(ancestors, *object_id, type_vars) (ancestors, *object_id, type_vars)
} else { } else {
continue; continue;
@ -595,8 +604,8 @@ impl TopLevelComposer {
// skip 5 to skip analyzing the primitives // skip 5 to skip analyzing the primitives
for (function_def, function_ast) in def_list.iter().skip(5) { for (function_def, function_ast) in def_list.iter().skip(5) {
let function_def = function_def.read(); let mut function_def = function_def.write();
let function_def = function_def.deref(); let function_def = function_def.deref_mut();
let function_ast = if let Some(function_ast) = function_ast { let function_ast = if let Some(function_ast) = function_ast {
function_ast function_ast
} else { } else {
@ -604,7 +613,9 @@ impl TopLevelComposer {
continue; continue;
}; };
if let TopLevelDef::Function { signature: dummy_ty, resolver, .. } = function_def { if let TopLevelDef::Function { signature: dummy_ty, resolver, var_id, .. } =
function_def
{
if let ast::StmtKind::FunctionDef { args, returns, .. } = &function_ast.node { if let ast::StmtKind::FunctionDef { args, returns, .. } = &function_ast.node {
let resolver = resolver.as_ref(); let resolver = resolver.as_ref();
let resolver = resolver.unwrap(); let resolver = resolver.unwrap();
@ -644,7 +655,7 @@ impl TopLevelComposer {
primitives_store, primitives_store,
annotation, annotation,
)?; )?;
let type_vars_within = let type_vars_within =
get_type_var_contained_in_type_annotation(&type_annotation) get_type_var_contained_in_type_annotation(&type_annotation)
.into_iter() .into_iter()
@ -720,6 +731,9 @@ impl TopLevelComposer {
primitives_store.none primitives_store.none
} }
}; };
var_id.extend_from_slice(
function_var_map.keys().into_iter().copied().collect_vec().as_slice(),
);
let function_ty = unifier.add_ty(TypeEnum::TFunc( let function_ty = unifier.add_ty(TypeEnum::TFunc(
FunSignature { args: arg_types, ret: return_ty, vars: function_var_map } FunSignature { args: arg_types, ret: return_ty, vars: function_var_map }
.into(), .into(),
@ -789,7 +803,7 @@ impl TopLevelComposer {
for b in class_body_ast { for b in class_body_ast {
if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node { if let ast::StmtKind::FunctionDef { args, returns, name, body, .. } = &b.node {
let (method_dummy_ty, ..) = let (method_dummy_ty, method_id) =
Self::get_class_method_def_info(class_methods_def, name)?; Self::get_class_method_def_info(class_methods_def, name)?;
// the method var map can surely include the class's generic parameters // the method var map can surely include the class's generic parameters
@ -817,7 +831,9 @@ impl TopLevelComposer {
.into()); .into());
} }
if name == "__init__" && !defined_paramter_name.contains("self") { if name == "__init__" && !defined_paramter_name.contains("self") {
return Err("class __init__ function must contain the `self` parameter".into()); return Err(
"class __init__ function must contain the `self` parameter".into()
);
} }
let mut result = Vec::new(); let mut result = Vec::new();
@ -939,9 +955,17 @@ impl TopLevelComposer {
} }
}; };
if let TopLevelDef::Function { var_id, .. } =
temp_def_list.get(method_id.0).unwrap().write().deref_mut()
{
var_id.extend_from_slice(
method_var_map.keys().into_iter().copied().collect_vec().as_slice(),
);
}
let method_type = unifier.add_ty(TypeEnum::TFunc( let method_type = unifier.add_ty(TypeEnum::TFunc(
FunSignature { args: arg_types, ret: ret_type, vars: method_var_map }.into(), FunSignature { args: arg_types, ret: ret_type, vars: method_var_map }.into(),
)); ));
// NOTE: unify now since function type is not in type annotation define // NOTE: unify now since function type is not in type annotation define
// which is fine since type within method_type will be subst later // which is fine since type within method_type will be subst later
unifier.unify(method_dummy_ty, method_type)?; unifier.unify(method_dummy_ty, method_type)?;

View File

@ -43,8 +43,6 @@ impl SymbolResolver for Resolver {
} }
} }
#[test_case( #[test_case(
vec![ vec![
indoc! {" indoc! {"
@ -115,7 +113,7 @@ fn test_simple_register(source: Vec<&str>) {
)] )]
fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&str>) { fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&str>) {
let mut composer = TopLevelComposer::new(); let mut composer = TopLevelComposer::new();
let resolver = Arc::new(Mutex::new(Box::new(Resolver { let resolver = Arc::new(Mutex::new(Box::new(Resolver {
id_to_def: Default::default(), id_to_def: Default::default(),
id_to_type: Default::default(), id_to_type: Default::default(),
@ -131,11 +129,14 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
} }
composer.start_analysis().unwrap(); composer.start_analysis().unwrap();
for (i, (def, _)) in composer.definition_ast_list.into_iter().enumerate() { for (i, (def, _)) in composer.definition_ast_list.iter().skip(5).enumerate() {
let def = &*def.read(); let def = &*def.read();
if let TopLevelDef::Function { signature, name, .. } = def { if let TopLevelDef::Function { signature, name, .. } = def {
let ty_str = composer.unifier.stringify(*signature, &mut |id| id.to_string(), &mut |id| id.to_string()); let ty_str =
composer
.unifier
.stringify(*signature, &mut |id| id.to_string(), &mut |id| id.to_string());
assert_eq!(ty_str, tys[i]); assert_eq!(ty_str, tys[i]);
assert_eq!(name, names[i]); assert_eq!(name, names[i]);
} }
@ -150,6 +151,8 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
self.a: int32 = 3 self.a: int32 = 3
def fun(self, b: B): def fun(self, b: B):
pass pass
def foo(self, a: T, b: V):
pass
"}, "},
indoc! {" indoc! {"
class B(C): class B(C):
@ -168,6 +171,10 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
def foo(a: A): def foo(a: A):
pass pass
"}, "},
indoc! {"
def ff(a: T) -> V:
pass
"}
], ],
vec![ vec![
indoc! {"5: Class { indoc! {"5: Class {
@ -242,10 +249,19 @@ fn test_simple_function_analyze(source: Vec<&str>, tys: Vec<&str>, names: Vec<&s
)] )]
fn test_simple_class_analyze(source: Vec<&str>, res: Vec<&str>) { fn test_simple_class_analyze(source: Vec<&str>, res: Vec<&str>) {
let mut composer = TopLevelComposer::new(); let mut composer = TopLevelComposer::new();
let tvar_t = composer.unifier.get_fresh_var();
let tvar_v = composer
.unifier
.get_fresh_var_with_range(&[composer.primitives_ty.bool, composer.primitives_ty.int32]);
println!("t: {}", tvar_t.1);
println!("v: {}\n", tvar_v.1);
let resolver = Arc::new(Mutex::new(Box::new(Resolver { let resolver = Arc::new(Mutex::new(Box::new(Resolver {
id_to_def: Default::default(), id_to_def: Default::default(),
id_to_type: Default::default(), id_to_type: vec![("T".to_string(), tvar_t.0), ("V".to_string(), tvar_v.0)]
.into_iter()
.collect(),
class_names: Default::default(), class_names: Default::default(),
}) as Box<dyn SymbolResolver + Send + Sync>)); }) as Box<dyn SymbolResolver + Send + Sync>));
@ -258,30 +274,30 @@ fn test_simple_class_analyze(source: Vec<&str>, res: Vec<&str>) {
} }
composer.start_analysis().unwrap(); composer.start_analysis().unwrap();
// skip 5 to skip primitives // skip 5 to skip primitives
for (i, (def, _)) in composer.definition_ast_list.iter().skip(5).enumerate() { for (i, (def, _)) in composer.definition_ast_list.iter().skip(5).enumerate() {
let def = &*def.read(); let def = &*def.read();
// println!( println!(
// "{}: {}\n", "{}: {}\n",
// i + 5, i + 5,
// def.to_string( def.to_string(
// composer.unifier.borrow_mut(), composer.unifier.borrow_mut(),
// &mut |id| id.to_string(), &mut |id| format!("class{}", id),
// &mut |id| id.to_string() &mut |id| format!("tvar{}", id)
// ) )
// ); );
assert_eq!( // assert_eq!(
format!( // format!(
"{}: {}", // "{}: {}",
i + 5, // i + 5,
def.to_string( // def.to_string(
composer.unifier.borrow_mut(), // composer.unifier.borrow_mut(),
&mut |id| id.to_string(), // &mut |id| id.to_string(),
&mut |id| id.to_string() // &mut |id| id.to_string()
) // )
), // ),
res[i] // res[i]
) // )
} }
} }

View File

@ -83,7 +83,10 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
self.unify(target.custom.unwrap(), ty.custom.unwrap(), &node.location)?; self.unify(target.custom.unwrap(), ty.custom.unwrap(), &node.location)?;
Some(ty) Some(ty)
} else { } else {
return Err(format!("declaration without definition is not yet supported, at {}", node.location)) return Err(format!(
"declaration without definition is not yet supported, at {}",
node.location
));
}; };
let top_level_defs = self.top_level.definitions.read(); let top_level_defs = self.top_level.definitions.read();
let annotation_type = self.function_data.resolver.lock().parse_type_annotation( let annotation_type = self.function_data.resolver.lock().parse_type_annotation(
@ -161,7 +164,8 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
ast::ExprKind::Constant { value, .. } => Some(self.infer_constant(value)?), ast::ExprKind::Constant { value, .. } => Some(self.infer_constant(value)?),
ast::ExprKind::Name { id, .. } => { ast::ExprKind::Name { id, .. } => {
if !self.defined_identifiers.contains(id) { if !self.defined_identifiers.contains(id) {
if self.function_data.resolver.lock().get_identifier_def(id.as_str()).is_some() { if self.function_data.resolver.lock().get_identifier_def(id.as_str()).is_some()
{
self.defined_identifiers.insert(id.clone()); self.defined_identifiers.insert(id.clone());
} else { } else {
return Err(format!( return Err(format!(
@ -482,13 +486,11 @@ impl<'a> Inferencer<'a> {
let resolver = self.function_data.resolver.lock(); let resolver = self.function_data.resolver.lock();
let variable_mapping = &mut self.variable_mapping; let variable_mapping = &mut self.variable_mapping;
let unifier = &mut self.unifier; let unifier = &mut self.unifier;
Ok(resolver Ok(resolver.get_symbol_type(unifier, self.primitives, id).unwrap_or_else(|| {
.get_symbol_type(unifier, self.primitives, id) let ty = unifier.get_fresh_var().0;
.unwrap_or_else(|| { variable_mapping.insert(id.to_string(), ty);
let ty = unifier.get_fresh_var().0; ty
variable_mapping.insert(id.to_string(), ty); }))
ty
}))
} }
} }

View File

@ -317,7 +317,7 @@ impl TestEnvironment {
primitives: &mut self.primitives, primitives: &mut self.primitives,
virtual_checks: &mut self.virtual_checks, virtual_checks: &mut self.virtual_checks,
calls: &mut self.calls, calls: &mut self.calls,
defined_identifiers: Default::default() defined_identifiers: Default::default(),
} }
} }
} }