mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-01 21:21:10 +00:00
Enhance: empty classes can be generated by Class()
This commit is contained in:
parent
5b0dedd421
commit
d8f7e386c8
12 changed files with 127 additions and 78 deletions
|
@ -1146,7 +1146,7 @@ impl PyCodeGenerator {
|
||||||
log!(info "entered {} ({})", fn_name!(), class_def.sig);
|
log!(info "entered {} ({})", fn_name!(), class_def.sig);
|
||||||
self.emit_push_null();
|
self.emit_push_null();
|
||||||
let ident = class_def.sig.ident().clone();
|
let ident = class_def.sig.ident().clone();
|
||||||
let require_or_sup = class_def.require_or_sup.clone();
|
let require_or_sup = class_def.require_or_sup.clone().map(|x| *x);
|
||||||
let obj = class_def.obj.clone();
|
let obj = class_def.obj.clone();
|
||||||
self.write_instr(LOAD_BUILD_CLASS);
|
self.write_instr(LOAD_BUILD_CLASS);
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
|
@ -1162,7 +1162,7 @@ impl PyCodeGenerator {
|
||||||
self.write_arg(0);
|
self.write_arg(0);
|
||||||
self.emit_load_const(ident.inspect().clone());
|
self.emit_load_const(ident.inspect().clone());
|
||||||
// LOAD subclasses
|
// LOAD subclasses
|
||||||
let subclasses_len = self.emit_require_type(obj, *require_or_sup);
|
let subclasses_len = self.emit_require_type(obj, require_or_sup);
|
||||||
self.emit_call_instr(2 + subclasses_len, Name);
|
self.emit_call_instr(2 + subclasses_len, Name);
|
||||||
self.stack_dec_n((1 + 2 + subclasses_len) - 1);
|
self.stack_dec_n((1 + 2 + subclasses_len) - 1);
|
||||||
self.emit_store_instr(ident, Name);
|
self.emit_store_instr(ident, Name);
|
||||||
|
@ -1194,12 +1194,12 @@ impl PyCodeGenerator {
|
||||||
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
|
||||||
|
|
||||||
/// Y = Inherit X => class Y(X): ...
|
/// Y = Inherit X => class Y(X): ...
|
||||||
fn emit_require_type(&mut self, obj: GenTypeObj, require_or_sup: Expr) -> usize {
|
fn emit_require_type(&mut self, obj: GenTypeObj, require_or_sup: Option<Expr>) -> usize {
|
||||||
log!(info "entered {} ({obj}, {require_or_sup})", fn_name!());
|
log!(info "entered {} ({obj}, {require_or_sup:?})", fn_name!());
|
||||||
match obj {
|
match obj {
|
||||||
GenTypeObj::Class(_) => 0,
|
GenTypeObj::Class(_) => 0,
|
||||||
GenTypeObj::Subclass(_) => {
|
GenTypeObj::Subclass(_) => {
|
||||||
self.emit_expr(require_or_sup);
|
self.emit_expr(require_or_sup.unwrap());
|
||||||
1 // TODO: not always 1
|
1 // TODO: not always 1
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
|
@ -2728,25 +2728,38 @@ impl PyCodeGenerator {
|
||||||
|
|
||||||
fn emit_init_method(&mut self, sig: &Signature, __new__: Type) {
|
fn emit_init_method(&mut self, sig: &Signature, __new__: Type) {
|
||||||
log!(info "entered {}", fn_name!());
|
log!(info "entered {}", fn_name!());
|
||||||
|
let new_first_param = __new__.non_default_params().unwrap().first();
|
||||||
let line = sig.ln_begin().unwrap();
|
let line = sig.ln_begin().unwrap();
|
||||||
let class_name = sig.ident().inspect();
|
let class_name = sig.ident().inspect();
|
||||||
let mut ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line);
|
let mut ident = Identifier::public_with_line(DOT, Str::ever("__init__"), line);
|
||||||
ident.vi.t = __new__.clone();
|
ident.vi.t = __new__.clone();
|
||||||
let param_name = fresh_varname();
|
|
||||||
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
|
|
||||||
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
|
|
||||||
let self_param = VarName::from_str_and_line(Str::ever("self"), line);
|
let self_param = VarName::from_str_and_line(Str::ever("self"), line);
|
||||||
let self_param = NonDefaultParamSignature::new(ParamPattern::VarName(self_param), None);
|
let self_param = NonDefaultParamSignature::new(ParamPattern::VarName(self_param), None);
|
||||||
|
let (param_name, params) = if let Some(new_first_param) = new_first_param {
|
||||||
|
let param_name = new_first_param
|
||||||
|
.name()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.unwrap_or_else(fresh_varname);
|
||||||
|
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
|
||||||
|
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
|
||||||
let params = Params::new(vec![self_param, param], None, vec![], None);
|
let params = Params::new(vec![self_param, param], None, vec![], None);
|
||||||
|
(param_name, params)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
"_".into(),
|
||||||
|
Params::new(vec![self_param], None, vec![], None),
|
||||||
|
)
|
||||||
|
};
|
||||||
let subr_sig = SubrSignature::new(ident, params);
|
let subr_sig = SubrSignature::new(ident, params);
|
||||||
let mut attrs = vec![];
|
let mut attrs = vec![];
|
||||||
match __new__.non_default_params().unwrap()[0].typ() {
|
match new_first_param.map(|pt| pt.typ()) {
|
||||||
// namedtupleは仕様上::xなどの名前を使えない
|
// namedtupleは仕様上::xなどの名前を使えない
|
||||||
// {x = Int; y = Int}
|
// {x = Int; y = Int}
|
||||||
// => self::x = %x.x; self::y = %x.y
|
// => self::x = %x.x; self::y = %x.y
|
||||||
// {.x = Int; .y = Int}
|
// {.x = Int; .y = Int}
|
||||||
// => self.x = %x.x; self.y = %x.y
|
// => self.x = %x.x; self.y = %x.y
|
||||||
Type::Record(rec) => {
|
// () => pass
|
||||||
|
Some(Type::Record(rec)) => {
|
||||||
for field in rec.keys() {
|
for field in rec.keys() {
|
||||||
let obj =
|
let obj =
|
||||||
Expr::Accessor(Accessor::private_with_line(Str::from(¶m_name), line));
|
Expr::Accessor(Accessor::private_with_line(Str::from(¶m_name), line));
|
||||||
|
@ -2768,9 +2781,14 @@ impl PyCodeGenerator {
|
||||||
attrs.push(Expr::AttrDef(attr_def));
|
attrs.push(Expr::AttrDef(attr_def));
|
||||||
}
|
}
|
||||||
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
|
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
|
||||||
attrs.push(Expr::Lit(Literal::try_from(none).unwrap()));
|
attrs.push(Expr::Lit(Literal::new(ValueObj::None, none)));
|
||||||
|
}
|
||||||
|
Some(other) => todo!("{other}"),
|
||||||
|
None => {
|
||||||
|
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
|
||||||
|
let none = Expr::Lit(Literal::new(ValueObj::None, none));
|
||||||
|
attrs.push(none);
|
||||||
}
|
}
|
||||||
other => todo!("{other}"),
|
|
||||||
}
|
}
|
||||||
let block = Block::new(attrs);
|
let block = Block::new(attrs);
|
||||||
let body = DefBody::new(EQUAL, block, DefId(0));
|
let body = DefBody::new(EQUAL, block, DefId(0));
|
||||||
|
@ -2787,24 +2805,37 @@ impl PyCodeGenerator {
|
||||||
let class_ident = sig.ident();
|
let class_ident = sig.ident();
|
||||||
let line = sig.ln_begin().unwrap();
|
let line = sig.ln_begin().unwrap();
|
||||||
let mut ident = Identifier::public_with_line(DOT, Str::ever("new"), line);
|
let mut ident = Identifier::public_with_line(DOT, Str::ever("new"), line);
|
||||||
ident.vi.t = __new__;
|
|
||||||
let param_name = fresh_varname();
|
|
||||||
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
|
|
||||||
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
|
|
||||||
let sig = SubrSignature::new(ident, Params::new(vec![param], None, vec![], None));
|
|
||||||
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
|
|
||||||
Str::from(param_name),
|
|
||||||
line,
|
|
||||||
)));
|
|
||||||
let class = Expr::Accessor(Accessor::Ident(class_ident.clone()));
|
let class = Expr::Accessor(Accessor::Ident(class_ident.clone()));
|
||||||
let mut new_ident =
|
let mut new_ident =
|
||||||
Identifier::bare(None, VarName::from_str_and_line(Str::ever("__new__"), line));
|
Identifier::bare(None, VarName::from_str_and_line(Str::ever("__new__"), line));
|
||||||
new_ident.vi.py_name = Some(Str::ever("__call__"));
|
new_ident.vi.py_name = Some(Str::ever("__call__"));
|
||||||
let class_new = class.attr_expr(new_ident);
|
let class_new = class.attr_expr(new_ident);
|
||||||
|
ident.vi.t = __new__;
|
||||||
|
if let Some(new_first_param) = ident.vi.t.non_default_params().unwrap().first() {
|
||||||
|
let param_name = new_first_param
|
||||||
|
.name()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.unwrap_or_else(fresh_varname);
|
||||||
|
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
|
||||||
|
let param = NonDefaultParamSignature::new(ParamPattern::VarName(param), None);
|
||||||
|
let params = Params::new(vec![param], None, vec![], None);
|
||||||
|
let sig = SubrSignature::new(ident, params);
|
||||||
|
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
|
||||||
|
Str::from(param_name),
|
||||||
|
line,
|
||||||
|
)));
|
||||||
let call = class_new.call_expr(Args::new(vec![arg], None, vec![], None));
|
let call = class_new.call_expr(Args::new(vec![arg], None, vec![], None));
|
||||||
let block = Block::new(vec![call]);
|
let block = Block::new(vec![call]);
|
||||||
let body = DefBody::new(EQUAL, block, DefId(0));
|
let body = DefBody::new(EQUAL, block, DefId(0));
|
||||||
self.emit_subr_def(Some(class_ident.inspect()), sig, body);
|
self.emit_subr_def(Some(class_ident.inspect()), sig, body);
|
||||||
|
} else {
|
||||||
|
let params = Params::new(vec![], None, vec![], None);
|
||||||
|
let sig = SubrSignature::new(ident, params);
|
||||||
|
let call = class_new.call_expr(Args::new(vec![], None, vec![], None));
|
||||||
|
let block = Block::new(vec![call]);
|
||||||
|
let body = DefBody::new(EQUAL, block, DefId(0));
|
||||||
|
self.emit_subr_def(Some(class_ident.inspect()), sig, body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj {
|
fn emit_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj {
|
||||||
|
|
|
@ -19,33 +19,30 @@ const CLASS_ERR: StyledStr = StyledStr::new("Class", Some(ERR), None);
|
||||||
const REQ_ERR: StyledStr = StyledStr::new("Requirement", Some(ERR), None);
|
const REQ_ERR: StyledStr = StyledStr::new("Requirement", Some(ERR), None);
|
||||||
const REQ_WARN: StyledStr = StyledStr::new("Requirement", Some(WARN), None);
|
const REQ_WARN: StyledStr = StyledStr::new("Requirement", Some(WARN), None);
|
||||||
|
|
||||||
/// Requirement: Type, Impl := Type -> ClassType
|
/// Requirement := Type or NoneType, Impl := Type -> ClassType
|
||||||
pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<ValueObj> {
|
||||||
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
|
let require = args.remove_left_or_key("Requirement");
|
||||||
ErrorCore::new(
|
let impls = args.remove_left_or_key("Impl");
|
||||||
|
let impls = impls.map(|v| v.as_type().unwrap());
|
||||||
|
let t = mono(ctx.name.clone());
|
||||||
|
match require {
|
||||||
|
Some(value) => {
|
||||||
|
if let Some(require) = value.as_type() {
|
||||||
|
Ok(ValueObj::gen_t(GenTypeObj::class(t, Some(require), impls)))
|
||||||
|
} else {
|
||||||
|
let require = StyledString::new(format!("{value}"), Some(ERR), None);
|
||||||
|
Err(ErrorCore::new(
|
||||||
vec![SubMessage::only_loc(Location::Unknown)],
|
vec![SubMessage::only_loc(Location::Unknown)],
|
||||||
format!("{REQ_ERR} is not passed"),
|
format!("non-type object {require} is passed to {REQ_WARN}",),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
ErrorKind::TypeError,
|
ErrorKind::TypeError,
|
||||||
Location::Unknown,
|
Location::Unknown,
|
||||||
)
|
)
|
||||||
})?;
|
.into())
|
||||||
let Some(require) = require.as_type() else {
|
}
|
||||||
let require = StyledString::new(format!("{}", require), Some(ERR), None);
|
}
|
||||||
return Err(ErrorCore::new(
|
None => Ok(ValueObj::gen_t(GenTypeObj::class(t, None, impls))),
|
||||||
vec![SubMessage::only_loc(Location::Unknown)],
|
}
|
||||||
format!(
|
|
||||||
"non-type object {require} is passed to {REQ_WARN}",
|
|
||||||
),
|
|
||||||
line!() as usize,
|
|
||||||
ErrorKind::TypeError,
|
|
||||||
Location::Unknown,
|
|
||||||
).into());
|
|
||||||
};
|
|
||||||
let impls = args.remove_left_or_key("Impl");
|
|
||||||
let impls = impls.map(|v| v.as_type().unwrap());
|
|
||||||
let t = mono(ctx.name.clone());
|
|
||||||
Ok(ValueObj::gen_t(GenTypeObj::class(t, require, impls)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Super: ClassType, Impl := Type, Additional := Type -> ClassType
|
/// Super: ClassType, Impl := Type, Additional := Type -> ClassType
|
||||||
|
|
|
@ -2062,9 +2062,9 @@ impl Context {
|
||||||
Private
|
Private
|
||||||
};
|
};
|
||||||
let class_t = func(
|
let class_t = func(
|
||||||
vec![kw("Requirement", Type)],
|
vec![],
|
||||||
None,
|
None,
|
||||||
vec![kw("Impl", Type)],
|
vec![kw("Requirement", or(Type, Ellipsis)), kw("Impl", Type)],
|
||||||
ClassType,
|
ClassType,
|
||||||
);
|
);
|
||||||
let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t, None));
|
let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t, None));
|
||||||
|
|
|
@ -14,7 +14,7 @@ use erg_common::{fn_name, Str};
|
||||||
use ast::{Decorator, DefId, Identifier, OperationKind, VarName};
|
use ast::{Decorator, DefId, Identifier, OperationKind, VarName};
|
||||||
use erg_parser::ast;
|
use erg_parser::ast;
|
||||||
|
|
||||||
use crate::ty::constructors::{free_var, func, func1, proc, ref_, ref_mut, v_enum};
|
use crate::ty::constructors::{free_var, func, func0, func1, proc, ref_, ref_mut, v_enum};
|
||||||
use crate::ty::free::{Constraint, FreeKind, HasLevel};
|
use crate::ty::free::{Constraint, FreeKind, HasLevel};
|
||||||
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
||||||
use crate::ty::{HasType, ParamTy, SubrType, Type};
|
use crate::ty::{HasType, ParamTy, SubrType, Type};
|
||||||
|
@ -882,8 +882,11 @@ impl Context {
|
||||||
2,
|
2,
|
||||||
self.level,
|
self.level,
|
||||||
);
|
);
|
||||||
let require = gen.require_or_sup().unwrap().typ().clone();
|
let new_t = if let Some(require) = gen.require_or_sup() {
|
||||||
let new_t = func1(require, gen.typ().clone());
|
func1(require.typ().clone(), gen.typ().clone())
|
||||||
|
} else {
|
||||||
|
func0(gen.typ().clone())
|
||||||
|
};
|
||||||
methods.register_fixed_auto_impl(
|
methods.register_fixed_auto_impl(
|
||||||
"__new__",
|
"__new__",
|
||||||
new_t.clone(),
|
new_t.clone(),
|
||||||
|
|
|
@ -222,7 +222,7 @@ impl ASTLowerer {
|
||||||
Type::ClassType => {
|
Type::ClassType => {
|
||||||
let ty_obj = GenTypeObj::class(
|
let ty_obj = GenTypeObj::class(
|
||||||
mono(format!("{}{ident}", self.ctx.path())),
|
mono(format!("{}{ident}", self.ctx.path())),
|
||||||
TypeObj::Builtin(Type::Uninited),
|
Some(TypeObj::Builtin(Type::Uninited)),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
self.ctx.register_gen_type(ident, ty_obj);
|
self.ctx.register_gen_type(ident, ty_obj);
|
||||||
|
|
|
@ -95,7 +95,9 @@ impl SideEffectChecker {
|
||||||
self.check_def(def);
|
self.check_def(def);
|
||||||
}
|
}
|
||||||
Expr::ClassDef(class_def) => {
|
Expr::ClassDef(class_def) => {
|
||||||
self.check_expr(class_def.require_or_sup.as_ref());
|
if let Some(req_sup) = &class_def.require_or_sup {
|
||||||
|
self.check_expr(req_sup);
|
||||||
|
}
|
||||||
// TODO: grow
|
// TODO: grow
|
||||||
for def in class_def.methods.iter() {
|
for def in class_def.methods.iter() {
|
||||||
self.check_expr(def);
|
self.check_expr(def);
|
||||||
|
@ -322,7 +324,9 @@ impl SideEffectChecker {
|
||||||
self.check_def(def);
|
self.check_def(def);
|
||||||
}
|
}
|
||||||
Expr::ClassDef(class_def) => {
|
Expr::ClassDef(class_def) => {
|
||||||
self.check_expr(class_def.require_or_sup.as_ref());
|
if let Some(req_sup) = &class_def.require_or_sup {
|
||||||
|
self.check_expr(req_sup);
|
||||||
|
}
|
||||||
for def in class_def.methods.iter() {
|
for def in class_def.methods.iter() {
|
||||||
self.check_expr(def);
|
self.check_expr(def);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2055,7 +2055,7 @@ impl Methods {
|
||||||
pub struct ClassDef {
|
pub struct ClassDef {
|
||||||
pub obj: GenTypeObj,
|
pub obj: GenTypeObj,
|
||||||
pub sig: Signature,
|
pub sig: Signature,
|
||||||
pub require_or_sup: Box<Expr>,
|
pub require_or_sup: Option<Box<Expr>>,
|
||||||
/// The type of `new` that is automatically defined if not defined
|
/// The type of `new` that is automatically defined if not defined
|
||||||
pub need_to_gen_new: bool,
|
pub need_to_gen_new: bool,
|
||||||
pub __new__: Type,
|
pub __new__: Type,
|
||||||
|
@ -2103,7 +2103,7 @@ impl ClassDef {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
obj: GenTypeObj,
|
obj: GenTypeObj,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
require_or_sup: Expr,
|
require_or_sup: Option<Expr>,
|
||||||
need_to_gen_new: bool,
|
need_to_gen_new: bool,
|
||||||
__new__: Type,
|
__new__: Type,
|
||||||
methods: Block,
|
methods: Block,
|
||||||
|
@ -2111,7 +2111,7 @@ impl ClassDef {
|
||||||
Self {
|
Self {
|
||||||
obj,
|
obj,
|
||||||
sig,
|
sig,
|
||||||
require_or_sup: Box::new(require_or_sup),
|
require_or_sup: require_or_sup.map(Box::new),
|
||||||
need_to_gen_new,
|
need_to_gen_new,
|
||||||
__new__,
|
__new__,
|
||||||
methods,
|
methods,
|
||||||
|
|
|
@ -1360,12 +1360,12 @@ impl ASTLowerer {
|
||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_)));
|
let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_)));
|
||||||
let sup_type = enum_unwrap!(&hir_def.body.block.first().unwrap(), hir::Expr::Call)
|
if let Some(sup_type) = enum_unwrap!(&hir_def.body.block.first().unwrap(), hir::Expr::Call)
|
||||||
.args
|
.args
|
||||||
.get_left_or_key("Super")
|
.get_left_or_key("Super")
|
||||||
.unwrap();
|
{
|
||||||
Self::check_inheritable(&self.cfg, &mut self.errs, type_obj, sup_type, &hir_def.sig);
|
Self::check_inheritable(&self.cfg, &mut self.errs, type_obj, sup_type, &hir_def.sig);
|
||||||
// vi.t.non_default_params().unwrap()[0].typ().clone()
|
}
|
||||||
let (__new__, need_to_gen_new) = if let (Some(dunder_new_vi), Some(new_vi)) = (
|
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__")),
|
||||||
class_ctx.get_current_scope_var(&VarName::from_static("new")),
|
class_ctx.get_current_scope_var(&VarName::from_static("new")),
|
||||||
|
@ -1404,7 +1404,7 @@ impl ASTLowerer {
|
||||||
)?
|
)?
|
||||||
};
|
};
|
||||||
let mut hir_def = self.lower_def(class_def.def)?;
|
let mut hir_def = self.lower_def(class_def.def)?;
|
||||||
let base = Self::get_require_or_sup_or_base(hir_def.body.block.remove(0));
|
let base = Self::get_require_or_sup_or_base(hir_def.body.block.remove(0)).unwrap();
|
||||||
let mut hir_methods = hir::Block::empty();
|
let mut hir_methods = hir::Block::empty();
|
||||||
for mut methods in class_def.methods_list.into_iter() {
|
for mut methods in class_def.methods_list.into_iter() {
|
||||||
let kind = ContextKind::PatchMethodDefs(base_t.clone());
|
let kind = ContextKind::PatchMethodDefs(base_t.clone());
|
||||||
|
@ -1786,16 +1786,16 @@ impl ASTLowerer {
|
||||||
.push((ClassDefType::Simple(base.clone()), methods));
|
.push((ClassDefType::Simple(base.clone()), methods));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_require_or_sup_or_base(expr: hir::Expr) -> hir::Expr {
|
fn get_require_or_sup_or_base(expr: hir::Expr) -> Option<hir::Expr> {
|
||||||
match expr {
|
match expr {
|
||||||
acc @ hir::Expr::Accessor(_) => acc,
|
acc @ hir::Expr::Accessor(_) => Some(acc),
|
||||||
hir::Expr::Call(mut call) => match call.obj.show_acc().as_ref().map(|s| &s[..]) {
|
hir::Expr::Call(mut call) => match call.obj.show_acc().as_ref().map(|s| &s[..]) {
|
||||||
Some("Class") => call.args.remove_left_or_key("Requirement").unwrap(),
|
Some("Class") => call.args.remove_left_or_key("Requirement"),
|
||||||
Some("Inherit") => call.args.remove_left_or_key("Super").unwrap(),
|
Some("Inherit") => call.args.remove_left_or_key("Super"),
|
||||||
Some("Inheritable") => {
|
Some("Inheritable") => {
|
||||||
Self::get_require_or_sup_or_base(call.args.remove_left_or_key("Class").unwrap())
|
Self::get_require_or_sup_or_base(call.args.remove_left_or_key("Class").unwrap())
|
||||||
}
|
}
|
||||||
Some("Patch") => call.args.remove_left_or_key("Base").unwrap(),
|
Some("Patch") => call.args.remove_left_or_key("Base"),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
|
|
|
@ -127,7 +127,9 @@ impl OwnershipChecker {
|
||||||
self.path_stack.pop();
|
self.path_stack.pop();
|
||||||
}
|
}
|
||||||
Expr::ClassDef(class_def) => {
|
Expr::ClassDef(class_def) => {
|
||||||
self.check_expr(&class_def.require_or_sup, Ownership::Owned, false);
|
if let Some(req_sup) = &class_def.require_or_sup {
|
||||||
|
self.check_expr(req_sup, Ownership::Owned, false);
|
||||||
|
}
|
||||||
for def in class_def.methods.iter() {
|
for def in class_def.methods.iter() {
|
||||||
self.check_expr(def, Ownership::Owned, true);
|
self.check_expr(def, Ownership::Owned, true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,15 +62,15 @@ pub type EvalValueResult<T> = Result<T, EvalValueError>;
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct ClassTypeObj {
|
pub struct ClassTypeObj {
|
||||||
pub t: Type,
|
pub t: Type,
|
||||||
pub require: Box<TypeObj>,
|
pub require: Option<Box<TypeObj>>,
|
||||||
pub impls: Option<Box<TypeObj>>,
|
pub impls: Option<Box<TypeObj>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClassTypeObj {
|
impl ClassTypeObj {
|
||||||
pub fn new(t: Type, require: TypeObj, impls: Option<TypeObj>) -> Self {
|
pub fn new(t: Type, require: Option<TypeObj>, impls: Option<TypeObj>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
t,
|
t,
|
||||||
require: Box::new(require),
|
require: require.map(Box::new),
|
||||||
impls: impls.map(Box::new),
|
impls: impls.map(Box::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ impl fmt::Display for GenTypeObj {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenTypeObj {
|
impl GenTypeObj {
|
||||||
pub fn class(t: Type, require: TypeObj, impls: Option<TypeObj>) -> Self {
|
pub fn class(t: Type, require: Option<TypeObj>, impls: Option<TypeObj>) -> Self {
|
||||||
GenTypeObj::Class(ClassTypeObj::new(t, require, impls))
|
GenTypeObj::Class(ClassTypeObj::new(t, require, impls))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ impl GenTypeObj {
|
||||||
|
|
||||||
pub fn require_or_sup(&self) -> Option<&TypeObj> {
|
pub fn require_or_sup(&self) -> Option<&TypeObj> {
|
||||||
match self {
|
match self {
|
||||||
Self::Class(class) => Some(class.require.as_ref()),
|
Self::Class(class) => class.require.as_ref().map(AsRef::as_ref),
|
||||||
Self::Subclass(subclass) => Some(subclass.sup.as_ref()),
|
Self::Subclass(subclass) => Some(subclass.sup.as_ref()),
|
||||||
Self::Trait(trait_) => Some(trait_.require.as_ref()),
|
Self::Trait(trait_) => Some(trait_.require.as_ref()),
|
||||||
Self::Subtrait(subtrait) => Some(subtrait.sup.as_ref()),
|
Self::Subtrait(subtrait) => Some(subtrait.sup.as_ref()),
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
Empty = Class()
|
||||||
|
empty = Empty.new()
|
||||||
|
print! empty
|
||||||
|
|
||||||
# Inheritance is prohibited by default. Remove this decorator and check for errors.
|
# Inheritance is prohibited by default. Remove this decorator and check for errors.
|
||||||
@Inheritable
|
@Inheritable
|
||||||
Point2D = Class {x = Int; y = Int}
|
Point2D = Class {x = Int; y = Int}
|
||||||
|
|
8
tests/bug/bug.er
Normal file
8
tests/bug/bug.er
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# z: Zip(Nat, Str)
|
||||||
|
z = zip [1+1], ["a"+"b"]
|
||||||
|
|
||||||
|
for! z, ((i, s),) =>
|
||||||
|
print! i + 1
|
||||||
|
print! s + "b"
|
||||||
|
print! s + 1
|
||||||
|
print! i + "a"
|
Loading…
Add table
Add a link
Reference in a new issue