2021-08-21 15:11:01 +08:00
|
|
|
use crate::typecheck::typedef::TypeEnum;
|
|
|
|
|
2021-07-22 15:36:37 +08:00
|
|
|
use super::type_inferencer::Inferencer;
|
|
|
|
use super::typedef::Type;
|
2021-11-03 17:11:00 +08:00
|
|
|
use nac3parser::ast::{self, Expr, ExprKind, Stmt, StmtKind, StrRef};
|
2021-08-27 12:36:51 +08:00
|
|
|
use std::{collections::HashSet, iter::once};
|
2021-07-22 15:36:37 +08:00
|
|
|
|
|
|
|
impl<'a> Inferencer<'a> {
|
2021-10-23 21:31:14 +08:00
|
|
|
fn should_have_value(&mut self, expr: &Expr<Option<Type>>) -> Result<(), String> {
|
|
|
|
if matches!(expr.custom, Some(ty) if self.unifier.unioned(ty, self.primitives.none)) {
|
|
|
|
Err(format!("Error at {}: cannot have value none", expr.location))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 17:07:49 +08:00
|
|
|
fn check_pattern(
|
|
|
|
&mut self,
|
|
|
|
pattern: &Expr<Option<Type>>,
|
2021-09-22 17:19:27 +08:00
|
|
|
defined_identifiers: &mut HashSet<StrRef>,
|
2021-07-27 14:39:53 +08:00
|
|
|
) -> Result<(), String> {
|
2021-07-22 17:07:49 +08:00
|
|
|
match &pattern.node {
|
|
|
|
ExprKind::Name { id, .. } => {
|
|
|
|
if !defined_identifiers.contains(id) {
|
2021-09-22 17:56:48 +08:00
|
|
|
defined_identifiers.insert(*id);
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(pattern)?;
|
2021-07-27 14:39:53 +08:00
|
|
|
Ok(())
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
ExprKind::Tuple { elts, .. } => {
|
|
|
|
for elt in elts.iter() {
|
2021-07-27 14:39:53 +08:00
|
|
|
self.check_pattern(elt, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(elt)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
2021-07-27 14:39:53 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
2021-08-21 15:11:01 +08:00
|
|
|
ExprKind::Subscript { value, slice, .. } => {
|
|
|
|
self.check_expr(value, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(value)?;
|
2021-08-21 15:11:01 +08:00
|
|
|
self.check_expr(slice, defined_identifiers)?;
|
|
|
|
if let TypeEnum::TTuple { .. } = &*self.unifier.get_ty(value.custom.unwrap()) {
|
|
|
|
return Err(format!(
|
|
|
|
"Error at {}: cannot assign to tuple element",
|
|
|
|
value.location
|
|
|
|
));
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2022-03-24 07:13:13 +08:00
|
|
|
ExprKind::Constant { .. } => {
|
|
|
|
Err(format!("cannot assign to a constant (at {})", pattern.location))
|
|
|
|
}
|
2021-08-05 14:55:09 +08:00
|
|
|
_ => self.check_expr(pattern, defined_identifiers),
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-22 15:36:37 +08:00
|
|
|
fn check_expr(
|
|
|
|
&mut self,
|
|
|
|
expr: &Expr<Option<Type>>,
|
2021-09-22 17:19:27 +08:00
|
|
|
defined_identifiers: &mut HashSet<StrRef>,
|
2021-07-22 15:36:37 +08:00
|
|
|
) -> Result<(), String> {
|
2021-07-22 17:07:49 +08:00
|
|
|
// there are some cases where the custom field is None
|
2021-07-22 15:36:37 +08:00
|
|
|
if let Some(ty) = &expr.custom {
|
2021-07-28 17:25:19 +08:00
|
|
|
if !self.unifier.is_concrete(*ty, &self.function_data.bound_variables) {
|
2021-07-22 15:36:37 +08:00
|
|
|
return Err(format!(
|
2021-07-22 17:07:49 +08:00
|
|
|
"expected concrete type at {} but got {}",
|
2021-07-22 15:36:37 +08:00
|
|
|
expr.location,
|
2021-07-28 17:25:19 +08:00
|
|
|
self.unifier.get_ty(*ty).get_type_name()
|
2021-07-22 15:36:37 +08:00
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
match &expr.node {
|
|
|
|
ExprKind::Name { id, .. } => {
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(expr)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
if !defined_identifiers.contains(id) {
|
2022-01-13 03:14:06 +08:00
|
|
|
match self.function_data.resolver.get_symbol_type(
|
|
|
|
self.unifier,
|
|
|
|
&self.top_level.definitions.read(),
|
|
|
|
self.primitives,
|
|
|
|
*id,
|
|
|
|
) {
|
|
|
|
Ok(_) => {
|
|
|
|
self.defined_identifiers.insert(*id);
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
return Err(format!(
|
2022-01-14 16:56:23 +08:00
|
|
|
"type error at identifier `{}` ({}) at {}",
|
2022-01-13 03:14:06 +08:00
|
|
|
id, e, expr.location
|
|
|
|
));
|
|
|
|
}
|
2021-08-27 11:13:43 +08:00
|
|
|
}
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ExprKind::List { elts, .. }
|
|
|
|
| ExprKind::Tuple { elts, .. }
|
|
|
|
| ExprKind::BoolOp { values: elts, .. } => {
|
|
|
|
for elt in elts.iter() {
|
|
|
|
self.check_expr(elt, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(elt)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ExprKind::Attribute { value, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(value, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(value)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
ExprKind::BinOp { left, right, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(left, defined_identifiers)?;
|
|
|
|
self.check_expr(right, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(left)?;
|
|
|
|
self.should_have_value(right)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
ExprKind::UnaryOp { operand, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(operand, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(operand)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
2021-08-05 14:55:09 +08:00
|
|
|
ExprKind::Compare { left, comparators, .. } => {
|
2021-07-22 15:36:37 +08:00
|
|
|
for elt in once(left.as_ref()).chain(comparators.iter()) {
|
|
|
|
self.check_expr(elt, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(elt)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ExprKind::Subscript { value, slice, .. } => {
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(value)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(value, defined_identifiers)?;
|
|
|
|
self.check_expr(slice, defined_identifiers)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
ExprKind::IfExp { test, body, orelse } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(test, defined_identifiers)?;
|
|
|
|
self.check_expr(body, defined_identifiers)?;
|
|
|
|
self.check_expr(orelse, defined_identifiers)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
ExprKind::Slice { lower, upper, step } => {
|
2021-08-05 14:55:09 +08:00
|
|
|
for elt in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() {
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(elt)?;
|
2021-07-22 15:36:37 +08:00
|
|
|
self.check_expr(elt, defined_identifiers)?;
|
|
|
|
}
|
|
|
|
}
|
2021-07-22 17:07:49 +08:00
|
|
|
ExprKind::Lambda { args, body } => {
|
2021-08-27 12:36:51 +08:00
|
|
|
let mut defined_identifiers = defined_identifiers.clone();
|
2021-07-22 17:07:49 +08:00
|
|
|
for arg in args.args.iter() {
|
2021-10-23 21:31:14 +08:00
|
|
|
// TODO: should we check the types here?
|
2021-07-22 17:07:49 +08:00
|
|
|
if !defined_identifiers.contains(&arg.node.arg) {
|
2021-09-22 17:56:48 +08:00
|
|
|
defined_identifiers.insert(arg.node.arg);
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
}
|
2021-08-27 11:13:43 +08:00
|
|
|
self.check_expr(body, &mut defined_identifiers)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
2021-08-05 14:55:09 +08:00
|
|
|
ExprKind::ListComp { elt, generators, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
// in our type inference stage, we already make sure that there is only 1 generator
|
2021-08-05 14:55:09 +08:00
|
|
|
let ast::Comprehension { target, iter, ifs, .. } = &generators[0];
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(iter, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(iter)?;
|
2021-08-27 12:36:51 +08:00
|
|
|
let mut defined_identifiers = defined_identifiers.clone();
|
2021-07-27 14:39:53 +08:00
|
|
|
self.check_pattern(target, &mut defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(target)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
for term in once(elt.as_ref()).chain(ifs.iter()) {
|
2021-08-27 11:13:43 +08:00
|
|
|
self.check_expr(term, &mut defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(term)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
}
|
2021-08-05 14:55:09 +08:00
|
|
|
ExprKind::Call { func, args, keywords } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
for expr in once(func.as_ref())
|
|
|
|
.chain(args.iter())
|
|
|
|
.chain(keywords.iter().map(|v| v.node.value.as_ref()))
|
|
|
|
{
|
|
|
|
self.check_expr(expr, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(expr)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ExprKind::Constant { .. } => {}
|
|
|
|
_ => {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
2021-07-22 17:07:49 +08:00
|
|
|
|
2021-07-26 16:00:29 +08:00
|
|
|
// check statements for proper identifier def-use and return on all paths
|
2021-07-22 17:07:49 +08:00
|
|
|
fn check_stmt(
|
|
|
|
&mut self,
|
|
|
|
stmt: &Stmt<Option<Type>>,
|
2021-09-22 17:19:27 +08:00
|
|
|
defined_identifiers: &mut HashSet<StrRef>,
|
2021-07-22 17:07:49 +08:00
|
|
|
) -> Result<bool, String> {
|
|
|
|
match &stmt.node {
|
2021-08-05 14:55:09 +08:00
|
|
|
StmtKind::For { target, iter, body, orelse, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(iter, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(iter)?;
|
|
|
|
let mut local_defined_identifiers = defined_identifiers.clone();
|
2021-07-22 17:07:49 +08:00
|
|
|
for stmt in orelse.iter() {
|
2021-10-23 21:31:14 +08:00
|
|
|
self.check_stmt(stmt, &mut local_defined_identifiers)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
2021-10-23 21:31:14 +08:00
|
|
|
let mut local_defined_identifiers = defined_identifiers.clone();
|
|
|
|
self.check_pattern(target, &mut local_defined_identifiers)?;
|
|
|
|
self.should_have_value(target)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
for stmt in body.iter() {
|
2021-10-23 21:31:14 +08:00
|
|
|
self.check_stmt(stmt, &mut local_defined_identifiers)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
Ok(false)
|
|
|
|
}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::If { test, body, orelse, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(test, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(test)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
let mut body_identifiers = defined_identifiers.clone();
|
|
|
|
let mut orelse_identifiers = defined_identifiers.clone();
|
|
|
|
let body_returned = self.check_block(body, &mut body_identifiers)?;
|
|
|
|
let orelse_returned = self.check_block(orelse, &mut orelse_identifiers)?;
|
|
|
|
|
|
|
|
for ident in body_identifiers.iter() {
|
|
|
|
if !defined_identifiers.contains(ident) && orelse_identifiers.contains(ident) {
|
2021-09-22 17:56:48 +08:00
|
|
|
defined_identifiers.insert(*ident);
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(body_returned && orelse_returned)
|
|
|
|
}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::While { test, body, orelse, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(test, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(test)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
let mut defined_identifiers = defined_identifiers.clone();
|
|
|
|
self.check_block(body, &mut defined_identifiers)?;
|
|
|
|
self.check_block(orelse, &mut defined_identifiers)?;
|
|
|
|
Ok(false)
|
|
|
|
}
|
2021-10-31 17:16:21 +08:00
|
|
|
StmtKind::With { items, body, .. } => {
|
|
|
|
let mut new_defined_identifiers = defined_identifiers.clone();
|
|
|
|
for item in items.iter() {
|
|
|
|
self.check_expr(&item.context_expr, defined_identifiers)?;
|
|
|
|
if let Some(var) = item.optional_vars.as_ref() {
|
|
|
|
self.check_pattern(var, &mut new_defined_identifiers)?;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
self.check_block(body, &mut new_defined_identifiers)?;
|
|
|
|
Ok(false)
|
|
|
|
}
|
2022-02-12 21:15:50 +08:00
|
|
|
StmtKind::Try { body, handlers, orelse, finalbody, .. } => {
|
|
|
|
self.check_block(body, &mut defined_identifiers.clone())?;
|
|
|
|
self.check_block(orelse, &mut defined_identifiers.clone())?;
|
|
|
|
for handler in handlers.iter() {
|
|
|
|
let mut defined_identifiers = defined_identifiers.clone();
|
|
|
|
let ast::ExcepthandlerKind::ExceptHandler { name, body, .. } = &handler.node;
|
|
|
|
if let Some(name) = name {
|
|
|
|
defined_identifiers.insert(*name);
|
|
|
|
}
|
|
|
|
self.check_block(body, &mut defined_identifiers)?;
|
|
|
|
}
|
|
|
|
self.check_block(finalbody, defined_identifiers)?;
|
|
|
|
Ok(false)
|
|
|
|
}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::Expr { value, .. } => {
|
2021-07-22 17:07:49 +08:00
|
|
|
self.check_expr(value, defined_identifiers)?;
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
StmtKind::Assign { targets, value, .. } => {
|
|
|
|
self.check_expr(value, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(value)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
for target in targets {
|
2021-07-27 14:39:53 +08:00
|
|
|
self.check_pattern(target, defined_identifiers)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
StmtKind::AnnAssign { target, value, .. } => {
|
|
|
|
if let Some(value) = value {
|
|
|
|
self.check_expr(value, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(value)?;
|
2021-07-27 14:39:53 +08:00
|
|
|
self.check_pattern(target, defined_identifiers)?;
|
2021-07-22 17:07:49 +08:00
|
|
|
}
|
|
|
|
Ok(false)
|
|
|
|
}
|
2021-11-04 15:02:51 +08:00
|
|
|
StmtKind::Return { value, .. } => {
|
2021-07-26 16:00:29 +08:00
|
|
|
if let Some(value) = value {
|
|
|
|
self.check_expr(value, defined_identifiers)?;
|
2021-10-23 21:31:14 +08:00
|
|
|
self.should_have_value(value)?;
|
2021-07-26 16:00:29 +08:00
|
|
|
}
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
StmtKind::Raise { exc, .. } => {
|
|
|
|
if let Some(value) = exc {
|
|
|
|
self.check_expr(value, defined_identifiers)?;
|
|
|
|
}
|
|
|
|
Ok(true)
|
|
|
|
}
|
|
|
|
// break, raise, etc.
|
2021-07-22 17:07:49 +08:00
|
|
|
_ => Ok(false),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn check_block(
|
|
|
|
&mut self,
|
|
|
|
block: &[Stmt<Option<Type>>],
|
2021-09-22 17:19:27 +08:00
|
|
|
defined_identifiers: &mut HashSet<StrRef>,
|
2021-07-22 17:07:49 +08:00
|
|
|
) -> Result<bool, String> {
|
|
|
|
let mut ret = false;
|
|
|
|
for stmt in block {
|
|
|
|
if ret {
|
|
|
|
return Err(format!("dead code at {:?}", stmt.location));
|
|
|
|
}
|
|
|
|
if self.check_stmt(stmt, defined_identifiers)? {
|
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(ret)
|
|
|
|
}
|
2021-07-22 15:36:37 +08:00
|
|
|
}
|