hm-inference #6
|
@ -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 typedef;
|
||||||
pub mod type_inferencer;
|
pub mod type_inferencer;
|
||||||
mod unification_table;
|
mod unification_table;
|
||||||
|
mod function_check;
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub struct Inferencer<'a> {
|
||||||
pub variable_mapping: HashMap<String, Type>,
|
pub variable_mapping: HashMap<String, Type>,
|
||||||
pub calls: &'a mut Vec<Rc<Call>>,
|
pub calls: &'a mut Vec<Rc<Call>>,
|
||||||
pub primitives: &'a PrimitiveStore,
|
pub primitives: &'a PrimitiveStore,
|
||||||
pub return_type: Option<Type>
|
pub return_type: Option<Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NaiveFolder();
|
struct NaiveFolder();
|
||||||
|
@ -107,8 +107,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::StmtKind::AnnAssign { .. } | ast::StmtKind::Expr { .. } => {}
|
ast::StmtKind::AnnAssign { .. } | ast::StmtKind::Expr { .. } => {}
|
||||||
ast::StmtKind::Return { value } => {
|
ast::StmtKind::Return { value } => match (value, self.return_type) {
|
||||||
match (value, self.return_type) {
|
|
||||||
(Some(v), Some(v1)) => {
|
(Some(v), Some(v1)) => {
|
||||||
self.unifier.unify(v.custom.unwrap(), v1)?;
|
self.unifier.unify(v.custom.unwrap(), v1)?;
|
||||||
}
|
}
|
||||||
|
@ -119,8 +118,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
|
||||||
return Err("Expected return value".to_string());
|
return Err("Expected return value".to_string());
|
||||||
}
|
}
|
||||||
(None, None) => {}
|
(None, None) => {}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
_ => return Err("Unsupported statement type".to_string()),
|
_ => return Err("Unsupported statement type".to_string()),
|
||||||
};
|
};
|
||||||
Ok(stmt)
|
Ok(stmt)
|
||||||
|
@ -151,7 +149,7 @@ impl<'a> fold::Fold<()> for Inferencer<'a> {
|
||||||
attr,
|
attr,
|
||||||
ctx: _,
|
ctx: _,
|
||||||
} => Some(self.infer_attribute(value, attr)?),
|
} => 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::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::UnaryOp { op, operand } => Some(self.infer_unary_ops(op, operand)?),
|
||||||
ast::ExprKind::Compare {
|
ast::ExprKind::Compare {
|
||||||
|
@ -242,7 +240,7 @@ impl<'a> Inferencer<'a> {
|
||||||
variable_mapping,
|
variable_mapping,
|
||||||
calls: self.calls,
|
calls: self.calls,
|
||||||
primitives: self.primitives,
|
primitives: self.primitives,
|
||||||
return_type: self.return_type
|
return_type: self.return_type,
|
||||||
};
|
};
|
||||||
let fun = FunSignature {
|
let fun = FunSignature {
|
||||||
args: fn_args
|
args: fn_args
|
||||||
|
@ -291,7 +289,7 @@ impl<'a> Inferencer<'a> {
|
||||||
variable_mapping,
|
variable_mapping,
|
||||||
calls: self.calls,
|
calls: self.calls,
|
||||||
primitives: self.primitives,
|
primitives: self.primitives,
|
||||||
return_type: self.return_type
|
return_type: self.return_type,
|
||||||
};
|
};
|
||||||
let elt = new_context.fold_expr(elt)?;
|
let elt = new_context.fold_expr(elt)?;
|
||||||
let generator = generators.pop().unwrap();
|
let generator = generators.pop().unwrap();
|
||||||
|
@ -392,24 +390,12 @@ impl<'a> Inferencer<'a> {
|
||||||
return Err("Integer out of bound".into());
|
return Err("Integer out of bound".into());
|
||||||
}
|
}
|
||||||
return Ok(Located {
|
return Ok(Located {
|
||||||
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,
|
location: args[0].location,
|
||||||
custom,
|
custom,
|
||||||
node: ExprKind::Constant {
|
node: ExprKind::Constant {
|
||||||
value: ast::Constant::Int(val.clone()),
|
value: ast::Constant::Int(val.clone()),
|
||||||
kind: kind.clone(),
|
kind: kind.clone(),
|
||||||
},
|
},
|
||||||
}],
|
|
||||||
keywords: vec![],
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,6 @@ pub struct FunSignature {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum TypeEnum {
|
pub enum TypeEnum {
|
||||||
TVar {
|
TVar {
|
||||||
// TODO: upper/lower bound
|
|
||||||
id: u32,
|
id: u32,
|
||||||
},
|
},
|
||||||
TSeq {
|
TSeq {
|
||||||
|
@ -102,6 +101,17 @@ impl TypeEnum {
|
||||||
TypeEnum::TFunc { .. } => "TFunc",
|
TypeEnum::TFunc { .. } => "TFunc",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_concrete(&self) -> bool {
|
||||||
|
matches!(
|
||||||
|
self,
|
||||||
|
TypeEnum::TTuple { .. }
|
||||||
|
| TypeEnum::TList { .. }
|
||||||
|
| TypeEnum::TObj { .. }
|
||||||
|
| TypeEnum::TVirtual { .. }
|
||||||
|
| TypeEnum::TFunc { .. }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Unifier {
|
pub struct Unifier {
|
||||||
|
|
Loading…
Reference in New Issue