mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-03 14:04:33 +00:00
feat: support recursive class definition
This commit is contained in:
parent
418f31e6ed
commit
f3b188e095
13 changed files with 285 additions and 93 deletions
|
@ -641,7 +641,11 @@ impl Context {
|
|||
// ({I: Int | True} :> Int) == true
|
||||
// {N: Nat | ...} :> Int) == false
|
||||
// ({I: Int | I >= 0} :> Int) == false
|
||||
// {U(: Type)} :> { .x = {Int} }(== {{ .x = Int }}) == true
|
||||
(Refinement(l), r) => {
|
||||
if let Some(r) = r.to_singleton() {
|
||||
return self.structural_supertype_of(lhs, &Type::Refinement(r));
|
||||
}
|
||||
if l.pred.mentions(&l.var) {
|
||||
match l.pred.can_be_false() {
|
||||
Some(true) => {
|
||||
|
|
|
@ -595,7 +595,13 @@ impl Context {
|
|||
call.loc(),
|
||||
self.caused_by(),
|
||||
))),
|
||||
_ => unreachable!(),
|
||||
other => Err(EvalErrors::from(EvalError::feature_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
other.loc(),
|
||||
&format!("const call: {other}"),
|
||||
self.caused_by(),
|
||||
))),
|
||||
}
|
||||
} else {
|
||||
Err(EvalErrors::from(EvalError::not_const_expr(
|
||||
|
@ -1031,26 +1037,8 @@ impl Context {
|
|||
line!(),
|
||||
))
|
||||
}),
|
||||
Or | BitOr => match (lhs, rhs) {
|
||||
(ValueObj::Bool(l), ValueObj::Bool(r)) => Ok(ValueObj::Bool(l || r)),
|
||||
(ValueObj::Int(l), ValueObj::Int(r)) => Ok(ValueObj::Int(l | r)),
|
||||
(ValueObj::Type(lhs), ValueObj::Type(rhs)) => Ok(self.eval_or_type(lhs, rhs)),
|
||||
_ => Err(EvalErrors::from(EvalError::unreachable(
|
||||
self.cfg.input.clone(),
|
||||
fn_name!(),
|
||||
line!(),
|
||||
))),
|
||||
},
|
||||
And | BitAnd => match (lhs, rhs) {
|
||||
(ValueObj::Bool(l), ValueObj::Bool(r)) => Ok(ValueObj::Bool(l && r)),
|
||||
(ValueObj::Int(l), ValueObj::Int(r)) => Ok(ValueObj::Int(l & r)),
|
||||
(ValueObj::Type(lhs), ValueObj::Type(rhs)) => Ok(self.eval_and_type(lhs, rhs)),
|
||||
_ => Err(EvalErrors::from(EvalError::unreachable(
|
||||
self.cfg.input.clone(),
|
||||
fn_name!(),
|
||||
line!(),
|
||||
))),
|
||||
},
|
||||
Or | BitOr => self.eval_or(lhs, rhs),
|
||||
And | BitAnd => self.eval_and(lhs, rhs),
|
||||
BitXor => match (lhs, rhs) {
|
||||
(ValueObj::Bool(l), ValueObj::Bool(r)) => Ok(ValueObj::Bool(l ^ r)),
|
||||
(ValueObj::Int(l), ValueObj::Int(r)) => Ok(ValueObj::Int(l ^ r)),
|
||||
|
@ -1068,6 +1056,27 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_or(&self, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> {
|
||||
match (lhs, rhs) {
|
||||
(ValueObj::Bool(l), ValueObj::Bool(r)) => Ok(ValueObj::Bool(l || r)),
|
||||
(ValueObj::Int(l), ValueObj::Int(r)) => Ok(ValueObj::Int(l | r)),
|
||||
(ValueObj::Type(lhs), ValueObj::Type(rhs)) => Ok(self.eval_or_type(lhs, rhs)),
|
||||
(lhs, rhs) => {
|
||||
let lhs = self.convert_value_into_type(lhs).ok();
|
||||
let rhs = self.convert_value_into_type(rhs).ok();
|
||||
if let Some((l, r)) = lhs.zip(rhs) {
|
||||
self.eval_or(ValueObj::builtin_type(l), ValueObj::builtin_type(r))
|
||||
} else {
|
||||
Err(EvalErrors::from(EvalError::unreachable(
|
||||
self.cfg.input.clone(),
|
||||
fn_name!(),
|
||||
line!(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_or_type(&self, lhs: TypeObj, rhs: TypeObj) -> ValueObj {
|
||||
match (lhs, rhs) {
|
||||
(
|
||||
|
@ -1101,6 +1110,27 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
fn eval_and(&self, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> {
|
||||
match (lhs, rhs) {
|
||||
(ValueObj::Bool(l), ValueObj::Bool(r)) => Ok(ValueObj::Bool(l && r)),
|
||||
(ValueObj::Int(l), ValueObj::Int(r)) => Ok(ValueObj::Int(l & r)),
|
||||
(ValueObj::Type(lhs), ValueObj::Type(rhs)) => Ok(self.eval_and_type(lhs, rhs)),
|
||||
(lhs, rhs) => {
|
||||
let lhs = self.convert_value_into_type(lhs).ok();
|
||||
let rhs = self.convert_value_into_type(rhs).ok();
|
||||
if let Some((l, r)) = lhs.zip(rhs) {
|
||||
self.eval_and(ValueObj::builtin_type(l), ValueObj::builtin_type(r))
|
||||
} else {
|
||||
Err(EvalErrors::from(EvalError::unreachable(
|
||||
self.cfg.input.clone(),
|
||||
fn_name!(),
|
||||
line!(),
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_and_type(&self, lhs: TypeObj, rhs: TypeObj) -> ValueObj {
|
||||
match (lhs, rhs) {
|
||||
(
|
||||
|
|
|
@ -65,12 +65,12 @@ pub(crate) fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
|
|||
match base {
|
||||
Some(value) => {
|
||||
if let Some(base) = value.as_type(ctx) {
|
||||
Ok(ValueObj::gen_t(GenTypeObj::class(t, Some(base), impls)).into())
|
||||
Ok(ValueObj::gen_t(GenTypeObj::class(t, Some(base), impls, true)).into())
|
||||
} else {
|
||||
Err(type_mismatch("type", value, "Base"))
|
||||
}
|
||||
}
|
||||
None => Ok(ValueObj::gen_t(GenTypeObj::class(t, None, impls)).into()),
|
||||
None => Ok(ValueObj::gen_t(GenTypeObj::class(t, None, impls, true)).into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ pub(crate) fn trait_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<
|
|||
let impls = args.remove_left_or_key("Impl");
|
||||
let impls = impls.map(|v| v.as_type(ctx).unwrap());
|
||||
let t = mono(ctx.name.clone());
|
||||
Ok(ValueObj::gen_t(GenTypeObj::trait_(t, req, impls)).into())
|
||||
Ok(ValueObj::gen_t(GenTypeObj::trait_(t, req, impls, true)).into())
|
||||
}
|
||||
|
||||
/// Base: Type, Impl := Type -> Patch
|
||||
|
|
|
@ -907,13 +907,46 @@ impl Context {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// To allow forward references and recursive definitions
|
||||
pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> {
|
||||
pub(crate) fn preregister_const(&mut self, block: &ast::Block) -> TyCheckResult<()> {
|
||||
let mut total_errs = TyCheckErrors::empty();
|
||||
for expr in block.iter() {
|
||||
match expr {
|
||||
ast::Expr::Def(def) => {
|
||||
if let Err(errs) = self.preregister_def(def) {
|
||||
if let Err(errs) = self.preregister_const_def(def) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
ast::Expr::ClassDef(class_def) => {
|
||||
if let Err(errs) = self.preregister_const_def(&class_def.def) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
ast::Expr::PatchDef(patch_def) => {
|
||||
if let Err(errs) = self.preregister_const_def(&patch_def.def) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
ast::Expr::Dummy(dummy) => {
|
||||
if let Err(errs) = self.preregister_const(&dummy.exprs) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
if total_errs.is_empty() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(total_errs)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn register_const(&mut self, block: &ast::Block) -> TyCheckResult<()> {
|
||||
let mut total_errs = TyCheckErrors::empty();
|
||||
for expr in block.iter() {
|
||||
match expr {
|
||||
ast::Expr::Def(def) => {
|
||||
if let Err(errs) = self.register_const_def(def) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
if def.def_kind().is_import() {
|
||||
|
@ -923,17 +956,17 @@ impl Context {
|
|||
}
|
||||
}
|
||||
ast::Expr::ClassDef(class_def) => {
|
||||
if let Err(errs) = self.preregister_def(&class_def.def) {
|
||||
if let Err(errs) = self.register_const_def(&class_def.def) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
ast::Expr::PatchDef(patch_def) => {
|
||||
if let Err(errs) = self.preregister_def(&patch_def.def) {
|
||||
if let Err(errs) = self.register_const_def(&patch_def.def) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
ast::Expr::Dummy(dummy) => {
|
||||
if let Err(errs) = self.preregister(&dummy.exprs) {
|
||||
if let Err(errs) = self.register_const(&dummy.exprs) {
|
||||
total_errs.extend(errs);
|
||||
}
|
||||
}
|
||||
|
@ -988,7 +1021,43 @@ impl Context {
|
|||
res
|
||||
}
|
||||
|
||||
pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
|
||||
fn preregister_const_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
|
||||
match &def.sig {
|
||||
ast::Signature::Var(var) if var.is_const() => {
|
||||
let Some(ast::Expr::Call(call)) = def.body.block.first() else {
|
||||
return Ok(());
|
||||
};
|
||||
self.preregister_type(var, call)
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn preregister_type(&mut self, var: &ast::VarSignature, call: &ast::Call) -> TyCheckResult<()> {
|
||||
match call.obj.as_ref() {
|
||||
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => match &ident.inspect()[..] {
|
||||
"Class" => {
|
||||
let ident = var.ident().unwrap();
|
||||
let t = Type::Mono(format!("{}{ident}", self.name).into());
|
||||
let class = GenTypeObj::class(t, None, None, false);
|
||||
let class = ValueObj::Type(TypeObj::Generated(class));
|
||||
self.register_gen_const(ident, class, false)
|
||||
}
|
||||
"Trait" => {
|
||||
let ident = var.ident().unwrap();
|
||||
let t = Type::Mono(format!("{}{ident}", self.name).into());
|
||||
let trait_ =
|
||||
GenTypeObj::trait_(t, TypeObj::builtin_type(Type::Failure), None, false);
|
||||
let trait_ = ValueObj::Type(TypeObj::Generated(trait_));
|
||||
self.register_gen_const(ident, trait_, false)
|
||||
}
|
||||
_ => Ok(()),
|
||||
},
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn register_const_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
|
||||
let id = Some(def.body.id);
|
||||
let __name__ = def.sig.ident().map(|i| i.inspect()).unwrap_or(UBAR);
|
||||
match &def.sig {
|
||||
|
@ -1278,7 +1347,10 @@ impl Context {
|
|||
alias: bool,
|
||||
) -> CompileResult<()> {
|
||||
let vis = self.instantiate_vis_modifier(&ident.vis)?;
|
||||
if self.rec_get_const_obj(ident.inspect()).is_some() && vis.is_private() {
|
||||
let inited = self
|
||||
.rec_get_const_obj(ident.inspect())
|
||||
.is_some_and(|v| v.is_inited());
|
||||
if inited && vis.is_private() {
|
||||
Err(CompileErrors::from(CompileError::reassign_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
@ -1457,14 +1529,13 @@ impl Context {
|
|||
2,
|
||||
self.level,
|
||||
);
|
||||
let Some(TypeObj::Builtin {
|
||||
if let Some(TypeObj::Builtin {
|
||||
t: Type::Record(req),
|
||||
..
|
||||
}) = gen.base_or_sup()
|
||||
else {
|
||||
todo!("{gen}")
|
||||
};
|
||||
self.register_instance_attrs(&mut ctx, req)?;
|
||||
{
|
||||
self.register_instance_attrs(&mut ctx, req)?;
|
||||
}
|
||||
self.register_gen_mono_type(ident, gen, ctx, Const)
|
||||
} else {
|
||||
feature_error!(
|
||||
|
@ -1635,15 +1706,10 @@ impl Context {
|
|||
meta_t: Type,
|
||||
) -> CompileResult<()> {
|
||||
let vis = self.instantiate_vis_modifier(&ident.vis)?;
|
||||
if self.mono_types.contains_key(ident.inspect()) {
|
||||
Err(CompileErrors::from(CompileError::reassign_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
ident.loc(),
|
||||
self.caused_by(),
|
||||
ident.inspect(),
|
||||
)))
|
||||
} else if self.rec_get_const_obj(ident.inspect()).is_some() && vis.is_private() {
|
||||
let inited = self
|
||||
.rec_get_const_obj(ident.inspect())
|
||||
.is_some_and(|v| v.is_inited());
|
||||
if inited && vis.is_private() {
|
||||
// TODO: display where defined
|
||||
Err(CompileErrors::from(CompileError::reassign_error(
|
||||
self.cfg.input.clone(),
|
||||
|
@ -1682,16 +1748,10 @@ impl Context {
|
|||
muty: Mutability,
|
||||
) -> CompileResult<()> {
|
||||
let vis = self.instantiate_vis_modifier(&ident.vis)?;
|
||||
// FIXME: recursive search
|
||||
if self.mono_types.contains_key(ident.inspect()) {
|
||||
Err(CompileErrors::from(CompileError::reassign_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
ident.loc(),
|
||||
self.caused_by(),
|
||||
ident.inspect(),
|
||||
)))
|
||||
} else if self.rec_get_const_obj(ident.inspect()).is_some() && vis.is_private() {
|
||||
let inited = self
|
||||
.rec_get_const_obj(ident.inspect())
|
||||
.is_some_and(|v| v.is_inited());
|
||||
if inited && vis.is_private() {
|
||||
Err(CompileErrors::from(CompileError::reassign_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
@ -1732,16 +1792,10 @@ impl Context {
|
|||
muty: Mutability,
|
||||
) -> CompileResult<()> {
|
||||
let vis = self.instantiate_vis_modifier(&ident.vis)?;
|
||||
// FIXME: recursive search
|
||||
if self.poly_types.contains_key(ident.inspect()) {
|
||||
Err(CompileErrors::from(CompileError::reassign_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
ident.loc(),
|
||||
self.caused_by(),
|
||||
ident.inspect(),
|
||||
)))
|
||||
} else if self.rec_get_const_obj(ident.inspect()).is_some() && vis.is_private() {
|
||||
let inited = self
|
||||
.rec_get_const_obj(ident.inspect())
|
||||
.is_some_and(|v| v.is_inited());
|
||||
if inited && vis.is_private() {
|
||||
Err(CompileErrors::from(CompileError::reassign_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
|
|
@ -1323,8 +1323,12 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
|||
self.sub_unify(maybe_sub, &Type::Refinement(sup))?;
|
||||
}
|
||||
(sub, Refinement(_)) => {
|
||||
let sub = sub.clone().into_refinement();
|
||||
self.sub_unify(&Type::Refinement(sub), maybe_sup)?;
|
||||
if let Some(sub) = sub.to_singleton() {
|
||||
self.sub_unify(&Type::Refinement(sub), maybe_sup)?;
|
||||
} else {
|
||||
let sub = sub.clone().into_refinement();
|
||||
self.sub_unify(&Type::Refinement(sub), maybe_sup)?;
|
||||
}
|
||||
}
|
||||
(Subr(_) | Record(_), Type) => {}
|
||||
// REVIEW: correct?
|
||||
|
|
|
@ -772,14 +772,18 @@ impl ASTLowerer {
|
|||
let (t, ty_obj) = match t {
|
||||
Type::ClassType => {
|
||||
let t = mono(format!("{}{ident}", self.module.context.path()));
|
||||
let ty_obj = GenTypeObj::class(t.clone(), None, None);
|
||||
let ty_obj = GenTypeObj::class(t.clone(), None, None, true);
|
||||
let t = v_enum(set! { ValueObj::builtin_class(t) });
|
||||
(t, Some(ty_obj))
|
||||
}
|
||||
Type::TraitType => {
|
||||
let t = mono(format!("{}{ident}", self.module.context.path()));
|
||||
let ty_obj =
|
||||
GenTypeObj::trait_(t.clone(), TypeObj::builtin_type(Type::Uninited), None);
|
||||
let ty_obj = GenTypeObj::trait_(
|
||||
t.clone(),
|
||||
TypeObj::builtin_type(Type::Uninited),
|
||||
None,
|
||||
true,
|
||||
);
|
||||
let t = v_enum(set! { ValueObj::builtin_trait(t) });
|
||||
(t, Some(ty_obj))
|
||||
}
|
||||
|
@ -793,7 +797,7 @@ impl ASTLowerer {
|
|||
})
|
||||
.collect();
|
||||
let t = poly(format!("{}{ident}", self.module.context.path()), params);
|
||||
let ty_obj = GenTypeObj::class(t.clone(), None, None);
|
||||
let ty_obj = GenTypeObj::class(t.clone(), None, None, true);
|
||||
let t = v_enum(set! { ValueObj::builtin_class(t) });
|
||||
(t, Some(ty_obj))
|
||||
}
|
||||
|
@ -875,7 +879,7 @@ impl ASTLowerer {
|
|||
|
||||
pub(crate) fn declare_module(&mut self, ast: AST) -> HIR {
|
||||
let mut module = hir::Module::with_capacity(ast.module.len());
|
||||
let _ = self.module.context.preregister(ast.module.block());
|
||||
let _ = self.module.context.register_const(ast.module.block());
|
||||
for chunk in ast.module.into_iter() {
|
||||
match self.declare_chunk(chunk, false) {
|
||||
Ok(chunk) => {
|
||||
|
|
|
@ -256,7 +256,7 @@ impl ASTLowerer {
|
|||
None,
|
||||
);
|
||||
let mut module = hir::Module::with_capacity(ast.module.len());
|
||||
if let Err(errs) = self.module.context.preregister(ast.module.block()) {
|
||||
if let Err(errs) = self.module.context.register_const(ast.module.block()) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
for chunk in ast.module.into_iter() {
|
||||
|
|
|
@ -1230,7 +1230,7 @@ impl ASTLowerer {
|
|||
}
|
||||
overwritten
|
||||
};
|
||||
if let Err(errs) = self.module.context.preregister(&lambda.body) {
|
||||
if let Err(errs) = self.module.context.register_const(&lambda.body) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
let body = self.lower_block(lambda.body).map_err(|errs| {
|
||||
|
@ -1453,7 +1453,7 @@ impl ASTLowerer {
|
|||
body: ast::DefBody,
|
||||
) -> LowerResult<hir::Def> {
|
||||
log!(info "entered {}({sig})", fn_name!());
|
||||
if let Err(errs) = self.module.context.preregister(&body.block) {
|
||||
if let Err(errs) = self.module.context.register_const(&body.block) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
match self.lower_block(body.block) {
|
||||
|
@ -1549,7 +1549,7 @@ impl ASTLowerer {
|
|||
if let Err(errs) = self.module.context.assign_params(&mut params, Some(subr_t)) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
if let Err(errs) = self.module.context.preregister(&body.block) {
|
||||
if let Err(errs) = self.module.context.register_const(&body.block) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
match self.lower_block(body.block) {
|
||||
|
@ -1614,7 +1614,7 @@ impl ASTLowerer {
|
|||
if let Err(errs) = self.module.context.assign_params(&mut params, None) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
if let Err(errs) = self.module.context.preregister(&body.block) {
|
||||
if let Err(errs) = self.module.context.register_const(&body.block) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
self.module
|
||||
|
@ -1678,10 +1678,13 @@ impl ASTLowerer {
|
|||
for attr in methods.attrs.iter_mut() {
|
||||
match attr {
|
||||
ast::ClassAttr::Def(def) => {
|
||||
self.module.context.preregister_def(def).map_err(|errs| {
|
||||
self.pop_append_errs();
|
||||
errs
|
||||
})?;
|
||||
self.module
|
||||
.context
|
||||
.register_const_def(def)
|
||||
.map_err(|errs| {
|
||||
self.pop_append_errs();
|
||||
errs
|
||||
})?;
|
||||
if let Some(ident) = def.sig.ident() {
|
||||
if self
|
||||
.module
|
||||
|
@ -1899,10 +1902,13 @@ impl ASTLowerer {
|
|||
def.sig.col_begin().unwrap(),
|
||||
));
|
||||
}
|
||||
self.module.context.preregister_def(def).map_err(|errs| {
|
||||
self.pop_append_errs();
|
||||
errs
|
||||
})?;
|
||||
self.module
|
||||
.context
|
||||
.register_const_def(def)
|
||||
.map_err(|errs| {
|
||||
self.pop_append_errs();
|
||||
errs
|
||||
})?;
|
||||
}
|
||||
ast::ClassAttr::Decl(_) | ast::ClassAttr::Doc(_) => {}
|
||||
}
|
||||
|
@ -2536,7 +2542,10 @@ impl ASTLowerer {
|
|||
}
|
||||
}
|
||||
let mut module = hir::Module::with_capacity(ast.module.len());
|
||||
if let Err(errs) = self.module.context.preregister(ast.module.block()) {
|
||||
if let Err(errs) = self.module.context.preregister_const(ast.module.block()) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
if let Err(errs) = self.module.context.register_const(ast.module.block()) {
|
||||
self.errs.extend(errs);
|
||||
}
|
||||
for chunk in ast.module.into_iter() {
|
||||
|
|
|
@ -22,6 +22,7 @@ use std::fmt;
|
|||
use std::ops::{BitAnd, BitOr, Deref, Not, Range, RangeInclusive};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use erg_common::consts::DEBUG_MODE;
|
||||
use erg_common::dict::Dict;
|
||||
use erg_common::error::Location;
|
||||
use erg_common::fresh::FRESH_GEN;
|
||||
|
@ -1925,6 +1926,14 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_singleton_refinement(&self) -> bool {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_singleton_refinement(),
|
||||
Self::Refinement(refine) => matches!(refine.pred.as_ref(), Predicate::Equal { .. }),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_record(&self) -> bool {
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_record(),
|
||||
|
@ -2531,6 +2540,35 @@ impl Type {
|
|||
}
|
||||
}
|
||||
|
||||
/// ```erg
|
||||
/// { .x = {Int} } == {{ .x = Int }}
|
||||
/// K({Int}) == {K(Int)} # TODO
|
||||
/// ```
|
||||
pub fn to_singleton(&self) -> Option<RefinementType> {
|
||||
match self {
|
||||
Type::Record(rec) if rec.values().all(|t| t.is_singleton_refinement()) => {
|
||||
let mut new_rec = Dict::new();
|
||||
for (k, t) in rec.iter() {
|
||||
if let Some(t) = t
|
||||
.singleton_value()
|
||||
.and_then(|tp| <&Type>::try_from(tp).ok())
|
||||
{
|
||||
new_rec.insert(k.clone(), t.clone());
|
||||
} else if DEBUG_MODE {
|
||||
todo!("{t}");
|
||||
}
|
||||
}
|
||||
let t = Type::Record(new_rec);
|
||||
Some(RefinementType::new(
|
||||
Str::ever("_"),
|
||||
Type::Type,
|
||||
Predicate::eq(Str::ever("_"), TyParam::t(t)),
|
||||
))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deconstruct_refinement(self) -> Result<(Str, Type, Predicate), Type> {
|
||||
match self {
|
||||
Type::FreeVar(fv) if fv.is_linked() => fv.crack().clone().deconstruct_refinement(),
|
||||
|
|
|
@ -63,14 +63,16 @@ pub struct ClassTypeObj {
|
|||
pub t: Type,
|
||||
pub base: Option<Box<TypeObj>>,
|
||||
pub impls: Option<Box<TypeObj>>,
|
||||
pub inited: bool,
|
||||
}
|
||||
|
||||
impl ClassTypeObj {
|
||||
pub fn new(t: Type, base: Option<TypeObj>, impls: Option<TypeObj>) -> Self {
|
||||
pub fn new(t: Type, base: Option<TypeObj>, impls: Option<TypeObj>, inited: bool) -> Self {
|
||||
Self {
|
||||
t,
|
||||
base: base.map(Box::new),
|
||||
impls: impls.map(Box::new),
|
||||
inited,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,14 +101,16 @@ pub struct TraitTypeObj {
|
|||
pub t: Type,
|
||||
pub requires: Box<TypeObj>,
|
||||
pub impls: Option<Box<TypeObj>>,
|
||||
pub inited: bool,
|
||||
}
|
||||
|
||||
impl TraitTypeObj {
|
||||
pub fn new(t: Type, requires: TypeObj, impls: Option<TypeObj>) -> Self {
|
||||
pub fn new(t: Type, requires: TypeObj, impls: Option<TypeObj>, inited: bool) -> Self {
|
||||
Self {
|
||||
t,
|
||||
requires: Box::new(requires),
|
||||
impls: impls.map(Box::new),
|
||||
inited,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -223,8 +227,8 @@ impl LimitedDisplay for GenTypeObj {
|
|||
}
|
||||
|
||||
impl GenTypeObj {
|
||||
pub fn class(t: Type, require: Option<TypeObj>, impls: Option<TypeObj>) -> Self {
|
||||
GenTypeObj::Class(ClassTypeObj::new(t, require, impls))
|
||||
pub fn class(t: Type, require: Option<TypeObj>, impls: Option<TypeObj>, inited: bool) -> Self {
|
||||
GenTypeObj::Class(ClassTypeObj::new(t, require, impls, inited))
|
||||
}
|
||||
|
||||
pub fn inherited(
|
||||
|
@ -236,8 +240,8 @@ impl GenTypeObj {
|
|||
GenTypeObj::Subclass(InheritedTypeObj::new(t, sup, impls, additional))
|
||||
}
|
||||
|
||||
pub fn trait_(t: Type, require: TypeObj, impls: Option<TypeObj>) -> Self {
|
||||
GenTypeObj::Trait(TraitTypeObj::new(t, require, impls))
|
||||
pub fn trait_(t: Type, require: TypeObj, impls: Option<TypeObj>, inited: bool) -> Self {
|
||||
GenTypeObj::Trait(TraitTypeObj::new(t, require, impls, inited))
|
||||
}
|
||||
|
||||
pub fn patch(t: Type, base: TypeObj, impls: Option<TypeObj>) -> Self {
|
||||
|
@ -265,6 +269,14 @@ impl GenTypeObj {
|
|||
GenTypeObj::Structural(StructuralTypeObj::new(t, type_))
|
||||
}
|
||||
|
||||
pub const fn is_inited(&self) -> bool {
|
||||
match self {
|
||||
Self::Class(class) => class.inited,
|
||||
Self::Trait(trait_) => trait_.inited,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn base_or_sup(&self) -> Option<&TypeObj> {
|
||||
match self {
|
||||
Self::Class(class) => class.base.as_ref().map(AsRef::as_ref),
|
||||
|
@ -428,6 +440,13 @@ impl TypeObj {
|
|||
}
|
||||
}
|
||||
|
||||
pub const fn is_inited(&self) -> bool {
|
||||
match self {
|
||||
Self::Builtin { .. } => true,
|
||||
Self::Generated(gen) => gen.is_inited(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn typ(&self) -> &Type {
|
||||
match self {
|
||||
TypeObj::Builtin { t, .. } => t,
|
||||
|
@ -970,6 +989,13 @@ impl ValueObj {
|
|||
matches!(self, Self::Type(_))
|
||||
}
|
||||
|
||||
pub const fn is_inited(&self) -> bool {
|
||||
match self {
|
||||
Self::Type(t) => t.is_inited(),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(t: Type, mut content: Str) -> Option<Self> {
|
||||
match t {
|
||||
Type::Int => content.replace('_', "").parse::<i32>().ok().map(Self::Int),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue