mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
fix(pylyzer): declarations in control flow blocks
This commit is contained in:
parent
ebd7707f77
commit
9f435706a1
2 changed files with 143 additions and 5 deletions
|
@ -44,7 +44,7 @@ use RegistrationMode::*;
|
|||
use super::eval::Substituter;
|
||||
use super::instantiate::TyVarCache;
|
||||
use super::instantiate_spec::ParamKind;
|
||||
use super::{MethodContext, ParamSpec, TraitImpl, TypeContext};
|
||||
use super::{ControlKind, MethodContext, ParamSpec, TraitImpl, TypeContext};
|
||||
|
||||
pub fn valid_mod_name(name: &str) -> bool {
|
||||
!name.is_empty() && !name.starts_with('/') && name.trim() == name
|
||||
|
@ -1103,6 +1103,11 @@ impl Context {
|
|||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
ast::Expr::Call(call) if PYTHON_MODE => {
|
||||
if let Err(errs) = self.preregister_control_consts(call) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1113,6 +1118,44 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn preregister_control_consts(&mut self, call: &ast::Call) -> TyCheckResult<()> {
|
||||
match call
|
||||
.obj
|
||||
.get_name()
|
||||
.and_then(|s| ControlKind::try_from(&s[..]).ok())
|
||||
{
|
||||
Some(ControlKind::If) => {
|
||||
let Some(ast::Expr::Lambda(then)) = call.args.nth_or_key(1, "then") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.preregister_consts(&then.body)?;
|
||||
if let Some(ast::Expr::Lambda(else_)) = call.args.nth_or_key(2, "else") {
|
||||
self.preregister_consts(&else_.body)?;
|
||||
}
|
||||
}
|
||||
Some(ControlKind::For) => {
|
||||
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.preregister_consts(&body.body)?;
|
||||
}
|
||||
Some(ControlKind::While) => {
|
||||
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.preregister_consts(&body.body)?;
|
||||
}
|
||||
Some(ControlKind::With) => {
|
||||
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.preregister_consts(&body.body)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn register_defs(&mut self, block: &ast::Block) -> TyCheckResult<()> {
|
||||
let mut total_errs = TyCheckErrors::empty();
|
||||
for expr in block.iter() {
|
||||
|
@ -1181,6 +1224,11 @@ impl Context {
|
|||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
ast::Expr::Call(call) if PYTHON_MODE => {
|
||||
if let Err(errs) = self.register_control_defs(call) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -1191,6 +1239,44 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn register_control_defs(&mut self, call: &ast::Call) -> TyCheckResult<()> {
|
||||
match call
|
||||
.obj
|
||||
.get_name()
|
||||
.and_then(|s| ControlKind::try_from(&s[..]).ok())
|
||||
{
|
||||
Some(ControlKind::If) => {
|
||||
let Some(ast::Expr::Lambda(then)) = call.args.nth_or_key(1, "then") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.register_defs(&then.body)?;
|
||||
if let Some(ast::Expr::Lambda(else_)) = call.args.nth_or_key(2, "else") {
|
||||
self.register_defs(&else_.body)?;
|
||||
}
|
||||
}
|
||||
Some(ControlKind::For) => {
|
||||
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.register_defs(&body.body)?;
|
||||
}
|
||||
Some(ControlKind::While) => {
|
||||
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.register_defs(&body.body)?;
|
||||
}
|
||||
Some(ControlKind::With) => {
|
||||
let Some(ast::Expr::Lambda(body)) = call.args.nth_or_key(1, "body") else {
|
||||
return Ok(());
|
||||
};
|
||||
self.register_defs(&body.body)?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// HACK: The constant expression evaluator can evaluate attributes when the type of the receiver is known.
|
||||
/// import/pyimport is not a constant function, but specially assumes that the type of the module is known in the eval phase.
|
||||
fn pre_import(&mut self, def: &ast::Def) -> TyCheckResult<()> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue