mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 10:49:54 +00:00
feat: isinstance
narrowing
This commit is contained in:
parent
ccf02405d8
commit
5876c24830
5 changed files with 62 additions and 24 deletions
|
@ -1019,6 +1019,7 @@ impl Context {
|
|||
.unwrap_or_else(Type::Refinement)
|
||||
}
|
||||
(Structural(l), Structural(r)) => self.intersection(l, r).structuralize(),
|
||||
(Guard(_), Guard(_)) => and(lhs.clone(), rhs.clone()),
|
||||
// {.i = Int} and {.s = Str} == {.i = Int; .s = Str}
|
||||
(Record(l), Record(r)) => Type::Record(l.clone().concat(r.clone())),
|
||||
// {i = Int; j = Int} and not {i = Int} == {j = Int}
|
||||
|
@ -1113,6 +1114,8 @@ impl Context {
|
|||
guard.var.clone(),
|
||||
self.complement(&guard.to),
|
||||
)),
|
||||
Or(l, r) => self.intersection(&self.complement(l), &self.complement(r)),
|
||||
And(l, r) => self.union(&self.complement(l), &self.complement(r)),
|
||||
other => not(other.clone()),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -932,6 +932,10 @@ impl Context {
|
|||
self.outer.as_ref().map(|x| x.as_ref())
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut_outer(&mut self) -> Option<&mut Context> {
|
||||
self.outer.as_mut().map(|x| x.as_mut())
|
||||
}
|
||||
|
||||
pub(crate) fn impl_of(&self) -> Option<Type> {
|
||||
if let ContextKind::MethodDefs(Some(tr)) = &self.kind {
|
||||
Some(tr.clone())
|
||||
|
|
|
@ -756,19 +756,20 @@ impl ASTLowerer {
|
|||
Ok(ident)
|
||||
}
|
||||
|
||||
fn get_type_from_bin_rhs(&self, op: TokenKind, var: Variable, rhs: &ast::Expr) -> Option<Type> {
|
||||
match op {
|
||||
TokenKind::InOp => self
|
||||
.module
|
||||
.context
|
||||
.expr_to_type(rhs.clone())
|
||||
.map(|to| guard(var, to)),
|
||||
fn get_guard_type(&self, op: &Token, lhs: &ast::Expr, rhs: &ast::Expr) -> Option<Type> {
|
||||
let var = expr_to_variable(lhs)?;
|
||||
match op.kind {
|
||||
TokenKind::InOp => {
|
||||
let to = self.module.context.expr_to_type(rhs.clone())?;
|
||||
Some(guard(var, to))
|
||||
}
|
||||
TokenKind::Symbol if &op.content[..] == "isinstance" => {
|
||||
let to = self.module.context.expr_to_type(rhs.clone())?;
|
||||
Some(guard(var, to))
|
||||
}
|
||||
TokenKind::NotInOp => {
|
||||
let ty = self
|
||||
.module
|
||||
.context
|
||||
.expr_to_type(rhs.clone())
|
||||
.map(|to| guard(var, to))?;
|
||||
let to = self.module.context.expr_to_type(rhs.clone())?;
|
||||
let ty = guard(var, to);
|
||||
Some(self.module.context.complement(&ty))
|
||||
}
|
||||
TokenKind::IsOp | TokenKind::DblEq => {
|
||||
|
@ -789,8 +790,7 @@ impl ASTLowerer {
|
|||
let mut args = bin.args.into_iter();
|
||||
let lhs = *args.next().unwrap();
|
||||
let rhs = *args.next().unwrap();
|
||||
let guard = expr_to_variable(&lhs)
|
||||
.and_then(|var| self.get_type_from_bin_rhs(bin.op.kind, var, &rhs));
|
||||
let guard = self.get_guard_type(&bin.op, &lhs, &rhs);
|
||||
let lhs = self.lower_expr(lhs).unwrap_or_else(|errs| {
|
||||
self.errs.extend(errs);
|
||||
hir::Expr::Dummy(hir::Dummy::new(vec![]))
|
||||
|
@ -915,6 +915,21 @@ impl ASTLowerer {
|
|||
self.module.context.higher_order_caller.push(name.clone());
|
||||
}
|
||||
let mut errs = LowerErrors::empty();
|
||||
let guard = if let (
|
||||
ast::Expr::Accessor(ast::Accessor::Ident(ident)),
|
||||
None,
|
||||
Some(lhs),
|
||||
Some(rhs),
|
||||
) = (
|
||||
call.obj.as_ref(),
|
||||
&call.attr_name,
|
||||
call.args.nth_or_key(0, "object"),
|
||||
call.args.nth_or_key(1, "classinfo"),
|
||||
) {
|
||||
self.get_guard_type(ident.name.token(), lhs, rhs)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let opt_cast_to = if call.is_assert_cast() {
|
||||
if let Some(typ) = call.assert_cast_target_type() {
|
||||
Some(Parser::expr_to_type_spec(typ.clone()).map_err(|e| {
|
||||
|
@ -949,7 +964,7 @@ impl ASTLowerer {
|
|||
return Err(errs);
|
||||
}
|
||||
};
|
||||
let vi = match self.module.context.get_call_t(
|
||||
let mut vi = match self.module.context.get_call_t(
|
||||
&obj,
|
||||
&call.attr_name,
|
||||
&hir_args.pos_args,
|
||||
|
@ -964,6 +979,13 @@ impl ASTLowerer {
|
|||
vi.unwrap_or(VarInfo::ILLEGAL.clone())
|
||||
}
|
||||
};
|
||||
if let Some(guard) = guard {
|
||||
debug_assert!(self
|
||||
.module
|
||||
.context
|
||||
.subtype_of(vi.t.return_t().unwrap(), &Type::Bool));
|
||||
*vi.t.mut_return_t().unwrap() = guard;
|
||||
}
|
||||
let attr_name = if let Some(attr_name) = call.attr_name {
|
||||
self.inc_ref(&vi, &attr_name.name);
|
||||
Some(hir::Identifier::new(attr_name, None, vi))
|
||||
|
@ -1185,15 +1207,8 @@ impl ASTLowerer {
|
|||
self.errs.extend(errs);
|
||||
}
|
||||
if !in_statement {
|
||||
for guard in self
|
||||
.module
|
||||
.context
|
||||
.get_outer()
|
||||
.unwrap()
|
||||
.guards
|
||||
.clone()
|
||||
.into_iter()
|
||||
{
|
||||
let guards = mem::take(&mut self.module.context.get_mut_outer().unwrap().guards);
|
||||
for guard in guards.into_iter() {
|
||||
if let Variable::Var(name) = &guard.var {
|
||||
let vi = self
|
||||
.module
|
||||
|
|
|
@ -315,6 +315,20 @@ impl Args {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn nth_or_key(&self, nth: usize, key: &str) -> Option<&Expr> {
|
||||
if !self.pos_args.is_empty() {
|
||||
self.pos_args.get(nth).map(|a| &a.expr)
|
||||
} else {
|
||||
self.kw_args.iter().find_map(|a| {
|
||||
if &a.keyword.content[..] == key {
|
||||
Some(&a.expr)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -5,6 +5,8 @@ i: Nat
|
|||
f(opt_i: Int or NoneType) =
|
||||
if opt_i != None, do:
|
||||
log opt_i + 1 # OK
|
||||
if isinstance(opt_i, Int), do:
|
||||
log opt_i + 1 # OK
|
||||
log opt_i + 1 # ERR
|
||||
|
||||
f(1)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue