nac3core/typecheck: check if value is none

This commit is contained in:
pca006132 2021-10-23 21:31:14 +08:00
parent cc83bbc63a
commit 2f6ba69770
1 changed files with 37 additions and 4 deletions

View File

@ -6,6 +6,14 @@ use rustpython_parser::ast::{self, Expr, ExprKind, Stmt, StmtKind, StrRef};
use std::{collections::HashSet, iter::once}; use std::{collections::HashSet, iter::once};
impl<'a> Inferencer<'a> { impl<'a> Inferencer<'a> {
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(())
}
}
fn check_pattern( fn check_pattern(
&mut self, &mut self,
pattern: &Expr<Option<Type>>, pattern: &Expr<Option<Type>>,
@ -16,16 +24,19 @@ impl<'a> Inferencer<'a> {
if !defined_identifiers.contains(id) { if !defined_identifiers.contains(id) {
defined_identifiers.insert(*id); defined_identifiers.insert(*id);
} }
self.should_have_value(pattern)?;
Ok(()) Ok(())
} }
ExprKind::Tuple { elts, .. } => { ExprKind::Tuple { elts, .. } => {
for elt in elts.iter() { for elt in elts.iter() {
self.check_pattern(elt, defined_identifiers)?; self.check_pattern(elt, defined_identifiers)?;
self.should_have_value(elt)?;
} }
Ok(()) Ok(())
} }
ExprKind::Subscript { value, slice, .. } => { ExprKind::Subscript { value, slice, .. } => {
self.check_expr(value, defined_identifiers)?; self.check_expr(value, defined_identifiers)?;
self.should_have_value(value)?;
self.check_expr(slice, defined_identifiers)?; self.check_expr(slice, defined_identifiers)?;
if let TypeEnum::TTuple { .. } = &*self.unifier.get_ty(value.custom.unwrap()) { if let TypeEnum::TTuple { .. } = &*self.unifier.get_ty(value.custom.unwrap()) {
return Err(format!( return Err(format!(
@ -56,6 +67,7 @@ impl<'a> Inferencer<'a> {
} }
match &expr.node { match &expr.node {
ExprKind::Name { id, .. } => { ExprKind::Name { id, .. } => {
self.should_have_value(expr)?;
if !defined_identifiers.contains(id) { if !defined_identifiers.contains(id) {
if self if self
.function_data .function_data
@ -82,24 +94,31 @@ impl<'a> Inferencer<'a> {
| ExprKind::BoolOp { values: elts, .. } => { | ExprKind::BoolOp { values: elts, .. } => {
for elt in elts.iter() { for elt in elts.iter() {
self.check_expr(elt, defined_identifiers)?; self.check_expr(elt, defined_identifiers)?;
self.should_have_value(elt)?;
} }
} }
ExprKind::Attribute { value, .. } => { ExprKind::Attribute { value, .. } => {
self.check_expr(value, defined_identifiers)?; self.check_expr(value, defined_identifiers)?;
self.should_have_value(value)?;
} }
ExprKind::BinOp { left, right, .. } => { ExprKind::BinOp { left, right, .. } => {
self.check_expr(left, defined_identifiers)?; self.check_expr(left, defined_identifiers)?;
self.check_expr(right, defined_identifiers)?; self.check_expr(right, defined_identifiers)?;
self.should_have_value(left)?;
self.should_have_value(right)?;
} }
ExprKind::UnaryOp { operand, .. } => { ExprKind::UnaryOp { operand, .. } => {
self.check_expr(operand, defined_identifiers)?; self.check_expr(operand, defined_identifiers)?;
self.should_have_value(operand)?;
} }
ExprKind::Compare { left, comparators, .. } => { ExprKind::Compare { left, comparators, .. } => {
for elt in once(left.as_ref()).chain(comparators.iter()) { for elt in once(left.as_ref()).chain(comparators.iter()) {
self.check_expr(elt, defined_identifiers)?; self.check_expr(elt, defined_identifiers)?;
self.should_have_value(elt)?;
} }
} }
ExprKind::Subscript { value, slice, .. } => { ExprKind::Subscript { value, slice, .. } => {
self.should_have_value(value)?;
self.check_expr(value, defined_identifiers)?; self.check_expr(value, defined_identifiers)?;
self.check_expr(slice, defined_identifiers)?; self.check_expr(slice, defined_identifiers)?;
} }
@ -110,12 +129,14 @@ impl<'a> Inferencer<'a> {
} }
ExprKind::Slice { lower, upper, step } => { ExprKind::Slice { lower, upper, step } => {
for elt in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() { for elt in [lower.as_ref(), upper.as_ref(), step.as_ref()].iter().flatten() {
self.should_have_value(elt)?;
self.check_expr(elt, defined_identifiers)?; self.check_expr(elt, defined_identifiers)?;
} }
} }
ExprKind::Lambda { args, body } => { ExprKind::Lambda { args, body } => {
let mut defined_identifiers = defined_identifiers.clone(); let mut defined_identifiers = defined_identifiers.clone();
for arg in args.args.iter() { for arg in args.args.iter() {
// TODO: should we check the types here?
if !defined_identifiers.contains(&arg.node.arg) { if !defined_identifiers.contains(&arg.node.arg) {
defined_identifiers.insert(arg.node.arg); defined_identifiers.insert(arg.node.arg);
} }
@ -126,10 +147,13 @@ impl<'a> Inferencer<'a> {
// in our type inference stage, we already make sure that there is only 1 generator // in our type inference stage, we already make sure that there is only 1 generator
let ast::Comprehension { target, iter, ifs, .. } = &generators[0]; let ast::Comprehension { target, iter, ifs, .. } = &generators[0];
self.check_expr(iter, defined_identifiers)?; self.check_expr(iter, defined_identifiers)?;
self.should_have_value(iter)?;
let mut defined_identifiers = defined_identifiers.clone(); let mut defined_identifiers = defined_identifiers.clone();
self.check_pattern(target, &mut defined_identifiers)?; self.check_pattern(target, &mut defined_identifiers)?;
self.should_have_value(target)?;
for term in once(elt.as_ref()).chain(ifs.iter()) { for term in once(elt.as_ref()).chain(ifs.iter()) {
self.check_expr(term, &mut defined_identifiers)?; self.check_expr(term, &mut defined_identifiers)?;
self.should_have_value(term)?;
} }
} }
ExprKind::Call { func, args, keywords } => { ExprKind::Call { func, args, keywords } => {
@ -138,6 +162,7 @@ impl<'a> Inferencer<'a> {
.chain(keywords.iter().map(|v| v.node.value.as_ref())) .chain(keywords.iter().map(|v| v.node.value.as_ref()))
{ {
self.check_expr(expr, defined_identifiers)?; self.check_expr(expr, defined_identifiers)?;
self.should_have_value(expr)?;
} }
} }
ExprKind::Constant { .. } => {} ExprKind::Constant { .. } => {}
@ -158,18 +183,22 @@ impl<'a> Inferencer<'a> {
match &stmt.node { match &stmt.node {
StmtKind::For { target, iter, body, orelse, .. } => { StmtKind::For { target, iter, body, orelse, .. } => {
self.check_expr(iter, defined_identifiers)?; self.check_expr(iter, defined_identifiers)?;
self.should_have_value(iter)?;
let mut local_defined_identifiers = defined_identifiers.clone();
for stmt in orelse.iter() { for stmt in orelse.iter() {
self.check_stmt(stmt, defined_identifiers)?; self.check_stmt(stmt, &mut local_defined_identifiers)?;
} }
let mut defined_identifiers = defined_identifiers.clone(); let mut local_defined_identifiers = defined_identifiers.clone();
self.check_pattern(target, &mut defined_identifiers)?; self.check_pattern(target, &mut local_defined_identifiers)?;
self.should_have_value(target)?;
for stmt in body.iter() { for stmt in body.iter() {
self.check_stmt(stmt, &mut defined_identifiers)?; self.check_stmt(stmt, &mut local_defined_identifiers)?;
} }
Ok(false) Ok(false)
} }
StmtKind::If { test, body, orelse } => { StmtKind::If { test, body, orelse } => {
self.check_expr(test, defined_identifiers)?; self.check_expr(test, defined_identifiers)?;
self.should_have_value(test)?;
let mut body_identifiers = defined_identifiers.clone(); let mut body_identifiers = defined_identifiers.clone();
let mut orelse_identifiers = defined_identifiers.clone(); let mut orelse_identifiers = defined_identifiers.clone();
let body_returned = self.check_block(body, &mut body_identifiers)?; let body_returned = self.check_block(body, &mut body_identifiers)?;
@ -184,6 +213,7 @@ impl<'a> Inferencer<'a> {
} }
StmtKind::While { test, body, orelse } => { StmtKind::While { test, body, orelse } => {
self.check_expr(test, defined_identifiers)?; self.check_expr(test, defined_identifiers)?;
self.should_have_value(test)?;
let mut defined_identifiers = defined_identifiers.clone(); let mut defined_identifiers = defined_identifiers.clone();
self.check_block(body, &mut defined_identifiers)?; self.check_block(body, &mut defined_identifiers)?;
self.check_block(orelse, &mut defined_identifiers)?; self.check_block(orelse, &mut defined_identifiers)?;
@ -195,6 +225,7 @@ impl<'a> Inferencer<'a> {
} }
StmtKind::Assign { targets, value, .. } => { StmtKind::Assign { targets, value, .. } => {
self.check_expr(value, defined_identifiers)?; self.check_expr(value, defined_identifiers)?;
self.should_have_value(value)?;
for target in targets { for target in targets {
self.check_pattern(target, defined_identifiers)?; self.check_pattern(target, defined_identifiers)?;
} }
@ -203,6 +234,7 @@ impl<'a> Inferencer<'a> {
StmtKind::AnnAssign { target, value, .. } => { StmtKind::AnnAssign { target, value, .. } => {
if let Some(value) = value { if let Some(value) = value {
self.check_expr(value, defined_identifiers)?; self.check_expr(value, defined_identifiers)?;
self.should_have_value(value)?;
self.check_pattern(target, defined_identifiers)?; self.check_pattern(target, defined_identifiers)?;
} }
Ok(false) Ok(false)
@ -210,6 +242,7 @@ impl<'a> Inferencer<'a> {
StmtKind::Return { value } => { StmtKind::Return { value } => {
if let Some(value) = value { if let Some(value) = value {
self.check_expr(value, defined_identifiers)?; self.check_expr(value, defined_identifiers)?;
self.should_have_value(value)?;
} }
Ok(true) Ok(true)
} }