diff --git a/nac3core/src/typecheck/function_check.rs b/nac3core/src/typecheck/function_check.rs new file mode 100644 index 00000000..1e8a2de2 --- /dev/null +++ b/nac3core/src/typecheck/function_check.rs @@ -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>, + 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(()) + } +} diff --git a/nac3core/src/typecheck/mod.rs b/nac3core/src/typecheck/mod.rs index 6b55ddba..fbee8ebe 100644 --- a/nac3core/src/typecheck/mod.rs +++ b/nac3core/src/typecheck/mod.rs @@ -5,3 +5,4 @@ pub mod symbol_resolver; pub mod typedef; pub mod type_inferencer; mod unification_table; +mod function_check; diff --git a/nac3core/src/typecheck/type_inferencer/mod.rs b/nac3core/src/typecheck/type_inferencer/mod.rs index 45ef892d..b7d296cc 100644 --- a/nac3core/src/typecheck/type_inferencer/mod.rs +++ b/nac3core/src/typecheck/type_inferencer/mod.rs @@ -31,7 +31,7 @@ pub struct Inferencer<'a> { pub variable_mapping: HashMap, pub calls: &'a mut Vec>, pub primitives: &'a PrimitiveStore, - pub return_type: Option + pub return_type: Option, } 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(), }, }); } diff --git a/nac3core/src/typecheck/typedef/mod.rs b/nac3core/src/typecheck/typedef/mod.rs index 421f58ce..6274c7c2 100644 --- a/nac3core/src/typecheck/typedef/mod.rs +++ b/nac3core/src/typecheck/typedef/mod.rs @@ -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 {