forked from M-Labs/nac3
init function check
This commit is contained in:
parent
d484fa1e5c
commit
c315227a28
|
@ -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(())
|
||||
}
|
||||
}
|
|
@ -5,3 +5,4 @@ pub mod symbol_resolver;
|
|||
pub mod typedef;
|
||||
pub mod type_inferencer;
|
||||
mod unification_table;
|
||||
mod function_check;
|
||||
|
|
|
@ -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(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue