1
0
forked from M-Labs/nac3

init function check

This commit is contained in:
pca006132 2021-07-22 15:36:37 +08:00
parent d484fa1e5c
commit c315227a28
4 changed files with 107 additions and 34 deletions

View File

@ -0,0 +1,76 @@
use super::type_inferencer::Inferencer;
use super::typedef::Type;
use rustpython_parser::ast::{self, Expr, ExprKind, StmtKind};
use std::iter::once;
impl<'a> Inferencer<'a> {
fn check_expr(
&mut self,
expr: &Expr<Option<Type>>,
defined_identifiers: &[String],
) -> Result<(), String> {
if let Some(ty) = &expr.custom {
let ty = self.unifier.get_ty(*ty);
let ty = ty.as_ref().borrow();
if ty.is_concrete() {
return Err(format!(
"expected concrete type at {:?} but got {}",
expr.location,
ty.get_type_name()
));
}
}
match &expr.node {
ExprKind::Name { id, .. } => {
if !defined_identifiers.contains(id) {
return Err(format!("unknown identifier {} (use before def?)", id));
}
}
ExprKind::List { elts, .. }
| ExprKind::Tuple { elts, .. }
| ExprKind::BoolOp { values: elts, .. } => {
for elt in elts.iter() {
self.check_expr(elt, defined_identifiers)?;
}
}
ExprKind::Attribute { value, .. } => {
self.check_expr(value.as_ref(), defined_identifiers)?;
}
ExprKind::BinOp { left, right, .. } => {
self.check_expr(left.as_ref(), defined_identifiers)?;
self.check_expr(right.as_ref(), defined_identifiers)?;
}
ExprKind::UnaryOp { operand, .. } => {
self.check_expr(operand.as_ref(), defined_identifiers)?;
}
ExprKind::Compare {
left, comparators, ..
} => {
for elt in once(left.as_ref()).chain(comparators.iter()) {
self.check_expr(elt, defined_identifiers)?;
}
}
ExprKind::Subscript { value, slice, .. } => {
self.check_expr(value.as_ref(), defined_identifiers)?;
self.check_expr(slice.as_ref(), defined_identifiers)?;
}
ExprKind::IfExp { test, body, orelse } => {
self.check_expr(test.as_ref(), defined_identifiers)?;
self.check_expr(body.as_ref(), defined_identifiers)?;
self.check_expr(orelse.as_ref(), defined_identifiers)?;
}
ExprKind::Slice { lower, upper, step } => {
for elt in [lower.as_ref(), upper.as_ref(), step.as_ref()]
.iter()
.flatten()
{
self.check_expr(elt, defined_identifiers)?;
}
}
ExprKind::ListComp { .. } => unimplemented!(),
ExprKind::Lambda { .. } => unimplemented!(),
_ => {}
}
Ok(())
}
}

View File

@ -5,3 +5,4 @@ pub mod symbol_resolver;
pub mod typedef;
pub mod type_inferencer;
mod unification_table;
mod function_check;

View File

@ -31,7 +31,7 @@ pub struct Inferencer<'a> {
pub variable_mapping: HashMap<String, Type>,
pub calls: &'a mut Vec<Rc<Call>>,
pub primitives: &'a PrimitiveStore,
pub return_type: Option<Type>
pub return_type: Option<Type>,
}
struct NaiveFolder();
@ -107,20 +107,18 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
}
}
ast::StmtKind::AnnAssign { .. } | ast::StmtKind::Expr { .. } => {}
ast::StmtKind::Return { value } => {
match (value, self.return_type) {
(Some(v), Some(v1)) => {
self.unifier.unify(v.custom.unwrap(), v1)?;
}
(Some(_), None) => {
return Err("Unexpected return value".to_string());
}
(None, Some(_)) => {
return Err("Expected return value".to_string());
}
(None, None) => {}
ast::StmtKind::Return { value } => match (value, self.return_type) {
(Some(v), Some(v1)) => {
self.unifier.unify(v.custom.unwrap(), v1)?;
}
}
(Some(_), None) => {
return Err("Unexpected return value".to_string());
}
(None, Some(_)) => {
return Err("Expected return value".to_string());
}
(None, None) => {}
},
_ => return Err("Unsupported statement type".to_string()),
};
Ok(stmt)
@ -151,7 +149,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
attr,
ctx: _,
} => Some(self.infer_attribute(value, attr)?),
ast::ExprKind::BoolOp { op: _, values } => Some(self.infer_bool_ops(values)?),
ast::ExprKind::BoolOp { values, .. } => Some(self.infer_bool_ops(values)?),
ast::ExprKind::BinOp { left, op, right } => Some(self.infer_bin_ops(left, op, right)?),
ast::ExprKind::UnaryOp { op, operand } => Some(self.infer_unary_ops(op, operand)?),
ast::ExprKind::Compare {
@ -242,7 +240,7 @@ impl<'a> Inferencer<'a> {
variable_mapping,
calls: self.calls,
primitives: self.primitives,
return_type: self.return_type
return_type: self.return_type,
};
let fun = FunSignature {
args: fn_args
@ -291,7 +289,7 @@ impl<'a> Inferencer<'a> {
variable_mapping,
calls: self.calls,
primitives: self.primitives,
return_type: self.return_type
return_type: self.return_type,
};
let elt = new_context.fold_expr(elt)?;
let generator = generators.pop().unwrap();
@ -392,23 +390,11 @@ impl<'a> Inferencer<'a> {
return Err("Integer out of bound".into());
}
return Ok(Located {
location,
location: args[0].location,
custom,
node: ExprKind::Call {
func: Box::new(Located {
custom: None,
location: func.location,
node: ExprKind::Name { id, ctx },
}),
args: vec![Located {
location: args[0].location,
custom,
node: ExprKind::Constant {
value: ast::Constant::Int(val.clone()),
kind: kind.clone(),
},
}],
keywords: vec![],
node: ExprKind::Constant {
value: ast::Constant::Int(val.clone()),
kind: kind.clone(),
},
});
}

View File

@ -46,7 +46,6 @@ pub struct FunSignature {
#[derive(Clone)]
pub enum TypeEnum {
TVar {
// TODO: upper/lower bound
id: u32,
},
TSeq {
@ -102,6 +101,17 @@ impl TypeEnum {
TypeEnum::TFunc { .. } => "TFunc",
}
}
pub fn is_concrete(&self) -> bool {
matches!(
self,
TypeEnum::TTuple { .. }
| TypeEnum::TList { .. }
| TypeEnum::TObj { .. }
| TypeEnum::TVirtual { .. }
| TypeEnum::TFunc { .. }
)
}
}
pub struct Unifier {