fix: some bugs

Fixed:

* argument `_` of anonymous function disappears
* els crashes
* incomplete `.update!` codegen
This commit is contained in:
Shunsuke Shibayama 2023-02-13 15:06:50 +09:00
parent da7ff0a258
commit 2574de3a68
7 changed files with 121 additions and 50 deletions

View file

@ -38,7 +38,9 @@ impl<Checker: BuildRunnable> Server<Checker> {
.filter(|warn| warn.core.main_message.ends_with("is not used")) .filter(|warn| warn.core.main_message.ends_with("is not used"))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for warn in warns { 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) { match visitor.get_min_expr(range) {
Some(Expr::Def(def)) => { Some(Expr::Def(def)) => {
let Some(mut range) = util::loc_to_range(def.loc()) else { let Some(mut range) = util::loc_to_range(def.loc()) else {

View file

@ -555,7 +555,8 @@ impl<'a> HIRVisitor<'a> {
} }
fn get_lambda_info(&self, lambda: &Lambda, token: &Token) -> Option<VarInfo> { 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> { 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> { fn get_record_info(&self, record: &Record, token: &Token) -> Option<VarInfo> {
for field in record.attrs.iter() { 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); return Some(expr);
} }
} }

View file

@ -142,7 +142,12 @@ impl<Checker: BuildRunnable> Server<Checker> {
def_loc: &AbsLocation, def_loc: &AbsLocation,
) -> ELSResult<()> { ) -> ELSResult<()> {
if let Some(module) = def_loc.module.as_ref() { 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); def_pos.line = def_pos.line.saturating_sub(1);
let def_uri = util::normalize_url(Url::from_file_path(module).unwrap()); let def_uri = util::normalize_url(Url::from_file_path(module).unwrap());
let mut default_code_block = "".to_string(); let mut default_code_block = "".to_string();

View file

@ -2195,12 +2195,17 @@ impl PyCodeGenerator {
} }
/// X.update! x -> x + 1 /// X.update! x -> x + 1
/// X = (x -> x + 1)(X) /// => X = mutate_operator((x -> x + 1)(X))
/// X = X + 1 /// TODO: should be `X = X + 1` in the above case
fn emit_call_update_311(&mut self, obj: Expr, mut args: Args) { fn emit_call_update_311(&mut self, obj: Expr, mut args: Args) {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
let acc = enum_unwrap!(obj, Expr::Accessor); let acc = enum_unwrap!(obj, Expr::Accessor);
let func = args.remove_left_or_key("f").unwrap(); 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_push_null();
self.emit_expr(func); self.emit_expr(func);
self.emit_acc(acc.clone()); self.emit_acc(acc.clone());
@ -2208,23 +2213,32 @@ impl PyCodeGenerator {
// (1 (subroutine) + argc) input objects -> 1 return object // (1 (subroutine) + argc) input objects -> 1 return object
// self.stack_dec_n((1 + 1) - 1); // self.stack_dec_n((1 + 1) - 1);
self.stack_dec(); self.stack_dec();
self.emit_precall_and_call(1);
self.stack_dec();
self.store_acc(acc); self.store_acc(acc);
self.emit_load_const(ValueObj::None); self.emit_load_const(ValueObj::None);
} }
/// X.update! x -> x + 1 /// X.update! x -> x + 1
/// X = (x -> x + 1)(X) /// X = mutate_operator((x -> x + 1)(X))
/// X = X + 1 /// X = X + 1
fn emit_call_update_310(&mut self, obj: Expr, mut args: Args) { fn emit_call_update_310(&mut self, obj: Expr, mut args: Args) {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
let acc = enum_unwrap!(obj, Expr::Accessor); let acc = enum_unwrap!(obj, Expr::Accessor);
let func = args.remove_left_or_key("f").unwrap(); 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_expr(func);
self.emit_acc(acc.clone()); self.emit_acc(acc.clone());
self.write_instr(Opcode310::CALL_FUNCTION); self.write_instr(Opcode310::CALL_FUNCTION);
self.write_arg(1); self.write_arg(1);
// (1 (subroutine) + argc) input objects -> 1 return object // (1 (subroutine) + argc) input objects -> 1 return object
self.stack_dec_n((1 + 1) - 1); 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.store_acc(acc);
self.emit_load_const(ValueObj::None); self.emit_load_const(ValueObj::None);
} }

View file

@ -261,13 +261,16 @@ impl Context {
// Literal patterns will be desugared to discard patterns // Literal patterns will be desugared to discard patterns
ast::ParamPattern::Lit(_) => unreachable!(), ast::ParamPattern::Lit(_) => unreachable!(),
ast::ParamPattern::Discard(token) => { ast::ParamPattern::Discard(token) => {
let spec_t = self.instantiate_param_sig_t( let (spec_t, errs) = match self.instantiate_param_sig_t(
&sig.raw, &sig.raw,
opt_decl_t, opt_decl_t,
&mut TyVarCache::new(self.level, self), &mut TyVarCache::new(self.level, self),
Normal, Normal,
kind, kind,
)?; ) {
Ok(ty) => (ty, TyCheckErrors::empty()),
Err(errs) => (Type::Failure, errs),
};
let def_id = DefId(get_hash(&(&self.name, "_"))); let def_id = DefId(get_hash(&(&self.name, "_")));
let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault); let kind = VarKind::parameter(def_id, DefaultInfo::NonDefault);
let vi = VarInfo::new( let vi = VarInfo::new(
@ -282,7 +285,11 @@ impl Context {
); );
sig.vi = vi.clone(); sig.vi = vi.clone();
self.params.push((Some(VarName::from_static("_")), vi)); self.params.push((Some(VarName::from_static("_")), vi));
if errs.is_empty() {
Ok(()) Ok(())
} else {
Err(errs)
}
} }
ast::ParamPattern::VarName(name) => { ast::ParamPattern::VarName(name) => {
if self if self
@ -299,13 +306,16 @@ impl Context {
} else { } else {
// ok, not defined // ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self); 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, &sig.raw,
opt_decl_t, opt_decl_t,
&mut dummy_tv_cache, &mut dummy_tv_cache,
Normal, Normal,
kind, kind,
)?; ) {
Ok(ty) => (ty, TyCheckErrors::empty()),
Err(errs) => (Type::Failure, errs),
};
let spec_t = if is_var_params { let spec_t = if is_var_params {
unknown_len_array_t(spec_t) unknown_len_array_t(spec_t)
} else { } else {
@ -313,7 +323,11 @@ impl Context {
}; };
if &name.inspect()[..] == "self" { if &name.inspect()[..] == "self" {
if let Some(self_t) = self.rec_get_self_t() { 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 { } else {
log!(err "self_t is None"); log!(err "self_t is None");
} }
@ -336,7 +350,11 @@ impl Context {
} }
sig.vi = vi.clone(); sig.vi = vi.clone();
self.params.push((Some(name.clone()), vi)); self.params.push((Some(name.clone()), vi));
if errs.is_empty() {
Ok(()) Ok(())
} else {
Err(errs)
}
} }
} }
ast::ParamPattern::Ref(name) => { ast::ParamPattern::Ref(name) => {
@ -354,21 +372,26 @@ impl Context {
} else { } else {
// ok, not defined // ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self); 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, &sig.raw,
opt_decl_t, opt_decl_t,
&mut dummy_tv_cache, &mut dummy_tv_cache,
Normal, Normal,
kind, kind,
)?; ) {
Ok(ty) => (ty, TyCheckErrors::empty()),
Err(errs) => (Type::Failure, errs),
};
if &name.inspect()[..] == "self" { if &name.inspect()[..] == "self" {
if let Some(self_t) = self.rec_get_self_t() { if let Some(self_t) = self.rec_get_self_t() {
self.sub_unify( if let Err(es) = self.sub_unify(
&spec_t, &spec_t,
&ref_(self_t), &ref_(self_t),
name.loc(), name.loc(),
Some(name.inspect()), Some(name.inspect()),
)?; ) {
errs.extend(es);
}
} else { } else {
log!(err "self_t is None"); log!(err "self_t is None");
} }
@ -386,7 +409,11 @@ impl Context {
); );
sig.vi = vi.clone(); sig.vi = vi.clone();
self.params.push((Some(name.clone()), vi)); self.params.push((Some(name.clone()), vi));
if errs.is_empty() {
Ok(()) Ok(())
} else {
Err(errs)
}
} }
} }
ast::ParamPattern::RefMut(name) => { ast::ParamPattern::RefMut(name) => {
@ -404,21 +431,26 @@ impl Context {
} else { } else {
// ok, not defined // ok, not defined
let mut dummy_tv_cache = TyVarCache::new(self.level, self); 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, &sig.raw,
opt_decl_t, opt_decl_t,
&mut dummy_tv_cache, &mut dummy_tv_cache,
Normal, Normal,
kind, kind,
)?; ) {
Ok(ty) => (ty, TyCheckErrors::empty()),
Err(errs) => (Type::Failure, errs),
};
if &name.inspect()[..] == "self" { if &name.inspect()[..] == "self" {
if let Some(self_t) = self.rec_get_self_t() { if let Some(self_t) = self.rec_get_self_t() {
self.sub_unify( if let Err(es) = self.sub_unify(
&spec_t, &spec_t,
&ref_mut(self_t, None), &ref_mut(self_t, None),
name.loc(), name.loc(),
Some(name.inspect()), Some(name.inspect()),
)?; ) {
errs.extend(es);
}
} else { } else {
log!(err "self_t is None"); log!(err "self_t is None");
} }
@ -436,7 +468,11 @@ impl Context {
); );
sig.vi = vi.clone(); sig.vi = vi.clone();
self.params.push((Some(name.clone()), vi)); self.params.push((Some(name.clone()), vi));
if errs.is_empty() {
Ok(()) Ok(())
} else {
Err(errs)
}
} }
} }
other => { other => {
@ -1045,7 +1081,7 @@ impl Context {
if let Some(sup) = if let Some(sup) =
self.rec_get_const_obj(&gen.base_or_sup().unwrap().typ().local_name()) 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 { let param_t = match sup {
TypeObj::Builtin(t) => t, TypeObj::Builtin(t) => t,
TypeObj::Generated(t) => t.base_or_sup().unwrap().typ(), TypeObj::Generated(t) => t.base_or_sup().unwrap().typ(),
@ -1086,7 +1122,7 @@ impl Context {
2, 2,
self.level, 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() { for (field, t) in req.iter() {
let muty = if field.is_const() { let muty = if field.is_const() {
Mutability::Const Mutability::Const
@ -1162,7 +1198,7 @@ impl Context {
} }
GenTypeObj::Patch(_) => { GenTypeObj::Patch(_) => {
if gen.typ().is_monomorphic() { 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( let ctx = Self::mono_patch(
gen.typ().qual_name(), gen.typ().qual_name(),
base.clone(), base.clone(),
@ -1356,7 +1392,7 @@ impl Context {
} }
fn import_erg_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> { 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 mod_cache = self.mod_cache().unwrap();
let py_mod_cache = self.py_mod_cache().unwrap(); let py_mod_cache = self.py_mod_cache().unwrap();
let path = match Self::resolve_real_path(&self.cfg, Path::new(&__name__[..])) { 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> { 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 py_mod_cache = self.py_mod_cache().unwrap();
let path = self.get_path(mod_name, __name__)?; let path = self.get_path(mod_name, __name__)?;
if py_mod_cache.get(&path).is_some() { if py_mod_cache.get(&path).is_some() {
@ -1586,12 +1622,7 @@ impl Context {
RegistrationMode::Normal, RegistrationMode::Normal,
false, false,
)?; )?;
let lhs = enum_unwrap!( let Some(hir::Expr::BinOp(hir::BinOp { lhs, .. })) = call.args.get_mut_left_or_key("pred") else { todo!("{}", call.args) };
call.args.get_mut_left_or_key("pred").unwrap(),
hir::Expr::BinOp
)
.lhs
.as_mut();
match ( match (
self.supertype_of(lhs.ref_t(), &cast_to), self.supertype_of(lhs.ref_t(), &cast_to),
self.subtype_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) (false, true) => Ok(()), // TODO: warn (needless)
// assert x in Nat (x: Int) // assert x in Nat (x: Int)
(true, false) => { (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())?; self.change_var_type(acc, cast_to.clone())?;
} }
match lhs.ref_t() { match lhs.ref_t() {

View file

@ -1017,28 +1017,45 @@ impl ASTLowerer {
} }
errs 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(&param.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 let (non_default_params, default_params): (Vec<_>, Vec<_>) = self
.module .module
.context .context
.params .params
.iter() .iter()
.partition(|(_, v)| !v.kind.has_default()); .partition(|(_, vi)| !vi.kind.has_default());
let non_default_params = non_default_params #[cfg(not(feature = "py_compatible"))]
.into_iter() let non_default_params = non_default_params.into_iter();
// necessary when `py_compatible` feature is enabled #[cfg(feature = "py_compatible")]
.filter(|(name, _)| { let non_default_params = non_default_params.into_iter().filter(|(name, _)| {
params params
.non_defaults .non_defaults
.iter() .iter()
.any(|nd| nd.name() == name.as_ref()) .any(|nd| nd.name() == name.as_ref())
}) });
let non_default_param_tys = non_default_params
.map(|(name, vi)| { .map(|(name, vi)| {
ParamTy::pos(name.as_ref().map(|n| n.inspect().clone()), vi.t.clone()) ParamTy::pos(name.as_ref().map(|n| n.inspect().clone()), vi.t.clone())
}) })
.collect(); .collect();
#[cfg(not(feature = "py_compatible"))]
let default_params = default_params.into_iter();
#[cfg(feature = "py_compatible")]
let default_params = default_params let default_params = default_params
.into_iter() .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())) .map(|(name, vi)| ParamTy::kw(name.as_ref().unwrap().inspect().clone(), vi.t.clone()))
.collect(); .collect();
if in_statement { if in_statement {
@ -1062,9 +1079,9 @@ impl ASTLowerer {
self.pop_append_errs(); self.pop_append_errs();
} }
let ty = if is_procedural { 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 { } 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 }; let t = if ty.has_qvar() { ty.quantify() } else { ty };
Ok(hir::Lambda::new(id, params, lambda.op, body, t)) Ok(hir::Lambda::new(id, params, lambda.op, body, t))

View file

@ -1,4 +1,5 @@
i = !1 i = !0
i.update! _ -> 1
i.update! i -> i * 3 i.update! i -> i * 3
assert i == 3 assert i == 3