mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 10:49:54 +00:00
fix: some bugs
Fixed: * argument `_` of anonymous function disappears * els crashes * incomplete `.update!` codegen
This commit is contained in:
parent
da7ff0a258
commit
2574de3a68
7 changed files with 121 additions and 50 deletions
|
@ -38,7 +38,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
.filter(|warn| warn.core.main_message.ends_with("is not used"))
|
||||
.collect::<Vec<_>>();
|
||||
for warn in warns {
|
||||
let range = util::loc_to_range(warn.core.loc).unwrap();
|
||||
let Some(range) = util::loc_to_range(warn.core.loc) else {
|
||||
continue;
|
||||
};
|
||||
match visitor.get_min_expr(range) {
|
||||
Some(Expr::Def(def)) => {
|
||||
let Some(mut range) = util::loc_to_range(def.loc()) else {
|
||||
|
|
|
@ -555,7 +555,8 @@ impl<'a> HIRVisitor<'a> {
|
|||
}
|
||||
|
||||
fn get_lambda_info(&self, lambda: &Lambda, token: &Token) -> Option<VarInfo> {
|
||||
self.get_block_info(&lambda.body, token)
|
||||
self.get_params_info(&lambda.params, token)
|
||||
.or_else(|| self.get_block_info(&lambda.body, token))
|
||||
}
|
||||
|
||||
fn get_array_info(&self, arr: &Array, token: &Token) -> Option<VarInfo> {
|
||||
|
@ -583,7 +584,7 @@ impl<'a> HIRVisitor<'a> {
|
|||
|
||||
fn get_record_info(&self, record: &Record, token: &Token) -> Option<VarInfo> {
|
||||
for field in record.attrs.iter() {
|
||||
if let Some(expr) = self.get_block_info(&field.body.block, token) {
|
||||
if let Some(expr) = self.get_def_info(field, token) {
|
||||
return Some(expr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,7 +142,12 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
def_loc: &AbsLocation,
|
||||
) -> ELSResult<()> {
|
||||
if let Some(module) = def_loc.module.as_ref() {
|
||||
let mut def_pos = util::loc_to_range(def_loc.loc).unwrap().start;
|
||||
let mut def_pos = match util::loc_to_range(def_loc.loc) {
|
||||
Some(range) => range.start,
|
||||
None => {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
def_pos.line = def_pos.line.saturating_sub(1);
|
||||
let def_uri = util::normalize_url(Url::from_file_path(module).unwrap());
|
||||
let mut default_code_block = "".to_string();
|
||||
|
|
|
@ -2195,12 +2195,17 @@ impl PyCodeGenerator {
|
|||
}
|
||||
|
||||
/// X.update! x -> x + 1
|
||||
/// X = (x -> x + 1)(X)
|
||||
/// X = X + 1
|
||||
/// => X = mutate_operator((x -> x + 1)(X))
|
||||
/// TODO: should be `X = X + 1` in the above case
|
||||
fn emit_call_update_311(&mut self, obj: Expr, mut args: Args) {
|
||||
log!(info "entered {}", fn_name!());
|
||||
let acc = enum_unwrap!(obj, Expr::Accessor);
|
||||
let func = args.remove_left_or_key("f").unwrap();
|
||||
if !self.mutate_op_loaded {
|
||||
self.load_mutate_op();
|
||||
}
|
||||
self.emit_push_null();
|
||||
self.emit_load_name_instr(Identifier::private("#mutate_operator"));
|
||||
self.emit_push_null();
|
||||
self.emit_expr(func);
|
||||
self.emit_acc(acc.clone());
|
||||
|
@ -2208,23 +2213,32 @@ impl PyCodeGenerator {
|
|||
// (1 (subroutine) + argc) input objects -> 1 return object
|
||||
// self.stack_dec_n((1 + 1) - 1);
|
||||
self.stack_dec();
|
||||
self.emit_precall_and_call(1);
|
||||
self.stack_dec();
|
||||
self.store_acc(acc);
|
||||
self.emit_load_const(ValueObj::None);
|
||||
}
|
||||
|
||||
/// X.update! x -> x + 1
|
||||
/// X = (x -> x + 1)(X)
|
||||
/// X = mutate_operator((x -> x + 1)(X))
|
||||
/// X = X + 1
|
||||
fn emit_call_update_310(&mut self, obj: Expr, mut args: Args) {
|
||||
log!(info "entered {}", fn_name!());
|
||||
let acc = enum_unwrap!(obj, Expr::Accessor);
|
||||
let func = args.remove_left_or_key("f").unwrap();
|
||||
if !self.mutate_op_loaded {
|
||||
self.load_mutate_op();
|
||||
}
|
||||
self.emit_load_name_instr(Identifier::private("#mutate_operator"));
|
||||
self.emit_expr(func);
|
||||
self.emit_acc(acc.clone());
|
||||
self.write_instr(Opcode310::CALL_FUNCTION);
|
||||
self.write_arg(1);
|
||||
// (1 (subroutine) + argc) input objects -> 1 return object
|
||||
self.stack_dec_n((1 + 1) - 1);
|
||||
self.write_instr(Opcode310::CALL_FUNCTION);
|
||||
self.write_arg(1);
|
||||
self.stack_dec();
|
||||
self.store_acc(acc);
|
||||
self.emit_load_const(ValueObj::None);
|
||||
}
|
||||
|
|
|
@ -261,13 +261,16 @@ impl Context {
|
|||
// Literal patterns will be desugared to discard patterns
|
||||
ast::ParamPattern::Lit(_) => unreachable!(),
|
||||
ast::ParamPattern::Discard(token) => {
|
||||
let spec_t = self.instantiate_param_sig_t(
|
||||
let (spec_t, errs) = match self.instantiate_param_sig_t(
|
||||
&sig.raw,
|
||||
opt_decl_t,
|
||||
&mut TyVarCache::new(self.level, self),
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
) {
|
||||
Ok(ty) => (ty, TyCheckErrors::empty()),
|
||||
Err(errs) => (Type::Failure, errs),
|
||||
};
|
||||
let def_id = DefId(get_hash(&(&self.name, "_")));
|
||||
let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault);
|
||||
let vi = VarInfo::new(
|
||||
|
@ -282,7 +285,11 @@ impl Context {
|
|||
);
|
||||
sig.vi = vi.clone();
|
||||
self.params.push((Some(VarName::from_static("_")), vi));
|
||||
Ok(())
|
||||
if errs.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errs)
|
||||
}
|
||||
}
|
||||
ast::ParamPattern::VarName(name) => {
|
||||
if self
|
||||
|
@ -299,13 +306,16 @@ impl Context {
|
|||
} else {
|
||||
// ok, not defined
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t = self.instantiate_param_sig_t(
|
||||
let (spec_t, mut errs) = match self.instantiate_param_sig_t(
|
||||
&sig.raw,
|
||||
opt_decl_t,
|
||||
&mut dummy_tv_cache,
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
) {
|
||||
Ok(ty) => (ty, TyCheckErrors::empty()),
|
||||
Err(errs) => (Type::Failure, errs),
|
||||
};
|
||||
let spec_t = if is_var_params {
|
||||
unknown_len_array_t(spec_t)
|
||||
} else {
|
||||
|
@ -313,7 +323,11 @@ impl Context {
|
|||
};
|
||||
if &name.inspect()[..] == "self" {
|
||||
if let Some(self_t) = self.rec_get_self_t() {
|
||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))?;
|
||||
if let Err(es) =
|
||||
self.sub_unify(&spec_t, &self_t, name.loc(), Some(name.inspect()))
|
||||
{
|
||||
errs.extend(es);
|
||||
}
|
||||
} else {
|
||||
log!(err "self_t is None");
|
||||
}
|
||||
|
@ -336,7 +350,11 @@ impl Context {
|
|||
}
|
||||
sig.vi = vi.clone();
|
||||
self.params.push((Some(name.clone()), vi));
|
||||
Ok(())
|
||||
if errs.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ParamPattern::Ref(name) => {
|
||||
|
@ -354,21 +372,26 @@ impl Context {
|
|||
} else {
|
||||
// ok, not defined
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t = self.instantiate_param_sig_t(
|
||||
let (spec_t, mut errs) = match self.instantiate_param_sig_t(
|
||||
&sig.raw,
|
||||
opt_decl_t,
|
||||
&mut dummy_tv_cache,
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
) {
|
||||
Ok(ty) => (ty, TyCheckErrors::empty()),
|
||||
Err(errs) => (Type::Failure, errs),
|
||||
};
|
||||
if &name.inspect()[..] == "self" {
|
||||
if let Some(self_t) = self.rec_get_self_t() {
|
||||
self.sub_unify(
|
||||
if let Err(es) = self.sub_unify(
|
||||
&spec_t,
|
||||
&ref_(self_t),
|
||||
name.loc(),
|
||||
Some(name.inspect()),
|
||||
)?;
|
||||
) {
|
||||
errs.extend(es);
|
||||
}
|
||||
} else {
|
||||
log!(err "self_t is None");
|
||||
}
|
||||
|
@ -386,7 +409,11 @@ impl Context {
|
|||
);
|
||||
sig.vi = vi.clone();
|
||||
self.params.push((Some(name.clone()), vi));
|
||||
Ok(())
|
||||
if errs.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ParamPattern::RefMut(name) => {
|
||||
|
@ -404,21 +431,26 @@ impl Context {
|
|||
} else {
|
||||
// ok, not defined
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t = self.instantiate_param_sig_t(
|
||||
let (spec_t, mut errs) = match self.instantiate_param_sig_t(
|
||||
&sig.raw,
|
||||
opt_decl_t,
|
||||
&mut dummy_tv_cache,
|
||||
Normal,
|
||||
kind,
|
||||
)?;
|
||||
) {
|
||||
Ok(ty) => (ty, TyCheckErrors::empty()),
|
||||
Err(errs) => (Type::Failure, errs),
|
||||
};
|
||||
if &name.inspect()[..] == "self" {
|
||||
if let Some(self_t) = self.rec_get_self_t() {
|
||||
self.sub_unify(
|
||||
if let Err(es) = self.sub_unify(
|
||||
&spec_t,
|
||||
&ref_mut(self_t, None),
|
||||
name.loc(),
|
||||
Some(name.inspect()),
|
||||
)?;
|
||||
) {
|
||||
errs.extend(es);
|
||||
}
|
||||
} else {
|
||||
log!(err "self_t is None");
|
||||
}
|
||||
|
@ -436,7 +468,11 @@ impl Context {
|
|||
);
|
||||
sig.vi = vi.clone();
|
||||
self.params.push((Some(name.clone()), vi));
|
||||
Ok(())
|
||||
if errs.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(errs)
|
||||
}
|
||||
}
|
||||
}
|
||||
other => {
|
||||
|
@ -1045,7 +1081,7 @@ impl Context {
|
|||
if let Some(sup) =
|
||||
self.rec_get_const_obj(&gen.base_or_sup().unwrap().typ().local_name())
|
||||
{
|
||||
let sup = enum_unwrap!(sup, ValueObj::Type);
|
||||
let ValueObj::Type(sup) = sup else { todo!("{sup}") };
|
||||
let param_t = match sup {
|
||||
TypeObj::Builtin(t) => t,
|
||||
TypeObj::Generated(t) => t.base_or_sup().unwrap().typ(),
|
||||
|
@ -1086,7 +1122,7 @@ impl Context {
|
|||
2,
|
||||
self.level,
|
||||
);
|
||||
let req = enum_unwrap!(gen.base_or_sup().unwrap(), TypeObj::Builtin:(Type::Record:(_)));
|
||||
let Some(TypeObj::Builtin(Type::Record(req))) = gen.base_or_sup() else { todo!("{gen}") };
|
||||
for (field, t) in req.iter() {
|
||||
let muty = if field.is_const() {
|
||||
Mutability::Const
|
||||
|
@ -1162,7 +1198,7 @@ impl Context {
|
|||
}
|
||||
GenTypeObj::Patch(_) => {
|
||||
if gen.typ().is_monomorphic() {
|
||||
let base = enum_unwrap!(gen.base_or_sup().unwrap(), TypeObj::Builtin);
|
||||
let Some(TypeObj::Builtin(base)) = gen.base_or_sup() else { todo!("{gen}") };
|
||||
let ctx = Self::mono_patch(
|
||||
gen.typ().qual_name(),
|
||||
base.clone(),
|
||||
|
@ -1356,7 +1392,7 @@ impl Context {
|
|||
}
|
||||
|
||||
fn import_erg_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> {
|
||||
let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
|
||||
let ValueObj::Str(__name__) = mod_name.value.clone() else { todo!("{mod_name}") };
|
||||
let mod_cache = self.mod_cache().unwrap();
|
||||
let py_mod_cache = self.py_mod_cache().unwrap();
|
||||
let path = match Self::resolve_real_path(&self.cfg, Path::new(&__name__[..])) {
|
||||
|
@ -1514,7 +1550,7 @@ impl Context {
|
|||
}
|
||||
|
||||
fn import_py_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> {
|
||||
let __name__ = enum_unwrap!(mod_name.value.clone(), ValueObj::Str);
|
||||
let ValueObj::Str(__name__) = mod_name.value.clone() else { todo!("{mod_name}") };
|
||||
let py_mod_cache = self.py_mod_cache().unwrap();
|
||||
let path = self.get_path(mod_name, __name__)?;
|
||||
if py_mod_cache.get(&path).is_some() {
|
||||
|
@ -1586,12 +1622,7 @@ impl Context {
|
|||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let lhs = enum_unwrap!(
|
||||
call.args.get_mut_left_or_key("pred").unwrap(),
|
||||
hir::Expr::BinOp
|
||||
)
|
||||
.lhs
|
||||
.as_mut();
|
||||
let Some(hir::Expr::BinOp(hir::BinOp { lhs, .. })) = call.args.get_mut_left_or_key("pred") else { todo!("{}", call.args) };
|
||||
match (
|
||||
self.supertype_of(lhs.ref_t(), &cast_to),
|
||||
self.subtype_of(lhs.ref_t(), &cast_to),
|
||||
|
@ -1602,7 +1633,7 @@ impl Context {
|
|||
(false, true) => Ok(()), // TODO: warn (needless)
|
||||
// assert x in Nat (x: Int)
|
||||
(true, false) => {
|
||||
if let hir::Expr::Accessor(ref acc) = lhs {
|
||||
if let hir::Expr::Accessor(ref acc) = lhs.as_ref() {
|
||||
self.change_var_type(acc, cast_to.clone())?;
|
||||
}
|
||||
match lhs.ref_t() {
|
||||
|
|
|
@ -1017,28 +1017,45 @@ impl ASTLowerer {
|
|||
}
|
||||
errs
|
||||
})?;
|
||||
// suppress warns of lambda types, e.g. `(x: Int, y: Int) -> Int`
|
||||
if self.module.context.subtype_of(body.ref_t(), &Type::Type) {
|
||||
for param in params.non_defaults.iter() {
|
||||
self.inc_ref(¶m.vi, param);
|
||||
}
|
||||
if let Some(var_param) = params.var_params.as_deref() {
|
||||
self.inc_ref(&var_param.vi, var_param);
|
||||
}
|
||||
for default in params.defaults.iter() {
|
||||
self.inc_ref(&default.sig.vi, &default.sig);
|
||||
}
|
||||
}
|
||||
let (non_default_params, default_params): (Vec<_>, Vec<_>) = self
|
||||
.module
|
||||
.context
|
||||
.params
|
||||
.iter()
|
||||
.partition(|(_, v)| !v.kind.has_default());
|
||||
let non_default_params = non_default_params
|
||||
.into_iter()
|
||||
// necessary when `py_compatible` feature is enabled
|
||||
.filter(|(name, _)| {
|
||||
params
|
||||
.non_defaults
|
||||
.iter()
|
||||
.any(|nd| nd.name() == name.as_ref())
|
||||
})
|
||||
.partition(|(_, vi)| !vi.kind.has_default());
|
||||
#[cfg(not(feature = "py_compatible"))]
|
||||
let non_default_params = non_default_params.into_iter();
|
||||
#[cfg(feature = "py_compatible")]
|
||||
let non_default_params = non_default_params.into_iter().filter(|(name, _)| {
|
||||
params
|
||||
.non_defaults
|
||||
.iter()
|
||||
.any(|nd| nd.name() == name.as_ref())
|
||||
});
|
||||
let non_default_param_tys = non_default_params
|
||||
.map(|(name, vi)| {
|
||||
ParamTy::pos(name.as_ref().map(|n| n.inspect().clone()), vi.t.clone())
|
||||
})
|
||||
.collect();
|
||||
#[cfg(not(feature = "py_compatible"))]
|
||||
let default_params = default_params.into_iter();
|
||||
#[cfg(feature = "py_compatible")]
|
||||
let default_params = default_params
|
||||
.into_iter()
|
||||
.filter(|(name, _)| params.defaults.iter().any(|d| d.name() == name.as_ref()))
|
||||
.filter(|(name, _)| params.defaults.iter().any(|d| d.name() == name.as_ref()));
|
||||
let default_param_tys = default_params
|
||||
.map(|(name, vi)| ParamTy::kw(name.as_ref().unwrap().inspect().clone(), vi.t.clone()))
|
||||
.collect();
|
||||
if in_statement {
|
||||
|
@ -1062,9 +1079,9 @@ impl ASTLowerer {
|
|||
self.pop_append_errs();
|
||||
}
|
||||
let ty = if is_procedural {
|
||||
proc(non_default_params, None, default_params, body.t())
|
||||
proc(non_default_param_tys, None, default_param_tys, body.t())
|
||||
} else {
|
||||
func(non_default_params, None, default_params, body.t())
|
||||
func(non_default_param_tys, None, default_param_tys, body.t())
|
||||
};
|
||||
let t = if ty.has_qvar() { ty.quantify() } else { ty };
|
||||
Ok(hir::Lambda::new(id, params, lambda.op, body, t))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
i = !1
|
||||
i = !0
|
||||
i.update! _ -> 1
|
||||
i.update! i -> i * 3
|
||||
assert i == 3
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue