Merge branch 'main' into pr/320

This commit is contained in:
Shunsuke Shibayama 2023-06-09 22:04:44 +09:00
commit 924b22a171
91 changed files with 1836 additions and 1027 deletions

View file

@ -10,7 +10,7 @@ use erg_parser::build_ast::ASTBuilder;
use crate::artifact::{BuildRunnable, Buildable, CompleteArtifact, IncompleteArtifact};
use crate::context::{Context, ContextProvider, ModuleContext};
use crate::effectcheck::SideEffectChecker;
use crate::error::{CompileError, CompileErrors};
use crate::error::{CompileError, CompileErrors, LowerWarnings};
use crate::lower::ASTLowerer;
use crate::module::SharedCompilerResource;
use crate::ownercheck::OwnershipChecker;
@ -66,18 +66,26 @@ impl Runnable for HIRBuilder {
fn exec(&mut self) -> Result<ExitStatus, Self::Errs> {
let mut builder = ASTBuilder::new(self.cfg().copy());
let ast = builder.build(self.cfg_mut().input.read())?;
let artifact = self.check(ast, "exec").map_err(|arti| arti.errors)?;
artifact.warns.fmt_all_stderr();
let artifact = builder
.build(self.cfg_mut().input.read())
.map_err(|arti| arti.errors)?;
artifact.warns.write_all_stderr();
let artifact = self
.check(artifact.ast, "exec")
.map_err(|arti| arti.errors)?;
artifact.warns.write_all_stderr();
println!("{}", artifact.object);
Ok(ExitStatus::compile_passed(artifact.warns.len()))
}
fn eval(&mut self, src: String) -> Result<String, Self::Errs> {
let mut builder = ASTBuilder::new(self.cfg().copy());
let ast = builder.build(src)?;
let artifact = self.check(ast, "eval").map_err(|arti| arti.errors)?;
artifact.warns.fmt_all_stderr();
let artifact = builder.build(src).map_err(|arti| arti.errors)?;
artifact.warns.write_all_stderr();
let artifact = self
.check(artifact.ast, "eval")
.map_err(|arti| arti.errors)?;
artifact.warns.write_all_stderr();
Ok(artifact.object.to_string())
}
}
@ -148,10 +156,13 @@ impl HIRBuilder {
mode: &str,
) -> Result<CompleteArtifact, IncompleteArtifact> {
let mut ast_builder = ASTBuilder::new(self.cfg().copy());
let ast = ast_builder.build(src).map_err(|errs| {
IncompleteArtifact::new(None, CompileErrors::from(errs), CompileErrors::empty())
})?;
self.check(ast, mode)
let artifact = ast_builder
.build(src)
.map_err(|iart| IncompleteArtifact::new(None, iart.errors.into(), iart.warns.into()))?;
self.lowerer
.warns
.extend(LowerWarnings::from(artifact.warns));
self.check(artifact.ast, mode)
}
pub fn pop_mod_ctx(&mut self) -> Option<ModuleContext> {

View file

@ -7,9 +7,10 @@ use std::process;
use crate::ty::codeobj::{CodeObj, CodeObjFlags, MakeFunctionFlags};
use crate::ty::value::GenTypeObj;
use erg_common::cache::CacheSet;
use erg_common::config::{ErgConfig, Input};
use erg_common::config::ErgConfig;
use erg_common::env::erg_std_path;
use erg_common::error::{ErrorDisplay, Location};
use erg_common::io::Input;
use erg_common::opcode::{CommonOpcode, CompareOp};
use erg_common::opcode308::Opcode308;
use erg_common::opcode310::Opcode310;
@ -646,8 +647,8 @@ impl PyCodeGenerator {
}
StoreLoadKind::Local | StoreLoadKind::LocalConst => match acc_kind {
Name => LOAD_NAME as u8,
Attr => LOAD_ATTR as u8,
Method => LOAD_METHOD as u8,
UnboundAttr => LOAD_ATTR as u8,
BoundAttr => LOAD_METHOD as u8,
},
}
}
@ -669,9 +670,9 @@ impl PyCodeGenerator {
StoreLoadKind::Local | StoreLoadKind::LocalConst => {
match acc_kind {
Name => STORE_NAME as u8,
Attr => STORE_ATTR as u8,
UnboundAttr => STORE_ATTR as u8,
// cannot overwrite methods directly
Method => STORE_ATTR as u8,
BoundAttr => STORE_ATTR as u8,
}
}
}
@ -792,9 +793,9 @@ impl PyCodeGenerator {
log!(info "entered {} ({ident})", fn_name!());
let escaped = escape_ident(ident);
let name = self
.local_search(&escaped, Attr)
.local_search(&escaped, UnboundAttr)
.unwrap_or_else(|| self.register_attr(escaped));
let instr = self.select_load_instr(name.kind, Attr);
let instr = self.select_load_instr(name.kind, UnboundAttr);
self.write_instr(instr);
self.write_arg(name.idx);
if self.py_version.minor >= Some(11) {
@ -809,9 +810,9 @@ impl PyCodeGenerator {
}
let escaped = escape_ident(ident);
let name = self
.local_search(&escaped, Method)
.local_search(&escaped, BoundAttr)
.unwrap_or_else(|| self.register_method(escaped));
let instr = self.select_load_instr(name.kind, Method);
let instr = self.select_load_instr(name.kind, BoundAttr);
self.write_instr(instr);
self.write_arg(name.idx);
if self.py_version.minor >= Some(11) {
@ -866,7 +867,7 @@ impl PyCodeGenerator {
}
Accessor::Attr(attr) => {
self.emit_expr(*attr.obj);
self.emit_store_instr(attr.ident, Attr);
self.emit_store_instr(attr.ident, UnboundAttr);
}
}
}
@ -1010,7 +1011,7 @@ impl PyCodeGenerator {
self.emit_precall_and_call(argc);
} else {
match kind {
AccessKind::Method => self.write_instr(Opcode310::CALL_METHOD),
AccessKind::BoundAttr => self.write_instr(Opcode310::CALL_METHOD),
_ => self.write_instr(Opcode310::CALL_FUNCTION),
}
self.write_arg(argc);
@ -2188,7 +2189,7 @@ impl PyCodeGenerator {
let is_py_api = method_name.is_py_api();
self.emit_expr(obj);
self.emit_load_method_instr(method_name);
self.emit_args_311(args, Method, is_py_api);
self.emit_args_311(args, BoundAttr, is_py_api);
}
fn emit_var_args_311(&mut self, pos_len: usize, var_args: &PosArg) {
@ -3121,7 +3122,7 @@ impl PyCodeGenerator {
self.emit_load_name_instr(Identifier::private("#path"));
self.emit_load_method_instr(Identifier::public("append"));
self.emit_load_const(erg_std_path().to_str().unwrap());
self.emit_call_instr(1, Method);
self.emit_call_instr(1, BoundAttr);
self.stack_dec();
self.emit_pop_top();
let erg_std_mod = Identifier::public("_erg_std_prelude");

View file

@ -80,19 +80,31 @@ impl Name {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AccessKind {
Name,
Attr,
Method,
/// class/module attr
/// e.g. `Str.center`
UnboundAttr,
/// method/instance attr
/// e.g. `"aaa".center`
///
/// can also access class/module attrs
BoundAttr,
}
impl AccessKind {
pub const fn is_local(&self) -> bool {
matches!(self, Self::Name)
}
pub const fn is_attr(&self) -> bool {
matches!(self, Self::Attr)
pub const fn is_unbound_attr(&self) -> bool {
matches!(self, Self::UnboundAttr)
}
pub const fn is_method(&self) -> bool {
matches!(self, Self::Method)
pub const fn is_bound_attr(&self) -> bool {
matches!(self, Self::BoundAttr)
}
pub fn matches(&self, vi: &VarInfo) -> bool {
match self {
Self::Name | Self::BoundAttr => true,
Self::UnboundAttr => !vi.kind.is_instance_attr(),
}
}
}
@ -155,19 +167,19 @@ impl Runnable for Compiler {
let warns = self
.compile_and_dump_as_pyc(path, src, "exec")
.map_err(|eart| {
eart.warns.fmt_all_stderr();
eart.warns.write_all_stderr();
eart.errors
})?;
warns.fmt_all_stderr();
warns.write_all_stderr();
Ok(ExitStatus::compile_passed(warns.len()))
}
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
let arti = self.compile(src, "eval").map_err(|eart| {
eart.warns.fmt_all_stderr();
eart.warns.write_all_stderr();
eart.errors
})?;
arti.warns.fmt_all_stderr();
arti.warns.write_all_stderr();
Ok(arti.object.code_info(Some(self.code_generator.py_version)))
}
}

View file

@ -301,6 +301,13 @@ impl Context {
panic!("err: {err}");
}
}
} else if typ.has_undoable_linked_var() {
if let Err(err) = self.overwrite_typarams(typ, rhs) {
Self::undo_substitute_typarams(typ);
if DEBUG_MODE {
panic!("err: {err}");
}
}
}
for rhs_sup in rhs_ctx.super_traits.iter() {
// Not `supertype_of` (only structures are compared)
@ -459,8 +466,8 @@ impl Context {
// => ?P.undoable_link(Int)
// => Mul Int :> Int
(FreeVar(lfv), rhs) => {
if let FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } = &*lfv.borrow() {
return self.supertype_of(t, rhs);
if let Some(t) = lfv.get_linked() {
return self.supertype_of(&t, rhs);
}
if let Some((_sub, sup)) = lfv.get_subsup() {
lfv.undoable_link(rhs);
@ -482,8 +489,8 @@ impl Context {
}
}
(lhs, FreeVar(rfv)) => {
if let FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } = &*rfv.borrow() {
return self.supertype_of(lhs, t);
if let Some(t) = rfv.get_linked() {
return self.supertype_of(lhs, &t);
}
if let Some((sub, _sup)) = rfv.get_subsup() {
rfv.undoable_link(lhs);
@ -908,15 +915,23 @@ impl Context {
}
}
_ => {
if let (Ok(sup), Ok(sub)) = (
match (
self.convert_tp_into_type(sup_p.clone()),
self.convert_tp_into_type(sub_p.clone()),
) {
return match variance {
Variance::Contravariant => self.subtype_of(&sup, &sub),
Variance::Covariant => self.supertype_of(&sup, &sub),
Variance::Invariant => self.same_type_of(&sup, &sub),
};
(Ok(sup), Ok(sub)) => {
return match variance {
Variance::Contravariant => self.subtype_of(&sup, &sub),
Variance::Covariant => self.supertype_of(&sup, &sub),
Variance::Invariant => self.same_type_of(&sup, &sub),
};
}
(Err(le), Err(re)) => {
log!(err "cannot convert {le}, {re} to types")
}
(Err(err), _) | (_, Err(err)) => {
log!(err "cannot convert {err} to a type");
}
}
self.eq_tp(sup_p, sub_p)
}

View file

@ -1338,6 +1338,11 @@ impl Context {
TyParam::FreeVar(fv) if fv.is_linked() => self.convert_tp_into_type(fv.crack().clone()),
TyParam::Type(t) => Ok(t.as_ref().clone()),
TyParam::Mono(name) => Ok(Type::Mono(name)),
TyParam::App { name, args } => Ok(Type::Poly { name, params: args }),
TyParam::Proj { obj, attr } => {
let lhs = self.convert_tp_into_type(*obj)?;
Ok(lhs.proj(attr))
}
// TyParam::Erased(_t) => Ok(Type::Obj),
TyParam::Value(v) => self.convert_value_into_type(v).map_err(TyParam::Value),
// TODO: Dict, Set
@ -1650,6 +1655,20 @@ impl Context {
Ok(())
}
pub(crate) fn overwrite_typarams(&self, qt: &Type, st: &Type) -> EvalResult<()> {
let qtps = qt.typarams();
let stps = st.typarams();
if qt.qual_name() != st.qual_name() || qtps.len() != stps.len() {
log!(err "{qt} / {st}");
log!(err "[{}] [{}]", erg_common::fmt_vec(&qtps), erg_common::fmt_vec(&stps));
return Ok(()); // TODO: e.g. Sub(Int) / Eq and Sub(?T)
}
for (qtp, stp) in qtps.into_iter().zip(stps.into_iter()) {
self.overwrite_typaram(qtp, stp)?;
}
Ok(())
}
fn substitute_typaram(&self, qtp: TyParam, stp: TyParam) -> EvalResult<()> {
match qtp {
TyParam::FreeVar(ref fv) if fv.is_generalized() => {
@ -1693,6 +1712,49 @@ impl Context {
Ok(())
}
fn overwrite_typaram(&self, qtp: TyParam, stp: TyParam) -> EvalResult<()> {
match qtp {
TyParam::FreeVar(ref fv) if fv.is_undoable_linked() => {
if !stp.is_unbound_var() || !stp.is_generalized() {
fv.undoable_link(&stp);
}
if let Err(errs) = self.sub_unify_tp(&stp, &qtp, None, &(), false) {
log!(err "{errs}");
}
Ok(())
}
TyParam::Type(qt) => self.overwrite_type(stp, *qt),
TyParam::Value(ValueObj::Type(qt)) => self.overwrite_type(stp, qt.into_typ()),
_ => Ok(()),
}
}
fn overwrite_type(&self, stp: TyParam, qt: Type) -> EvalResult<()> {
let st = self.convert_tp_into_type(stp).map_err(|tp| {
EvalError::not_a_type_error(
self.cfg.input.clone(),
line!() as usize,
().loc(),
self.caused_by(),
&tp.to_string(),
)
})?;
if qt.has_undoable_linked_var() {
if let Ok(qt) = <&FreeTyVar>::try_from(&qt) {
if !st.is_unbound_var() || !st.is_generalized() {
qt.undoable_link(&st);
}
}
}
if !st.is_unbound_var() || !st.is_generalized() {
self.overwrite_typarams(&qt, &st)?;
}
if let Err(errs) = self.sub_unify(&st, &qt, &(), None) {
log!(err "{errs}");
}
Ok(())
}
pub(crate) fn undo_substitute_typarams(substituted_q: &Type) {
for tp in substituted_q.typarams().into_iter() {
match tp {

View file

@ -303,7 +303,9 @@ pub(crate) fn sub_tpdict_get<'d>(
let mut matches = vec![];
for (k, v) in dict.iter() {
match (<&Type>::try_from(key), <&Type>::try_from(k)) {
(Ok(idx), Ok(kt)) if ctx.subtype_of(&idx.lower_bounded(), &kt.lower_bounded()) => {
(Ok(idx), Ok(kt))
if ctx.subtype_of(&idx.lower_bounded(), &kt.lower_bounded()) || dict.len() == 1 =>
{
matches.push((idx, kt, v));
}
(_, _) if key == k => {

View file

@ -2,9 +2,9 @@
use std::option::Option; // conflicting to Type::Option
use std::path::{Path, PathBuf};
use erg_common::config::Input;
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
use erg_common::error::{ErrorCore, Location, SubMessage};
use erg_common::io::Input;
use erg_common::levenshtein;
use erg_common::set::Set;
use erg_common::traits::{Locational, NoTypeDisplay, Stream};
@ -420,7 +420,7 @@ impl Context {
) -> Triple<VarInfo, TyCheckError> {
if let Some(vi) = self.get_current_scope_var(&ident.name) {
match self.validate_visibility(ident, vi, input, namespace) {
Ok(()) => {
Ok(()) if acc_kind.matches(vi) => {
return Triple::Ok(vi.clone());
}
Err(err) => {
@ -428,6 +428,7 @@ impl Context {
return Triple::Err(err);
}
}
_ => {}
}
} else if let Some((name, _vi)) = self
.future_defined_locals
@ -453,6 +454,17 @@ impl Context {
self.get_similar_name(ident.inspect()),
));
}
for (_, method_ctx) in self.methods_list.iter() {
match method_ctx.rec_get_var_info(ident, acc_kind, input, namespace) {
Triple::Ok(vi) => {
return Triple::Ok(vi);
}
Triple::Err(e) => {
return Triple::Err(e);
}
Triple::None => {}
}
}
if acc_kind.is_local() {
if let Some(parent) = self.get_outer().or_else(|| self.get_builtins()) {
return parent.rec_get_var_info(ident, acc_kind, input, namespace);
@ -468,7 +480,7 @@ impl Context {
) -> Option<&mut VarInfo> {
if let Some(vi) = self.get_current_scope_var(&ident.name) {
match self.validate_visibility(ident, vi, &self.cfg.input, self) {
Ok(()) => {
Ok(()) if acc_kind.matches(vi) => {
let vi = self.get_mut_current_scope_var(&ident.name).unwrap();
return Some(vi);
}
@ -477,6 +489,7 @@ impl Context {
return None;
}
}
_ => {}
}
}
if acc_kind.is_local() {
@ -500,7 +513,7 @@ impl Context {
.or_else(|| self.future_defined_locals.get(&ident.inspect()[..]))
{
match self.validate_visibility(ident, vi, input, namespace) {
Ok(()) => {
Ok(()) if acc_kind.matches(vi) => {
return Triple::Ok(vi.clone());
}
Err(err) => {
@ -508,6 +521,7 @@ impl Context {
return Triple::Err(err);
}
}
_ => {}
}
}
if acc_kind.is_local() {
@ -562,9 +576,10 @@ impl Context {
}
_ => {}
}
// class/module attr
if let Ok(singular_ctxs) = self.get_singular_ctxs_by_hir_expr(obj, namespace) {
for ctx in singular_ctxs {
match ctx.rec_get_var_info(ident, AccessKind::Attr, input, namespace) {
match ctx.rec_get_var_info(ident, AccessKind::UnboundAttr, input, namespace) {
Triple::Ok(vi) => {
return Triple::Ok(vi);
}
@ -575,7 +590,8 @@ impl Context {
}
}
}
match self.get_attr_from_nominal_t(obj, ident, input, namespace) {
// bound method/instance attr
match self.get_bound_attr_from_nominal_t(obj, ident, input, namespace) {
Triple::Ok(vi) => {
if let Some(self_t) = vi.t.self_t() {
match self
@ -636,7 +652,7 @@ impl Context {
Triple::None
}
fn get_attr_from_nominal_t(
fn get_bound_attr_from_nominal_t(
&self,
obj: &hir::Expr,
ident: &Identifier,
@ -646,7 +662,7 @@ impl Context {
let self_t = obj.t();
if let Some(sups) = self.get_nominal_super_type_ctxs(&self_t) {
for ctx in sups {
match ctx.rec_get_var_info(ident, AccessKind::Attr, input, namespace) {
match ctx.rec_get_var_info(ident, AccessKind::BoundAttr, input, namespace) {
Triple::Ok(vi) => {
return Triple::Ok(vi);
}
@ -657,7 +673,7 @@ impl Context {
}
// if self is a methods context
if let Some(ctx) = self.get_same_name_context(&ctx.name) {
match ctx.rec_get_var_info(ident, AccessKind::Method, input, namespace) {
match ctx.rec_get_var_info(ident, AccessKind::BoundAttr, input, namespace) {
Triple::Ok(vi) => {
return Triple::Ok(vi);
}
@ -691,7 +707,7 @@ impl Context {
}
};
for ctx in ctxs {
match ctx.rec_get_var_info(ident, AccessKind::Attr, input, namespace) {
match ctx.rec_get_var_info(ident, AccessKind::BoundAttr, input, namespace) {
Triple::Ok(vi) => {
obj.ref_t().coerce();
return Triple::Ok(vi);
@ -702,7 +718,7 @@ impl Context {
_ => {}
}
if let Some(ctx) = self.get_same_name_context(&ctx.name) {
match ctx.rec_get_var_info(ident, AccessKind::Method, input, namespace) {
match ctx.rec_get_var_info(ident, AccessKind::BoundAttr, input, namespace) {
Triple::Ok(vi) => {
return Triple::Ok(vi);
}
@ -946,7 +962,7 @@ impl Context {
}
}
if let Some(ctx) = self.get_same_name_context(&ctx.name) {
match ctx.rec_get_var_info(attr_name, AccessKind::Method, input, namespace) {
match ctx.rec_get_var_info(attr_name, AccessKind::BoundAttr, input, namespace) {
Triple::Ok(t) => {
return Ok(t);
}
@ -3072,4 +3088,58 @@ impl Context {
)))
}
}
pub(crate) fn get_instance_attr(&self, name: &str) -> Option<&VarInfo> {
if let Some(vi) = self.locals.get(name) {
if vi.kind.is_instance_attr() {
return Some(vi);
}
}
if let Some(vi) = self.decls.get(name) {
if vi.kind.is_instance_attr() {
return Some(vi);
}
}
if self.kind.is_method_def() {
self.get_nominal_type_ctx(&mono(&self.name))
.and_then(|(_, ctx)| ctx.get_instance_attr(name))
} else {
self.methods_list.iter().find_map(|(_, ctx)| {
if ctx.kind.is_trait_impl() {
None
} else {
ctx.get_instance_attr(name)
}
})
}
}
/// does not remove instance attribute declarations
pub(crate) fn remove_class_attr(&mut self, name: &str) -> Option<(VarName, VarInfo)> {
if let Some((k, v)) = self.locals.remove_entry(name) {
if v.kind.is_instance_attr() {
self.locals.insert(k, v);
} else {
return Some((k, v));
}
} else if let Some((k, v)) = self.decls.remove_entry(name) {
if v.kind.is_instance_attr() {
self.decls.insert(k, v);
} else {
return Some((k, v));
}
}
if self.kind.is_method_def() {
self.get_mut_nominal_type_ctx(&mono(&self.name))
.and_then(|(_, ctx)| ctx.remove_class_attr(name))
} else {
self.methods_list.iter_mut().find_map(|(_, ctx)| {
if ctx.kind.is_trait_impl() {
None
} else {
ctx.remove_class_attr(name)
}
})
}
}
}

View file

@ -574,19 +574,23 @@ impl Context {
) -> TyCheckResult<Type> {
match poly_spec.acc.to_string().trim_start_matches([':', '.']) {
"Array" => {
let ctx = self
.get_nominal_type_ctx(&array_t(Type::Obj, TyParam::Failure))
.unwrap()
.1;
// TODO: kw
let mut args = poly_spec.args.pos_args();
if let Some(first) = args.next() {
let t = self.instantiate_const_expr_as_type(
&first.expr,
None,
Some((ctx, 0)),
tmp_tv_cache,
not_found_is_qvar,
)?;
let len = if let Some(len) = args.next() {
self.instantiate_const_expr(
&len.expr,
None,
Some((ctx, 1)),
tmp_tv_cache,
not_found_is_qvar,
)?
@ -824,21 +828,24 @@ impl Context {
self.instantiate_acc(acc, erased_idx, tmp_tv_cache, not_found_is_qvar)
}
ast::ConstExpr::App(app) => {
let name = match &app.acc {
ast::ConstAccessor::Local(local) => local.inspect(),
_ => return type_feature_error!(self, app.loc(), "instantiating const callee"),
let ast::ConstAccessor::Local(ident) = &app.acc else {
return type_feature_error!(self, app.loc(), "instantiating const callee");
};
let &ctx = self
.get_singular_ctxs_by_ident(ident, self)?
.first()
.unwrap_or(&self);
let mut args = vec![];
for (i, arg) in app.args.pos_args().enumerate() {
let arg_t = self.instantiate_const_expr(
&arg.expr,
Some((self, i)),
Some((ctx, i)),
tmp_tv_cache,
not_found_is_qvar,
)?;
args.push(arg_t);
}
Ok(TyParam::app(name.clone(), args))
Ok(TyParam::app(ident.inspect().clone(), args))
}
ast::ConstExpr::Array(ConstArray::Normal(array)) => {
let mut tp_arr = vec![];

View file

@ -319,6 +319,10 @@ impl ContextKind {
matches!(self, Self::MethodDefs(_))
}
pub const fn is_trait_impl(&self) -> bool {
matches!(self, Self::MethodDefs(Some(_)))
}
pub const fn is_type(&self) -> bool {
matches!(self, Self::Class | Self::Trait | Self::StructuralTrait)
}

View file

@ -9,6 +9,7 @@ use std::time::{Duration, SystemTime};
use erg_common::config::ErgMode;
use erg_common::consts::{ERG_MODE, PYTHON_MODE};
use erg_common::dict::Dict;
use erg_common::env::{is_pystd_main_module, is_std_decl_path};
use erg_common::erg_util::BUILTIN_ERG_MODS;
use erg_common::levenshtein::get_similar_name;
@ -32,7 +33,7 @@ use crate::ty::free::{Constraint, HasLevel};
use crate::ty::typaram::TyParam;
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
use crate::ty::{
GuardType, HasType, ParamTy, SubrType, Type, Variable, Visibility, VisibilityModifier,
Field, GuardType, HasType, ParamTy, SubrType, Type, Variable, Visibility, VisibilityModifier,
};
use crate::build_hir::HIRBuilder;
@ -200,7 +201,10 @@ impl Context {
} else {
None
};
if let Some(_decl) = self.decls.remove(&ident.name) {
if self
.remove_class_attr(ident.name.inspect())
.is_some_and(|(_, decl)| !decl.kind.is_auto())
{
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
self.cfg.input.clone(),
line!() as usize,
@ -266,7 +270,10 @@ impl Context {
self.absolutize(sig.ident.name.loc()),
);
self.index().register(&vi);
if let Some(_decl) = self.decls.remove(name) {
if self
.remove_class_attr(name)
.is_some_and(|(_, decl)| !decl.kind.is_auto())
{
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
self.cfg.input.clone(),
line!() as usize,
@ -452,6 +459,7 @@ impl Context {
if self
.registered_info(name.inspect(), name.is_const())
.is_some()
&& &name.inspect()[..] != "_"
{
Err(TyCheckErrors::from(TyCheckError::reassign_error(
self.cfg.input.clone(),
@ -1287,9 +1295,7 @@ impl Context {
2,
self.level,
);
if ERG_MODE {
self.gen_class_new_method(&gen, &mut ctx)?;
}
self.gen_class_new_method(&gen, &mut ctx)?;
self.register_gen_mono_type(ident, gen, ctx, Const)
} else {
let params = gen
@ -1306,9 +1312,7 @@ impl Context {
2,
self.level,
);
if ERG_MODE {
self.gen_class_new_method(&gen, &mut ctx)?;
}
self.gen_class_new_method(&gen, &mut ctx)?;
self.register_gen_poly_type(ident, gen, ctx, Const)
}
}
@ -1350,16 +1354,7 @@ impl Context {
..
} = additional
{
for (field, t) in rec.iter() {
let varname = VarName::from_str(field.symbol.clone());
let vi = VarInfo::instance_attr(
field.clone(),
t.clone(),
self.impl_of(),
ctx.name.clone(),
);
ctx.decls.insert(varname, vi);
}
self.register_instance_attrs(&mut ctx, rec)?;
}
param_t
.map(|t| self.intersection(t, additional.typ()))
@ -1421,16 +1416,7 @@ impl Context {
self.level,
);
let Some(TypeObj::Builtin{ t: Type::Record(req), .. }) = gen.base_or_sup() else { todo!("{gen}") };
for (field, t) in req.iter() {
let vi = VarInfo::instance_attr(
field.clone(),
t.clone(),
self.impl_of(),
ctx.name.clone(),
);
ctx.decls
.insert(VarName::from_str(field.symbol.clone()), vi);
}
self.register_instance_attrs(&mut ctx, req)?;
self.register_gen_mono_type(ident, gen, ctx, Const)
} else {
feature_error!(
@ -1463,16 +1449,7 @@ impl Context {
None
};
if let Some(additional) = additional {
for (field, t) in additional.iter() {
let vi = VarInfo::instance_attr(
field.clone(),
t.clone(),
self.impl_of(),
ctx.name.clone(),
);
ctx.decls
.insert(VarName::from_str(field.symbol.clone()), vi);
}
self.register_instance_attrs(&mut ctx, additional)?;
}
for sup in super_classes.into_iter() {
if let Some((_, sup_ctx)) = self.get_nominal_type_ctx(&sup) {
@ -1524,6 +1501,29 @@ impl Context {
}
}
fn register_instance_attrs(
&self,
ctx: &mut Context,
rec: &Dict<Field, Type>,
) -> CompileResult<()> {
for (field, t) in rec.iter() {
let varname = VarName::from_str(field.symbol.clone());
let vi =
VarInfo::instance_attr(field.clone(), t.clone(), self.impl_of(), ctx.name.clone());
// self.index().register(&vi);
if let Some(_ent) = ctx.decls.insert(varname.clone(), vi) {
return Err(CompileErrors::from(CompileError::duplicate_decl_error(
self.cfg.input.clone(),
line!() as usize,
varname.loc(),
self.caused_by(),
varname.inspect(),
)));
}
}
Ok(())
}
fn gen_class_new_method(&self, gen: &GenTypeObj, ctx: &mut Context) -> CompileResult<()> {
let mut methods = Self::methods(None, self.cfg.clone(), self.shared.clone(), 2, self.level);
let new_t = if let Some(base) = gen.base_or_sup() {
@ -1532,16 +1532,7 @@ impl Context {
t: Type::Record(rec),
..
} => {
for (field, t) in rec.iter() {
let varname = VarName::from_str(field.symbol.clone());
let vi = VarInfo::instance_attr(
field.clone(),
t.clone(),
self.impl_of(),
ctx.name.clone(),
);
ctx.decls.insert(varname, vi);
}
self.register_instance_attrs(ctx, rec)?;
}
other => {
methods.register_fixed_auto_impl(
@ -1557,16 +1548,31 @@ impl Context {
} else {
func0(gen.typ().clone())
};
methods.register_fixed_auto_impl(
"__new__",
new_t.clone(),
Immutable,
Visibility::BUILTIN_PRIVATE,
Some("__call__".into()),
)?;
// 必要なら、ユーザーが独自に上書きする
// users can override this if necessary
methods.register_auto_impl("new", new_t, Immutable, Visibility::BUILTIN_PUBLIC, None)?;
if ERG_MODE {
methods.register_fixed_auto_impl(
"__new__",
new_t.clone(),
Immutable,
Visibility::BUILTIN_PRIVATE,
Some("__call__".into()),
)?;
// users can override this if necessary
methods.register_auto_impl(
"new",
new_t,
Immutable,
Visibility::BUILTIN_PUBLIC,
None,
)?;
} else {
methods.register_auto_impl(
"__call__",
new_t,
Immutable,
Visibility::BUILTIN_PUBLIC,
Some("__call__".into()),
)?;
}
ctx.methods_list
.push((ClassDefType::Simple(gen.typ().clone()), methods));
Ok(())

View file

@ -446,11 +446,13 @@ impl Context {
Ok(())
}
(TyParam::Dict(sub), TyParam::Dict(sup)) => {
for (lk, lv) in sub.iter() {
if let Some(rv) = sup.get(lk).or_else(|| sub_tpdict_get(sup, lk, self)) {
self.sub_unify_tp(lv, rv, _variance, loc, allow_divergence)?;
for (sub_k, sub_v) in sub.iter() {
if let Some(sup_v) = sup.get(sub_k).or_else(|| sub_tpdict_get(sup, sub_k, self))
{
// self.sub_unify_tp(sub_k, sup_k, _variance, loc, allow_divergence)?;
self.sub_unify_tp(sub_v, sup_v, _variance, loc, allow_divergence)?;
} else {
log!(err "{sup} does not have key {lk}");
log!(err "{sup} does not have key {sub_k}");
// TODO:
return Err(TyCheckErrors::from(TyCheckError::unreachable(
self.cfg.input.clone(),

View file

@ -177,7 +177,7 @@ impl ASTLowerer {
for ctx in ctxs {
if let Triple::Ok(vi) = ctx.rec_get_var_info(
&ident.raw,
AccessKind::Attr,
AccessKind::UnboundAttr,
self.input(),
&self.module.context,
) {

View file

@ -1,5 +1,5 @@
use erg_common::config::Input;
use erg_common::error::{ErrorCore, ErrorKind::*, Location, SubMessage};
use erg_common::io::Input;
use erg_common::switch_lang;
use crate::error::*;

View file

@ -1,5 +1,5 @@
use erg_common::config::Input;
use erg_common::error::{ErrorCore, ErrorKind::*, Location, SubMessage};
use erg_common::io::Input;
use erg_common::style::{StyledStr, StyledString, StyledStrings, Stylize};
use erg_common::traits::Locational;
use erg_common::{switch_lang, Str};
@ -485,11 +485,12 @@ impl LowerError {
) -> Self {
let hint = similar_name.map(|n| {
let vis = similar_info.map_or("".into(), |vi| vi.vis.modifier.display());
let kind = similar_info.map_or("", |vi| vi.kind.display());
switch_lang!(
"japanese" => format!("似た名前の{vis}属性があります: {n}"),
"simplified_chinese" => format!("具有相同名称的{vis}属性: {n}"),
"traditional_chinese" => format!("具有相同名稱的{vis}屬性: {n}"),
"english" => format!("has a similar name {vis} attribute: {n}"),
"japanese" => format!("似た名前の{vis}{kind}属性があります: {n}"),
"simplified_chinese" => format!("具有相同名称的{vis}{kind}属性: {n}"),
"traditional_chinese" => format!("具有相同名稱的{vis}{kind}屬性: {n}"),
"english" => format!("has a similar name {vis} {kind} attribute: {n}"),
)
});
let found = StyledString::new(name, Some(ERR), Some(ATTR));
@ -1157,4 +1158,30 @@ impl LowerWarning {
caused_by,
)
}
pub fn same_name_instance_attr_warning(
input: Input,
errno: usize,
loc: Location,
caused_by: String,
name: &str,
) -> Self {
let name = StyledStr::new(readable_name(name), Some(WARN), Some(ATTR));
Self::new(
ErrorCore::new(
vec![SubMessage::only_loc(loc)],
switch_lang!(
"japanese" => format!("同名のインスタンス属性{name}が存在します"),
"simplified_chinese" => format!("同名的实例属性{name}已存在"),
"traditional_chinese" => format!("同名的實例屬性{name}已存在"),
"english" => format!("an instance attribute named {name} already exists"),
),
errno,
NameWarning,
loc,
),
input,
caused_by,
)
}
}

View file

@ -4,15 +4,15 @@ pub mod tycheck;
use std::fmt;
use erg_common::config::Input;
use erg_common::error::{
ErrorCore, ErrorDisplay, ErrorKind::*, Location, MultiErrorDisplay, SubMessage,
};
use erg_common::io::Input;
use erg_common::style::{Attribute, Color, StyledStr, StyledString, StyledStrings, Theme, THEME};
use erg_common::traits::{Locational, Stream};
use erg_common::{impl_display_and_error, impl_stream, switch_lang};
use erg_parser::error::{ParserRunnerError, ParserRunnerErrors};
use erg_parser::error::{ParseError, ParseErrors, ParserRunnerError, ParserRunnerErrors};
pub use crate::error::eval::*;
pub use crate::error::lower::*;
@ -497,6 +497,18 @@ impl From<CompileError> for CompileErrors {
}
}
impl From<CompileError> for ParseError {
fn from(err: CompileError) -> Self {
Self::new(*err.core)
}
}
impl From<CompileErrors> for ParseErrors {
fn from(err: CompileErrors) -> Self {
Self::new(err.into_iter().map(ParseError::from).collect())
}
}
impl MultiErrorDisplay<CompileError> for CompileErrors {}
impl fmt::Display for CompileErrors {
@ -524,7 +536,7 @@ mod test {
ty::{Predicate, Type},
varinfo::{AbsLocation, VarInfo},
};
use erg_common::{config::Input, error::Location};
use erg_common::{error::Location, io::Input};
use erg_parser::ast::{VarName, VisModifierSpec};
// These Erg codes are not correct grammar.

View file

@ -1,7 +1,7 @@
use std::fmt::Display;
use erg_common::config::Input;
use erg_common::error::{ErrorCore, ErrorKind::*, Location, SubMessage};
use erg_common::io::Input;
use erg_common::set::Set;
use erg_common::style::{StyledStr, StyledString, StyledStrings, Stylize};
use erg_common::traits::{Locational, NoTypeDisplay};

View file

@ -8,6 +8,9 @@
dtype: Type
size: Nat
.nan: Float
.Nan: Float
.abs: |T|(object: .NDArray(T),) -> .NDArray(T)
.add: |T|(object: .NDArray(T), other: .NDArray(T)) -> .NDArray(T)
.all: |T <: Num|(object: .NDArray(T),) -> Bool

View file

View file

@ -0,0 +1,5 @@
{
.DataFrame!;
.Series!;
.Index;
} = pyimport "core/api"

View file

@ -0,0 +1,3 @@
{.DataFrame!;} = pyimport "./frame"
{.Series!;} = pyimport "./series"
{.Index;} = pyimport "./indexes/api"

View file

@ -0,0 +1,14 @@
{.Index;} = pyimport "./indexes/api"
# I := Nat, V := Obj
.DataFrame!: (C: Type, I: Type, V: Type) -> ClassType
.DataFrame!(C, I, V) <: Input(C)
.DataFrame!(C, I, V) <: Input(I)
.DataFrame!(C, I, V) <: Output(V)
.DataFrame!.
__call__: |K, V, I|(dic: {K: [V; _]} or Iterable(Iterable(V)), index: [I; _] := [Nat; _]) -> .DataFrame!(K, I, V)
shape: (Nat, Nat)
index: .Index(_) # TODO
head: |C, I, V|(self: .DataFrame!(C, I, V), tail: Nat := {5}) -> .DataFrame!(C, I, V)
tail: |C, I, V|(self: .DataFrame!(C, I, V), tail: Nat := {5}) -> .DataFrame!(C, I, V)
info!: (self: .DataFrame!(_, _, _)) => NoneType

View file

@ -0,0 +1 @@
{.Index;} = pyimport "./base"

View file

@ -0,0 +1,2 @@
.Index: (T: Type) -> ClassType
.Index(T) <: Output(T)

View file

@ -0,0 +1,8 @@
{.Index;} = pyimport "./indexes/api"
# K := Nat, V := Obj
.Series!: (K: Type, V: Type) -> ClassType
.Series!(K, V) <: Input(K)
.Series!(K, V) <: Output(V)
.Series!.
__call__: |K, V|(iterable: Iterable(V), index: [K; _] or .Index(K) := [Nat; _]) -> .Series! K, V

View file

View file

View file

View file

View file

@ -215,12 +215,12 @@ impl ASTLowerer {
format!("{}{code}", "\n".repeat(first_line as usize))
};
match ASTBuilder::new(self.cfg().clone()).build(code) {
Ok(ast) => {
self.check_doc_ast(ast);
Ok(artifact) => {
self.check_doc_ast(artifact.ast);
}
Err(errs) => {
let errs = CompileErrors::from(errs);
self.errs.extend(errs);
Err(iart) => {
self.errs.extend(CompileErrors::from(iart.errors));
self.warns.extend(CompileErrors::from(iart.warns));
}
}
}

View file

@ -37,8 +37,8 @@ use crate::context::{
RegistrationMode, TraitImpl,
};
use crate::error::{
CompileError, CompileErrors, LowerError, LowerErrors, LowerResult, LowerWarning, LowerWarnings,
SingleLowerResult,
CompileError, CompileErrors, CompileWarning, LowerError, LowerErrors, LowerResult,
LowerWarning, LowerWarnings, SingleLowerResult,
};
use crate::hir;
use crate::hir::HIR;
@ -125,22 +125,27 @@ impl Runnable for ASTLowerer {
fn exec(&mut self) -> Result<ExitStatus, Self::Errs> {
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
let ast = ast_builder.build(self.cfg.input.read())?;
let artifact = self
.lower(ast, "exec")
let artifact = ast_builder
.build(self.cfg.input.read())
.map_err(|artifact| artifact.errors)?;
artifact.warns.fmt_all_stderr();
println!("{}", artifact.object);
artifact.warns.write_all_to(&mut self.cfg.output);
let artifact = self
.lower(artifact.ast, "exec")
.map_err(|artifact| artifact.errors)?;
artifact.warns.write_all_to(&mut self.cfg.output);
use std::io::Write;
write!(self.cfg.output, "{}", artifact.object).unwrap();
Ok(ExitStatus::compile_passed(artifact.warns.len()))
}
fn eval(&mut self, src: String) -> Result<String, Self::Errs> {
let mut ast_builder = ASTBuilder::new(self.cfg.copy());
let ast = ast_builder.build(src)?;
let artifact = ast_builder.build(src).map_err(|artifact| artifact.errors)?;
artifact.warns.write_all_stderr();
let artifact = self
.lower(ast, "eval")
.lower(artifact.ast, "eval")
.map_err(|artifact| artifact.errors)?;
artifact.warns.fmt_all_stderr();
artifact.warns.write_all_stderr();
Ok(format!("{}", artifact.object))
}
}
@ -1663,6 +1668,23 @@ impl ASTLowerer {
self.pop_append_errs();
errs
})?;
if let Some(ident) = def.sig.ident() {
if self
.module
.context
.get_instance_attr(ident.inspect())
.is_some()
{
self.warns
.push(CompileWarning::same_name_instance_attr_warning(
self.cfg.input.clone(),
line!() as usize,
ident.loc(),
self.module.context.caused_by(),
ident.inspect(),
));
}
}
}
ast::ClassAttr::Decl(_) | ast::ClassAttr::Doc(_) => {}
}
@ -1730,21 +1752,19 @@ impl ASTLowerer {
if let Some(sup_type) = call.args.get_left_or_key("Super") {
Self::check_inheritable(&self.cfg, &mut self.errs, type_obj, sup_type, &hir_def.sig);
}
let (__new__, need_to_gen_new) = if let (Some(dunder_new_vi), Some(new_vi)) = (
class_ctx.get_current_scope_var(&VarName::from_static("__new__")),
class_ctx.get_current_scope_var(&VarName::from_static("new")),
) {
(dunder_new_vi.t.clone(), new_vi.kind == VarKind::Auto)
} else {
let Some(__new__) = class_ctx.get_current_scope_var(&VarName::from_static("__new__")).or(class_ctx.get_current_scope_var(&VarName::from_static("__call__"))) else {
return unreachable_error!(LowerErrors, LowerError, self);
};
let need_to_gen_new = class_ctx
.get_current_scope_var(&VarName::from_static("new"))
.map_or(false, |vi| vi.kind == VarKind::Auto);
let require_or_sup = Self::get_require_or_sup_or_base(hir_def.body.block.remove(0));
Ok(hir::ClassDef::new(
type_obj.clone(),
hir_def.sig,
require_or_sup,
need_to_gen_new,
__new__,
__new__.t.clone(),
hir_methods,
))
}

View file

@ -1,5 +1,6 @@
use erg_common::config::ErgConfig;
use erg_common::error::MultiErrorDisplay;
use erg_common::io::Output;
use erg_common::spawn::exec_new_thread;
use erg_common::traits::Runnable;
@ -13,7 +14,8 @@ use erg_compiler::ty::constructors::{
use erg_compiler::ty::Type::*;
fn load_file(path: &'static str) -> Result<ModuleContext, CompileErrors> {
let cfg = ErgConfig::with_main_path(path.into());
let mut cfg = ErgConfig::with_main_path(path.into());
cfg.output = Output::Null;
let mut lowerer = ASTLowerer::new(cfg);
lowerer.exec()?;
Ok(lowerer.pop_mod_ctx().unwrap())
@ -26,7 +28,7 @@ fn test_infer_types() -> Result<(), ()> {
fn _test_infer_types() -> Result<(), ()> {
let module = load_file("tests/infer.er").map_err(|errs| {
errs.fmt_all_stderr();
errs.write_all_stderr();
})?;
let t = type_q("T");
let u = type_q("U");

View file

@ -148,10 +148,10 @@ impl Runnable for Transpiler {
path.set_extension("py");
let src = self.cfg.input.read();
let artifact = self.transpile(src, "exec").map_err(|eart| {
eart.warns.fmt_all_stderr();
eart.warns.write_all_stderr();
eart.errors
})?;
artifact.warns.fmt_all_stderr();
artifact.warns.write_all_stderr();
let mut f = File::create(path).unwrap();
f.write_all(artifact.object.code.as_bytes()).unwrap();
Ok(ExitStatus::compile_passed(artifact.warns.len()))
@ -159,10 +159,10 @@ impl Runnable for Transpiler {
fn eval(&mut self, src: String) -> Result<String, CompileErrors> {
let artifact = self.transpile(src, "eval").map_err(|eart| {
eart.warns.fmt_all_stderr();
eart.warns.write_all_stderr();
eart.errors
})?;
artifact.warns.fmt_all_stderr();
artifact.warns.write_all_stderr();
Ok(artifact.object.code)
}
}

View file

@ -444,6 +444,22 @@ impl SubrType {
|| self.return_t.has_qvar()
}
pub fn has_undoable_linked_var(&self) -> bool {
self.non_default_params
.iter()
.any(|pt| pt.typ().has_undoable_linked_var())
|| self
.var_params
.as_ref()
.map(|pt| pt.typ().has_undoable_linked_var())
.unwrap_or(false)
|| self
.default_params
.iter()
.any(|pt| pt.typ().has_undoable_linked_var())
|| self.return_t.has_undoable_linked_var()
}
pub fn typarams(&self) -> Vec<TyParam> {
[
self.non_default_params
@ -2450,6 +2466,58 @@ impl Type {
}
}
pub fn has_undoable_linked_var(&self) -> bool {
match self {
Self::FreeVar(fv) if fv.is_undoable_linked() => true,
Self::FreeVar(fv) if fv.is_linked() => fv.crack().has_undoable_linked_var(),
Self::FreeVar(fv) => {
if let Some((sub, sup)) = fv.get_subsup() {
fv.dummy_link();
let res_sub = sub.has_undoable_linked_var();
let res_sup = sup.has_undoable_linked_var();
fv.undo();
res_sub || res_sup
} else {
let opt_t = fv.get_type();
opt_t.map_or(false, |t| t.has_undoable_linked_var())
}
}
Self::Ref(ty) => ty.has_undoable_linked_var(),
Self::RefMut { before, after } => {
before.has_undoable_linked_var()
|| after
.as_ref()
.map(|t| t.has_undoable_linked_var())
.unwrap_or(false)
}
Self::And(lhs, rhs) | Self::Or(lhs, rhs) => {
lhs.has_undoable_linked_var() || rhs.has_undoable_linked_var()
}
Self::Not(ty) => ty.has_undoable_linked_var(),
Self::Callable { param_ts, return_t } => {
param_ts.iter().any(|t| t.has_undoable_linked_var())
|| return_t.has_undoable_linked_var()
}
Self::Subr(subr) => subr.has_undoable_linked_var(),
Self::Quantified(quant) => quant.has_undoable_linked_var(),
Self::Record(r) => r.values().any(|t| t.has_undoable_linked_var()),
Self::Refinement(refine) => {
refine.t.has_undoable_linked_var() || refine.pred.has_undoable_linked_var()
}
Self::Poly { params, .. } => params.iter().any(|tp| tp.has_undoable_linked_var()),
Self::Proj { lhs, .. } => lhs.has_undoable_linked_var(),
Self::ProjCall { lhs, args, .. } => {
lhs.has_undoable_linked_var() || args.iter().any(|tp| tp.has_undoable_linked_var())
}
Self::Structural(ty) => ty.has_undoable_linked_var(),
Self::Guard(guard) => guard.to.has_undoable_linked_var(),
Self::Bounded { sub, sup } => {
sub.has_undoable_linked_var() || sup.has_undoable_linked_var()
}
_ => false,
}
}
pub fn has_no_qvar(&self) -> bool {
!self.has_qvar()
}

View file

@ -341,6 +341,21 @@ impl Predicate {
}
}
pub fn has_undoable_linked_var(&self) -> bool {
match self {
Self::Value(_) => false,
Self::Const(_) => false,
Self::Equal { rhs, .. }
| Self::GreaterEqual { rhs, .. }
| Self::LessEqual { rhs, .. }
| Self::NotEqual { rhs, .. } => rhs.has_undoable_linked_var(),
Self::Or(lhs, rhs) | Self::And(lhs, rhs) => {
lhs.has_undoable_linked_var() || rhs.has_undoable_linked_var()
}
Self::Not(pred) => pred.has_undoable_linked_var(),
}
}
pub fn min_max<'a>(
&'a self,
min: Option<&'a TyParam>,

View file

@ -1062,6 +1062,29 @@ impl TyParam {
!self.has_unbound_var()
}
pub fn has_undoable_linked_var(&self) -> bool {
match self {
Self::FreeVar(fv) => fv.is_undoable_linked(),
Self::Type(t) => t.has_undoable_linked_var(),
Self::Proj { obj, .. } => obj.has_undoable_linked_var(),
Self::Array(ts) | Self::Tuple(ts) => ts.iter().any(|t| t.has_undoable_linked_var()),
Self::Set(ts) => ts.iter().any(|t| t.has_undoable_linked_var()),
Self::Dict(kv) => kv
.iter()
.any(|(k, v)| k.has_undoable_linked_var() || v.has_undoable_linked_var()),
Self::Record(rec) => rec.iter().any(|(_, v)| v.has_undoable_linked_var()),
Self::Lambda(lambda) => lambda.body.iter().any(|t| t.has_undoable_linked_var()),
Self::UnaryOp { val, .. } => val.has_undoable_linked_var(),
Self::BinOp { lhs, rhs, .. } => {
lhs.has_undoable_linked_var() || rhs.has_undoable_linked_var()
}
Self::App { args, .. } => args.iter().any(|p| p.has_undoable_linked_var()),
Self::Erased(t) => t.has_undoable_linked_var(),
Self::Value(ValueObj::Type(t)) => t.typ().has_undoable_linked_var(),
_ => false,
}
}
pub fn union_size(&self) -> usize {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().union_size(),

View file

@ -7,10 +7,10 @@ use std::hash::{Hash, Hasher};
use std::ops::Neg;
use std::sync::Arc;
use erg_common::config::Input;
use erg_common::dict::Dict;
use erg_common::error::{ErrorCore, ErrorKind, Location};
use erg_common::fresh::fresh_varname;
use erg_common::io::Input;
use erg_common::python_util::PythonVersion;
use erg_common::serialize::*;
use erg_common::set::Set;

View file

@ -3,7 +3,7 @@ use std::path::PathBuf;
use erg_common::error::Location;
use erg_common::set::Set;
use erg_common::Str;
use erg_common::{switch_lang, Str};
use erg_parser::ast::DefId;
@ -39,6 +39,7 @@ use Mutability::*;
pub enum VarKind {
Defined(DefId),
Declared,
InstanceAttr,
Parameter {
def_id: DefId,
var: bool,
@ -88,6 +89,38 @@ impl VarKind {
pub const fn is_builtin(&self) -> bool {
matches!(self, Self::Builtin)
}
pub const fn is_auto(&self) -> bool {
matches!(self, Self::Auto)
}
pub const fn is_instance_attr(&self) -> bool {
matches!(self, Self::InstanceAttr)
}
pub const fn display(&self) -> &'static str {
match self {
Self::Auto | Self::FixedAuto => switch_lang!(
"japanese" => "自動",
"simplified_chinese" => "自动",
"traditional_chinese" => "自動",
"english" => "auto",
),
Self::Builtin => switch_lang!(
"japanese" => "組み込み",
"simplified_chinese" => "内置",
"traditional_chinese" => "內置",
"english" => "builtin",
),
Self::InstanceAttr => switch_lang!(
"japanese" => "インスタンス",
"simplified_chinese" => "实例",
"traditional_chinese" => "實例",
"english" => "instance",
),
_ => "",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -285,12 +318,11 @@ impl VarInfo {
} else {
Mutability::Immutable
};
let kind = VarKind::Declared;
Self::new(
t,
muty,
Visibility::new(field.vis, namespace),
kind,
VarKind::InstanceAttr,
None,
impl_of,
None,