Merge pull request #138 from erg-lang/class

Implement class syntax
This commit is contained in:
Shunsuke Shibayama 2022-09-10 20:24:43 +09:00 committed by GitHub
commit d56fd68058
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
63 changed files with 5146 additions and 2705 deletions

View file

@ -1,6 +1,6 @@
[package]
name = "erg_compiler"
version = "0.3.2"
version = "0.4.0-beta.1"
description = "Centimetre: the Erg compiler"
authors = ["Shunsuke Shibayama <sbym1346@gmail.com>"]
license = "MIT OR Apache-2.0"
@ -17,9 +17,9 @@ simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_c
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
[dependencies]
erg_common = { version = "0.3.2", path = "../erg_common" }
erg_parser = { version = "0.3.2", path = "../erg_parser" }
erg_type = { version = "0.3.2", path = "../erg_type" }
erg_common = { version = "0.4.0-beta.1", path = "../erg_common" }
erg_parser = { version = "0.4.0-beta.1", path = "../erg_parser" }
erg_type = { version = "0.4.0-beta.1", path = "../erg_type" }
[lib]
path = "lib.rs"

View file

@ -11,26 +11,39 @@ use erg_common::opcode::Opcode;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_common::{
debug_power_assert, enum_unwrap, fn_name_full, impl_stream_for_wrapper, log, switch_unreachable,
debug_power_assert, enum_unwrap, fn_name, fn_name_full, impl_stream_for_wrapper, log,
switch_unreachable,
};
use erg_parser::ast::DefId;
use erg_type::codeobj::{CodeObj, CodeObjFlags};
use Opcode::*;
use erg_parser::ast::{Identifier, ParamPattern, Params, VarName};
use erg_parser::ast::{ParamPattern, ParamSignature, Params, VarName};
use erg_parser::token::{Token, TokenKind};
use erg_type::free::fresh_varname;
use erg_type::value::TypeKind;
use erg_type::value::ValueObj;
use erg_type::{HasType, TypeCode, TypePair};
use erg_type::{HasType, Type, TypeCode, TypePair};
use crate::compile::{AccessKind, Name, StoreLoadKind};
use crate::context::eval::eval_lit;
use crate::error::{CompileError, CompileErrors, CompileResult};
use crate::eval::eval_lit;
use crate::hir::AttrDef;
use crate::hir::Attribute;
use crate::hir::{
Accessor, Args, Array, Block, Call, DefBody, Expr, Local, Signature, SubrSignature, Tuple,
VarSignature, HIR,
Accessor, Args, Array, Block, Call, ClassDef, DefBody, Expr, Identifier, Literal, PosArg,
Signature, SubrSignature, Tuple, VarSignature, HIR,
};
use AccessKind::*;
fn is_python_special(name: &str) -> bool {
match name {
"__call__" | "__init__" => true,
_ => false,
}
}
fn is_python_global(name: &str) -> bool {
match name {
"ArithmeticError"
@ -196,6 +209,7 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -
("Array!", _, "push!") => Str::ever("append"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Real") => Str::ever("real"),
("Complex" | "Real" | "Int" | "Nat" | "Float", _, "Imag") => Str::ever("imag"),
(_, _, "__new__") => Str::ever("__call__"),
("StringIO!", _, "getvalue!") => Str::ever("getvalue"),
("Module", Some("importlib"), "reload!") => Str::ever("reload"),
("Module", Some("random"), "randint!") => Str::ever("randint"),
@ -207,11 +221,17 @@ fn convert_to_python_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -
}
}
fn escape_attr(class: &str, uniq_obj_name: Option<&str>, name: Str) -> Str {
let mut name = convert_to_python_attr(class, uniq_obj_name, name).to_string();
fn escape_attr(class: &str, uniq_obj_name: Option<&str>, ident: Identifier) -> Str {
let vis = ident.vis();
let mut name =
convert_to_python_attr(class, uniq_obj_name, ident.name.into_token().content).to_string();
name = name.replace('!', "__erg_proc__");
name = name.replace('$', "__erg_shared__");
Str::rc(&name)
if vis.is_public() || is_python_global(&name) || is_python_special(&name) {
Str::from(name)
} else {
Str::from("::".to_string() + &name)
}
}
fn convert_to_python_name(name: Str) -> Str {
@ -247,7 +267,7 @@ fn escape_name(ident: Identifier) -> Str {
let mut name = convert_to_python_name(ident.name.into_token().content).to_string();
name = name.replace('!', "__erg_proc__");
name = name.replace('$', "__erg_shared__");
if vis.is_public() || is_python_global(&name) {
if vis.is_public() || is_python_global(&name) || is_python_special(&name) {
Str::from(name)
} else {
Str::from("::".to_string() + &name)
@ -312,7 +332,7 @@ impl_stream_for_wrapper!(CodeGenStack, CodeGenUnit);
pub struct CodeGenerator {
cfg: ErgConfig,
str_cache: CacheSet<str>,
namedtuple_loaded: bool,
prelude_loaded: bool,
unit_size: usize,
units: CodeGenStack,
pub(crate) errs: CompileErrors,
@ -323,7 +343,7 @@ impl CodeGenerator {
Self {
cfg,
str_cache: CacheSet::new(),
namedtuple_loaded: false,
prelude_loaded: false,
unit_size: 0,
units: CodeGenStack::empty(),
errs: CompileErrors::empty(),
@ -439,7 +459,7 @@ impl CodeGenerator {
self.stack_inc();
}
fn local_search(&self, name: &str, acc_kind: AccessKind) -> Option<Name> {
fn local_search(&self, name: &str, _acc_kind: AccessKind) -> Option<Name> {
let current_is_toplevel = self.cur_block() == self.toplevel_block();
if let Some(idx) = self
.cur_block_codeobj()
@ -447,11 +467,7 @@ impl CodeGenerator {
.iter()
.position(|n| &**n == name)
{
if current_is_toplevel || !acc_kind.is_local() {
Some(Name::local(idx))
} else {
Some(Name::global(idx))
}
Some(Name::local(idx))
} else if let Some(idx) = self
.cur_block_codeobj()
.varnames
@ -497,9 +513,8 @@ impl CodeGenerator {
Some(StoreLoadKind::Global)
}
fn register_name(&mut self, ident: Identifier) -> Name {
fn register_name(&mut self, name: Str) -> Name {
let current_is_toplevel = self.cur_block() == self.toplevel_block();
let name = escape_name(ident);
match self.rec_search(&name) {
Some(st @ (StoreLoadKind::Local | StoreLoadKind::Global)) => {
let st = if current_is_toplevel {
@ -530,24 +545,22 @@ impl CodeGenerator {
}
}
fn register_attr(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
fn register_attr(&mut self, name: Str) -> Name {
self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1)
}
fn register_method(&mut self, class: &str, uniq_obj_name: Option<&str>, name: Str) -> Name {
let name = Str::rc(name.split('.').last().unwrap());
let name = escape_attr(class, uniq_obj_name, name);
fn register_method(&mut self, name: Str) -> Name {
self.mut_cur_block_codeobj().names.push(name);
Name::local(self.cur_block_codeobj().names.len() - 1)
}
fn emit_load_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -561,9 +574,11 @@ impl CodeGenerator {
}
fn emit_import_name_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_NAME);
self.write_arg(name.idx as u8);
self.stack_dec(); // (level + from_list) -> module object
@ -571,9 +586,11 @@ impl CodeGenerator {
}
fn emit_import_from_instr(&mut self, ident: Identifier) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(ident.inspect(), Name)
.unwrap_or_else(|| self.register_name(ident));
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
self.write_instr(IMPORT_FROM);
self.write_arg(name.idx as u8);
// self.stack_inc(); (module object) -> attribute
@ -584,11 +601,13 @@ impl CodeGenerator {
&mut self,
class: &str,
uniq_obj_name: Option<&str>,
name: Str,
ident: Identifier,
) -> CompileResult<()> {
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self
.local_search(&name, Attr)
.unwrap_or_else(|| self.register_attr(class, uniq_obj_name, name));
.local_search(&escaped, Attr)
.unwrap_or_else(|| self.register_attr(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -604,11 +623,13 @@ impl CodeGenerator {
&mut self,
class: &str,
uniq_obj_name: Option<&str>,
name: Str,
ident: Identifier,
) -> CompileResult<()> {
log!(info "entered {} ({class}{ident})", fn_name!());
let escaped = escape_attr(class, uniq_obj_name, ident);
let name = self
.local_search(&name, Method)
.unwrap_or_else(|| self.register_method(class, uniq_obj_name, name));
.local_search(&escaped, Method)
.unwrap_or_else(|| self.register_method(escaped));
let instr = match name.kind {
StoreLoadKind::Fast | StoreLoadKind::FastConst => Opcode::LOAD_FAST,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::LOAD_GLOBAL,
@ -621,13 +642,21 @@ impl CodeGenerator {
}
fn emit_store_instr(&mut self, ident: Identifier, acc_kind: AccessKind) {
let name = self
.local_search(ident.inspect(), acc_kind)
.unwrap_or_else(|| self.register_name(ident));
log!(info "entered {} ({ident})", fn_name!());
let escaped = escape_name(ident);
let name = self.local_search(&escaped, acc_kind).unwrap_or_else(|| {
if acc_kind.is_local() {
self.register_name(escaped)
} else {
self.register_attr(escaped)
}
});
let instr = match name.kind {
StoreLoadKind::Fast => Opcode::STORE_FAST,
StoreLoadKind::FastConst => Opcode::ERG_STORE_FAST_IMMUT,
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::STORE_GLOBAL,
// NOTE: First-time variables are treated as GLOBAL, but they are always first-time variables when assigned, so they are just NAME
// NOTE: 初見の変数はGLOBAL扱いになるが、代入時は必ず初見であるので単なるNAME
StoreLoadKind::Global | StoreLoadKind::GlobalConst => Opcode::STORE_NAME,
StoreLoadKind::Deref | StoreLoadKind::DerefConst => Opcode::STORE_DEREF,
StoreLoadKind::Local | StoreLoadKind::LocalConst => {
match acc_kind {
@ -641,6 +670,25 @@ impl CodeGenerator {
self.write_instr(instr);
self.write_arg(name.idx as u8);
self.stack_dec();
if instr == Opcode::STORE_ATTR {
self.stack_dec();
}
}
/// Ergの文法として、属性への代入は存在しない(必ずオブジェクトはすべての属性を初期化しなくてはならないため)
/// この関数はPythonへ落とし込むときに使う
fn store_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!());
match acc {
Accessor::Ident(ident) => {
self.emit_store_instr(ident, Name);
}
Accessor::Attr(attr) => {
self.codegen_expr(*attr.obj);
self.emit_store_instr(attr.ident, Attr);
}
acc => todo!("store: {acc}"),
}
}
fn emit_pop_top(&mut self) {
@ -675,39 +723,68 @@ impl CodeGenerator {
.non_defaults
.iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_"))
.chain(if let Some(var_args) = &params.var_args {
vec![var_args.inspect().map(|s| &s[..]).unwrap_or("_")]
} else {
vec![]
})
.chain(
params
.defaults
.iter()
.map(|p| p.inspect().map(|s| &s[..]).unwrap_or("_")),
)
.map(|s| self.get_cached(s))
.map(|s| format!("::{s}"))
.map(|s| self.get_cached(&s))
.collect()
}
fn emit_mono_type_def(&mut self, sig: VarSignature, body: DefBody) {
fn emit_class_def(&mut self, class_def: ClassDef) {
log!(info "entered {} ({class_def})", fn_name!());
let ident = class_def.sig.ident().clone();
let kind = class_def.kind;
let require_or_sup = class_def.require_or_sup.clone();
self.write_instr(Opcode::LOAD_BUILD_CLASS);
self.write_arg(0);
self.stack_inc();
let code = self.codegen_typedef_block(sig.inspect().clone(), body.block);
let code = self.codegen_typedef_block(class_def);
self.emit_load_const(code);
self.emit_load_const(sig.inspect().clone());
self.emit_load_const(ident.inspect().clone());
self.write_instr(Opcode::MAKE_FUNCTION);
self.write_arg(0);
self.emit_load_const(sig.inspect().clone());
self.emit_load_const(ident.inspect().clone());
// LOAD subclasses
let subclasses_len = self.emit_require_type(kind, *require_or_sup);
self.write_instr(Opcode::CALL_FUNCTION);
self.write_arg(2);
self.stack_dec_n((1 + 2) - 1);
self.emit_store_instr(sig.ident, Name);
self.write_arg(2 + subclasses_len as u8);
self.stack_dec_n((1 + 2 + subclasses_len) - 1);
self.emit_store_instr(ident, Name);
self.stack_dec();
}
// NOTE: use `TypeVar`, `Generic` in `typing` module
// fn emit_poly_type_def(&mut self, sig: SubrSignature, body: DefBody) {}
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
if body.is_type() {
return self.emit_mono_type_def(sig, body);
fn emit_require_type(&mut self, kind: TypeKind, require_or_sup: Expr) -> usize {
log!(info "entered {} ({kind:?}, {require_or_sup})", fn_name!());
match kind {
TypeKind::Class => 0,
TypeKind::Subclass => {
self.codegen_expr(require_or_sup);
1 // TODO: not always 1
}
_ => todo!(),
}
}
fn emit_attr_def(&mut self, attr_def: AttrDef) {
log!(info "entered {} ({attr_def})", fn_name!());
self.codegen_frameless_block(attr_def.block, vec![]);
self.store_acc(attr_def.attr);
}
fn emit_var_def(&mut self, sig: VarSignature, mut body: DefBody) {
log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
if body.block.len() == 1 {
self.codegen_expr(body.block.remove(0));
} else {
@ -716,7 +793,8 @@ impl CodeGenerator {
self.emit_store_instr(sig.ident, Name);
}
fn emit_subr_def(&mut self, sig: SubrSignature, body: DefBody) {
fn emit_subr_def(&mut self, class_name: Option<&str>, sig: SubrSignature, body: DefBody) {
log!(info "entered {} ({sig} = {})", fn_name!(), body.block);
let name = sig.ident.inspect().clone();
let mut opcode_flag = 0u8;
let params = self.gen_param_names(&sig.params);
@ -732,7 +810,11 @@ impl CodeGenerator {
self.write_arg(cellvars_len);
opcode_flag += 8;
}
self.emit_load_const(name.clone());
if let Some(class) = class_name {
self.emit_load_const(Str::from(format!("{class}.{name}")));
} else {
self.emit_load_const(name);
}
self.write_instr(MAKE_FUNCTION);
self.write_arg(opcode_flag);
// stack_dec: <code obj> + <name> -> <function>
@ -741,6 +823,7 @@ impl CodeGenerator {
}
fn emit_discard_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
while let Some(arg) = args.try_remove(0) {
self.codegen_expr(arg);
self.emit_pop_top();
@ -749,6 +832,7 @@ impl CodeGenerator {
}
fn emit_if_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let cond = args.remove(0);
self.codegen_expr(cond);
let idx_pop_jump_if_false = self.cur_block().lasti;
@ -797,6 +881,7 @@ impl CodeGenerator {
}
fn emit_for_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let iterable = args.remove(0);
self.codegen_expr(iterable);
self.write_instr(GET_ITER);
@ -819,6 +904,7 @@ impl CodeGenerator {
}
fn emit_match_instr(&mut self, mut args: Args, _use_erg_specific: bool) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
let expr = args.remove(0);
self.codegen_expr(expr);
let len = args.len();
@ -855,10 +941,11 @@ impl CodeGenerator {
}
fn emit_match_pattern(&mut self, pat: ParamPattern) -> CompileResult<Vec<usize>> {
log!(info "entered {}", fn_name!());
let mut pop_jump_points = vec![];
match pat {
ParamPattern::VarName(name) => {
let ident = Identifier::new(None, name);
let ident = Identifier::bare(None, name);
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Lit(lit) => {
@ -908,19 +995,24 @@ impl CodeGenerator {
}
fn emit_call(&mut self, call: Call) {
log!(info "entered {} ({call})", fn_name!());
if let Some(method_name) = call.method_name {
self.emit_call_method(*call.obj, method_name, call.args);
} else {
match *call.obj {
Expr::Accessor(Accessor::Local(local)) => {
self.emit_call_local(local, call.args).unwrap()
Expr::Accessor(Accessor::Ident(ident)) if ident.vis().is_private() => {
self.emit_call_local(ident, call.args).unwrap()
}
other => {
self.codegen_expr(other);
self.emit_args(call.args, Name);
}
other => todo!("calling {other}"),
}
}
}
fn emit_call_local(&mut self, local: Local, mut args: Args) -> CompileResult<()> {
fn emit_call_local(&mut self, local: Identifier, args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
match &local.inspect()[..] {
"assert" => self.emit_assert_instr(args),
"discard" => self.emit_discard_instr(args),
@ -928,54 +1020,50 @@ impl CodeGenerator {
"if" | "if!" => self.emit_if_instr(args),
"match" | "match!" => self.emit_match_instr(args, true),
_ => {
let name = VarName::new(local.name);
let ident = Identifier::new(None, name);
self.emit_load_name_instr(ident).unwrap_or_else(|e| {
self.emit_load_name_instr(local).unwrap_or_else(|e| {
self.errs.push(e);
});
let argc = args.len();
let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr);
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
}
let kwsc = if !kws.is_empty() {
let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW);
1
} else {
self.write_instr(CALL_FUNCTION);
0
};
self.write_arg(argc as u8);
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1);
self.emit_args(args, Name);
Ok(())
}
}
}
fn emit_call_method(&mut self, obj: Expr, method_name: Token, mut args: Args) {
fn emit_call_method(&mut self, obj: Expr, method_name: Identifier, args: Args) {
log!(info "entered {}", fn_name!());
if &method_name.inspect()[..] == "update!" {
return self.emit_call_update(obj, args);
}
let class = obj.ref_t().name(); // これは必ずmethodのあるクラスになっている
let uniq_obj_name = obj.__name__().map(Str::rc);
self.codegen_expr(obj);
self.emit_load_method_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
method_name.content,
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_load_method_instr(&class, uniq_obj_name.as_ref().map(|s| &s[..]), method_name)
.unwrap_or_else(|err| {
self.errs.push(err);
});
self.emit_args(args, Method);
}
fn emit_args(&mut self, mut args: Args, kind: AccessKind) {
let argc = args.len();
let pos_len = args.pos_args.len();
let mut kws = Vec::with_capacity(args.kw_len());
while let Some(arg) = args.try_remove_pos(0) {
self.codegen_expr(arg.expr);
}
if let Some(var_args) = &args.var_args {
if pos_len > 0 {
self.write_instr(Opcode::BUILD_LIST);
self.write_arg(pos_len as u8);
}
self.codegen_expr(var_args.expr.clone());
if pos_len > 0 {
self.write_instr(Opcode::LIST_EXTEND);
self.write_arg(1);
self.write_instr(Opcode::LIST_TO_TUPLE);
self.write_arg(0);
}
}
while let Some(arg) = args.try_remove_kw(0) {
kws.push(ValueObj::Str(arg.keyword.content.clone()));
self.codegen_expr(arg.expr);
@ -984,18 +1072,49 @@ impl CodeGenerator {
let kws_tuple = ValueObj::from(kws);
self.emit_load_const(kws_tuple);
self.write_instr(CALL_FUNCTION_KW);
self.write_arg(argc as u8);
1
} else {
self.write_instr(CALL_METHOD);
if args.var_args.is_some() {
self.write_instr(CALL_FUNCTION_EX);
if kws.is_empty() {
self.write_arg(0);
} else {
self.write_arg(1);
}
} else {
if kind.is_method() {
self.write_instr(CALL_METHOD);
} else {
self.write_instr(CALL_FUNCTION);
}
self.write_arg(argc as u8);
}
0
};
self.write_arg(argc as u8);
// (1 (method) + argc + kwsc) input objects -> 1 return object
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + argc + kwsc) - 1);
}
/// X.update! x -> x + 1
/// X = (x -> x + 1)(X)
/// X = X + 1
fn emit_call_update(&mut self, obj: Expr, mut args: Args) {
log!(info "entered {}", fn_name!());
let acc = enum_unwrap!(obj, Expr::Accessor);
let func = args.remove_left_or_key("f").unwrap();
self.codegen_expr(func);
self.codegen_acc(acc.clone());
self.write_instr(CALL_FUNCTION);
self.write_arg(1 as u8);
// (1 (subroutine) + argc) input objects -> 1 return object
self.stack_dec_n((1 + 1) - 1);
self.store_acc(acc);
}
// assert takes 1 or 2 arguments (0: cond, 1: message)
fn emit_assert_instr(&mut self, mut args: Args) -> CompileResult<()> {
log!(info "entered {}", fn_name!());
self.codegen_expr(args.remove(0));
let pop_jump_point = self.cur_block().lasti;
self.write_instr(Opcode::POP_JUMP_IF_TRUE);
@ -1016,6 +1135,7 @@ impl CodeGenerator {
}
fn codegen_expr(&mut self, expr: Expr) {
log!(info "entered {} ({expr})", fn_name!());
if expr.ln_begin().unwrap_or_else(|| panic!("{expr}")) > self.cur_block().prev_lineno {
let sd = self.cur_block().lasti - self.cur_block().prev_lasti;
let ld = expr.ln_begin().unwrap() - self.cur_block().prev_lineno;
@ -1052,9 +1172,11 @@ impl CodeGenerator {
}
Expr::Accessor(acc) => self.codegen_acc(acc),
Expr::Def(def) => match def.sig {
Signature::Subr(sig) => self.emit_subr_def(sig, def.body),
Signature::Subr(sig) => self.emit_subr_def(None, sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body),
},
Expr::ClassDef(class) => self.emit_class_def(class),
Expr::AttrDef(attr) => self.emit_attr_def(attr),
// TODO:
Expr::Lambda(lambda) => {
let params = self.gen_param_names(&lambda.params);
@ -1193,20 +1315,6 @@ impl CodeGenerator {
},
Expr::Record(rec) => {
let attrs_len = rec.attrs.len();
// importing namedtuple
if !self.namedtuple_loaded {
self.emit_load_const(0);
self.emit_load_const(ValueObj::Tuple(std::rc::Rc::from([ValueObj::Str(
Str::ever("namedtuple"),
)])));
let ident = Identifier::public("collections");
self.emit_import_name_instr(ident).unwrap();
let ident = Identifier::public("namedtuple");
self.emit_import_from_instr(ident).unwrap();
let ident = Identifier::private(Str::ever("#NamedTuple"));
self.emit_store_instr(ident, Name);
self.namedtuple_loaded = true;
}
// making record type
let ident = Identifier::private(Str::ever("#NamedTuple"));
self.emit_load_name_instr(ident).unwrap();
@ -1252,15 +1360,9 @@ impl CodeGenerator {
}
fn codegen_acc(&mut self, acc: Accessor) {
log!(info "entered {} ({acc})", fn_name!());
match acc {
Accessor::Local(local) => {
self.emit_load_name_instr(Identifier::new(None, VarName::new(local.name)))
.unwrap_or_else(|err| {
self.errs.push(err);
});
}
Accessor::Public(public) => {
let ident = Identifier::new(Some(public.dot), VarName::new(public.name));
Accessor::Ident(ident) => {
self.emit_load_name_instr(ident).unwrap_or_else(|err| {
self.errs.push(err);
});
@ -1268,15 +1370,27 @@ impl CodeGenerator {
Accessor::Attr(a) => {
let class = a.obj.ref_t().name();
let uniq_obj_name = a.obj.__name__().map(Str::rc);
self.codegen_expr(*a.obj);
self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.name.content.clone(),
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
// C = Class ...
// C.
// a = C.x
// ↓
// class C:
// a = x
if Some(&self.cur_block_codeobj().name[..]) != a.obj.__name__() {
self.codegen_expr(*a.obj);
self.emit_load_attr_instr(
&class,
uniq_obj_name.as_ref().map(|s| &s[..]),
a.ident,
)
.unwrap_or_else(|err| {
self.errs.push(err);
});
} else {
self.emit_load_name_instr(a.ident).unwrap_or_else(|err| {
self.errs.push(err);
});
}
}
Accessor::TupleAttr(t_attr) => {
self.codegen_expr(*t_attr.obj);
@ -1297,6 +1411,7 @@ impl CodeGenerator {
/// forブロックなどで使う
fn codegen_frameless_block(&mut self, block: Block, params: Vec<Str>) {
log!(info "entered {}", fn_name!());
for param in params {
self.emit_store_instr(Identifier::private(param), Name);
}
@ -1311,23 +1426,50 @@ impl CodeGenerator {
self.cancel_pop_top();
}
fn codegen_typedef_block(&mut self, name: Str, block: Block) -> CodeObj {
fn codegen_typedef_block(&mut self, class: ClassDef) -> CodeObj {
log!(info "entered {}", fn_name!());
let name = class.sig.ident().inspect().clone();
self.unit_size += 1;
let firstlineno = match (
class.private_methods.get(0).and_then(|def| def.ln_begin()),
class.public_methods.get(0).and_then(|def| def.ln_begin()),
) {
(Some(l), Some(r)) => l.min(r),
(Some(line), None) | (None, Some(line)) => line,
(None, None) => class.sig.ln_begin().unwrap(),
};
self.units.push(CodeGenUnit::new(
self.unit_size,
vec![],
Str::rc(self.cfg.input.enclosed_name()),
&name,
block[0].ln_begin().unwrap(),
firstlineno,
));
let mod_name = self.toplevel_block_codeobj().name.clone();
self.emit_load_const(mod_name);
self.emit_store_instr(Identifier::public("__module__"), Attr);
self.emit_load_const(name);
self.emit_store_instr(Identifier::public("__qualname__"), Attr);
// TODO: サブルーチンはT.subという書式でSTORE
for expr in block.into_iter() {
self.codegen_expr(expr);
self.emit_store_instr(Identifier::public("__module__"), Name);
self.emit_load_const(name.clone());
self.emit_store_instr(Identifier::public("__qualname__"), Name);
self.emit_init_method(&class.sig, class.__new__.clone());
if class.need_to_gen_new {
self.emit_new_func(&class.sig, class.__new__);
}
for def in class.private_methods.into_iter() {
match def.sig {
Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body),
}
// TODO: discard
if self.cur_block().stack_len == 1 {
self.emit_pop_top();
}
}
for mut def in class.public_methods.into_iter() {
def.sig.ident_mut().dot = Some(Token::dummy());
match def.sig {
Signature::Subr(sig) => self.emit_subr_def(Some(&name[..]), sig, def.body),
Signature::Var(sig) => self.emit_var_def(sig, def.body),
}
// TODO: discard
if self.cur_block().stack_len == 1 {
self.emit_pop_top();
@ -1366,7 +1508,102 @@ impl CodeGenerator {
unit.codeobj
}
fn emit_init_method(&mut self, sig: &Signature, __new__: Type) {
log!(info "entered {}", fn_name!());
let line = sig.ln_begin().unwrap();
let class_name = sig.ident().inspect();
let ident = Identifier::public_with_line(Token::dummy(), Str::ever("__init__"), line);
let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = ParamSignature::new(ParamPattern::VarName(param), None, None);
let self_param = VarName::from_str_and_line(Str::ever("self"), line);
let self_param = ParamSignature::new(ParamPattern::VarName(self_param), None, None);
let params = Params::new(vec![self_param, param], None, vec![], None);
let subr_sig = SubrSignature::new(ident, params.clone(), __new__.clone());
let mut attrs = vec![];
match __new__.non_default_params().unwrap()[0].typ() {
// namedtupleは仕様上::xなどの名前を使えない
// {x = Int; y = Int}
// => self::x = %x.x; self::y = %x.y
// {.x = Int; .y = Int}
// => self.x = %x.x; self.y = %x.y
Type::Record(rec) => {
for field in rec.keys() {
let obj =
Expr::Accessor(Accessor::private_with_line(Str::from(&param_name), line));
let expr = Expr::Accessor(Accessor::Attr(Attribute::new(
obj,
Identifier::bare(
Some(Token::dummy()),
VarName::from_str(field.symbol.clone()),
),
Type::Failure,
)));
let obj = Expr::Accessor(Accessor::private_with_line(Str::ever("self"), line));
let dot = if field.vis.is_private() {
None
} else {
Some(Token::dummy())
};
let attr = Accessor::Attr(Attribute::new(
obj,
Identifier::bare(dot, VarName::from_str(field.symbol.clone())),
Type::Failure,
));
let attr_def = AttrDef::new(attr, Block::new(vec![expr]));
attrs.push(Expr::AttrDef(attr_def));
}
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
attrs.push(Expr::Lit(Literal::from(none)));
}
other => todo!("{other}"),
}
let block = Block::new(attrs);
let body = DefBody::new(Token::dummy(), block, DefId(0));
self.emit_subr_def(Some(class_name), subr_sig, body);
}
/// ```python
/// class C:
/// # __new__ => __call__
/// def new(x): return C.__call__(x)
/// ```
fn emit_new_func(&mut self, sig: &Signature, __new__: Type) {
log!(info "entered {}", fn_name!());
let class_name = sig.ident().inspect();
let line = sig.ln_begin().unwrap();
let ident = Identifier::public_with_line(Token::dummy(), Str::ever("new"), line);
let param_name = fresh_varname();
let param = VarName::from_str_and_line(Str::from(param_name.clone()), line);
let param = ParamSignature::new(ParamPattern::VarName(param), None, None);
let sig = SubrSignature::new(
ident,
Params::new(vec![param], None, vec![], None),
__new__.clone(),
);
let arg = PosArg::new(Expr::Accessor(Accessor::private_with_line(
Str::from(param_name),
line,
)));
let class = Expr::Accessor(Accessor::private_with_line(class_name.clone(), line));
let class_new = Expr::Accessor(Accessor::attr(
class,
Identifier::bare(None, VarName::from_str_and_line(Str::ever("__new__"), line)),
Type::Failure,
));
let call = Expr::Call(Call::new(
class_new,
None,
Args::new(vec![arg], None, vec![], None),
Type::Failure,
));
let block = Block::new(vec![call]);
let body = DefBody::new(Token::dummy(), block, DefId(0));
self.emit_subr_def(Some(&class_name[..]), sig, body);
}
fn codegen_block(&mut self, block: Block, opt_name: Option<Str>, params: Vec<Str>) -> CodeObj {
log!(info "entered {}", fn_name!());
self.unit_size += 1;
let name = if let Some(name) = opt_name {
name
@ -1414,7 +1651,10 @@ impl CodeGenerator {
// end of flagging
let unit = self.units.pop().unwrap();
if !self.units.is_empty() {
let ld = unit.prev_lineno - self.cur_block().prev_lineno;
let ld = unit
.prev_lineno
.checked_sub(self.cur_block().prev_lineno)
.unwrap_or(0);
if ld != 0 {
if let Some(l) = self.mut_cur_block_codeobj().lnotab.last_mut() {
*l += ld as u8;
@ -1425,6 +1665,25 @@ impl CodeGenerator {
unit.codeobj
}
fn load_prelude(&mut self) {
self.init_record();
}
fn init_record(&mut self) {
// importing namedtuple
self.emit_load_const(0);
self.emit_load_const(ValueObj::Tuple(std::rc::Rc::from([ValueObj::Str(
Str::ever("namedtuple"),
)])));
let ident = Identifier::public("collections");
self.emit_import_name_instr(ident).unwrap();
let ident = Identifier::public("namedtuple");
self.emit_import_from_instr(ident).unwrap();
let ident = Identifier::private(Str::ever("#NamedTuple"));
self.emit_store_instr(ident, Name);
// self.namedtuple_loaded = true;
}
pub fn codegen(&mut self, hir: HIR) -> CodeObj {
log!(info "the code-generating process has started.{RESET}");
self.unit_size += 1;
@ -1435,6 +1694,10 @@ impl CodeGenerator {
"<module>",
1,
));
if !self.prelude_loaded {
self.load_prelude();
self.prelude_loaded = true;
}
let mut print_point = 0;
if self.input().is_repl() {
print_point = self.cur_block().lasti;

View file

@ -15,6 +15,7 @@ use erg_parser::ParserRunner;
use crate::codegen::CodeGenerator;
use crate::effectcheck::SideEffectChecker;
use crate::error::{CompileError, CompileErrors, TyCheckErrors};
use crate::link::Linker;
use crate::lower::ASTLowerer;
use crate::ownercheck::OwnershipChecker;
@ -158,11 +159,13 @@ impl Compiler {
}
pub fn compile(&mut self, src: Str, mode: &str) -> Result<CodeObj, CompileErrors> {
log!(info "the compiling process has started");
log!(info "the compiling process has started.");
let mut cfg = self.cfg.copy();
cfg.input = Input::Str(src);
let mut parser = ParserRunner::new(cfg);
let ast = parser.parse()?;
let linker = Linker::new();
let ast = linker.link(ast).map_err(|errs| self.convert(errs))?;
let (hir, warns) = self
.lowerer
.lower(ast, mode)
@ -182,8 +185,7 @@ impl Compiler {
let codeobj = self.code_generator.codegen(hir);
log!(info "code object:\n{}", codeobj.code_info());
log!(
c GREEN,
"the compiling process has completed, found errors: {}",
info "the compiling process has completed, found errors: {}",
self.code_generator.errs.len()
);
if self.code_generator.errs.is_empty() {

View file

@ -1,7 +1,7 @@
//! provides type-comparison
use std::option::Option; // conflicting to Type::Option
use erg_type::constructors::or;
use erg_type::constructors::{and, or};
use erg_type::free::fresh_varname;
use erg_type::free::{Constraint, Cyclicity, FreeKind, FreeTyVar};
use erg_type::typaram::{TyParam, TyParamOrdering};
@ -50,9 +50,7 @@ impl Context {
pub(crate) fn eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool {
match (lhs, rhs) {
(TyParam::Type(lhs), TyParam::Type(rhs)) => {
return self.structural_same_type_of(lhs, rhs)
}
(TyParam::Type(lhs), TyParam::Type(rhs)) => return self.same_type_of(lhs, rhs),
(TyParam::Mono(l), TyParam::Mono(r)) => {
if let (Some(l), Some(r)) = (self.rec_get_const_obj(l), self.rec_get_const_obj(r)) {
return l == r;
@ -61,6 +59,23 @@ impl Context {
(TyParam::MonoQVar(name), _other) | (_other, TyParam::MonoQVar(name)) => {
panic!("Not instantiated type parameter: {name}")
}
(TyParam::UnaryOp { op: lop, val: lval }, TyParam::UnaryOp { op: rop, val: rval }) => {
return lop == rop && self.eq_tp(lval, rval);
}
(
TyParam::BinOp {
op: lop,
lhs: ll,
rhs: lr,
},
TyParam::BinOp {
op: rop,
lhs: rl,
rhs: rr,
},
) => {
return lop == rop && self.eq_tp(ll, rl) && self.eq_tp(lr, rr);
}
(
TyParam::App {
name: ln,
@ -80,19 +95,21 @@ impl Context {
}
(TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) => match &*fv.borrow() {
FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => {
return self.eq_tp(t, other)
return self.eq_tp(t, other);
}
FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } => {
let t = constraint.get_type().unwrap();
let other_t = self.type_of(other);
return self.structural_supertype_of(t, &other_t);
return self.same_type_of(t, &other_t);
}
},
(l, r) if l == r => return true,
(l, r) if l == r => {
return true;
}
_ => {}
}
self.eval.shallow_eq_tp(lhs, rhs, self)
self.shallow_eq_tp(lhs, rhs)
}
/// e.g.
@ -144,14 +161,18 @@ impl Context {
}
}
pub(crate) fn same_type_of(&self, lhs: &Type, rhs: &Type) -> bool {
self.supertype_of(lhs, rhs) && self.subtype_of(lhs, rhs)
}
pub(crate) fn cheap_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if lhs == rhs {
return (Absolutely, true);
}
match (lhs, rhs) {
// FIXME: Obj/Neverはクラス、Top/Bottomは構造型
(Obj, _) | (_, Never) => (Absolutely, true),
(_, Obj) | (Never, _) => (Absolutely, false),
// (_, Obj) if !lhs.is_unbound_var() => (Absolutely, false),
// (Never, _) if !rhs.is_unbound_var() => (Absolutely, false),
(Float | Ratio | Int | Nat | Bool, Bool)
| (Float | Ratio | Int | Nat, Nat)
| (Float | Ratio | Int, Int)
@ -164,14 +185,9 @@ impl Context {
),
(Type, Subr(subr)) => (
Absolutely,
subr.kind
.self_t()
.map(|t| self.supertype_of(&Type, t))
.unwrap_or(true)
&& subr
.non_default_params
.iter()
.all(|pt| self.supertype_of(&Type, &pt.typ()))
subr.non_default_params
.iter()
.all(|pt| self.supertype_of(&Type, &pt.typ()))
&& subr
.default_params
.iter()
@ -184,44 +200,30 @@ impl Context {
&& self.supertype_of(&Type, &subr.return_t),
),
(
Type::MonoClass(n),
Type::Mono(n),
Subr(SubrType {
kind: SubrKind::Func,
..
}),
) if &n[..] == "GenericFunc" => (Absolutely, true),
(
Type::MonoClass(n),
Type::Mono(n),
Subr(SubrType {
kind: SubrKind::Proc,
..
}),
) if &n[..] == "GenericProc" => (Absolutely, true),
(
Type::MonoClass(n),
Subr(SubrType {
kind: SubrKind::FuncMethod(_),
..
}),
) if &n[..] == "GenericFuncMethod" => (Absolutely, true),
(
Type::MonoClass(n),
Subr(SubrType {
kind: SubrKind::ProcMethod { .. },
..
}),
) if &n[..] == "GenericProcMethod" => (Absolutely, true),
(Type::MonoClass(l), Type::PolyClass { name: r, .. })
(Type::Mono(l), Type::Poly { name: r, .. })
if &l[..] == "GenericArray" && &r[..] == "Array" =>
{
(Absolutely, true)
}
(Type::MonoClass(l), Type::PolyClass { name: r, .. })
(Type::Mono(l), Type::Poly { name: r, .. })
if &l[..] == "GenericDict" && &r[..] == "Dict" =>
{
(Absolutely, true)
}
(Type::MonoClass(l), Type::MonoClass(r))
(Type::Mono(l), Type::Mono(r))
if &l[..] == "GenericCallable"
&& (&r[..] == "GenericFunc"
|| &r[..] == "GenericProc"
@ -230,11 +232,11 @@ impl Context {
{
(Absolutely, true)
}
(_, Type::FreeVar(fv)) | (Type::FreeVar(fv), _) => match fv.crack_bound_types() {
(_, Type::FreeVar(fv)) | (Type::FreeVar(fv), _) => match fv.get_bound_types() {
Some((Type::Never, Type::Obj)) => (Absolutely, true),
_ => (Maybe, false),
},
(Type::MonoClass(n), Subr(_)) if &n[..] == "GenericCallable" => (Absolutely, true),
(Type::Mono(n), Subr(_)) if &n[..] == "GenericCallable" => (Absolutely, true),
(lhs, rhs) if lhs.is_simple_class() && rhs.is_simple_class() => (Absolutely, false),
_ => (Maybe, false),
}
@ -258,7 +260,7 @@ impl Context {
}
_ => {}
}
match self.trait_supertype_of(lhs, rhs) {
match self.traits_supertype_of(lhs, rhs) {
(Absolutely, judge) => {
self.register_cache(rhs, lhs, judge);
return judge;
@ -292,20 +294,19 @@ impl Context {
}
fn classes_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if !lhs.is_class() || !rhs.is_class() {
return (Maybe, false);
}
for (rhs_sup, _) in self.rec_get_nominal_super_class_ctxs(rhs) {
match self.cheap_supertype_of(lhs, rhs_sup) {
(Absolutely, true) => {
return (Absolutely, true);
}
(Maybe, _) => {
if self.structural_supertype_of(lhs, rhs_sup) {
if let Some(sup_classes) = self.rec_get_nominal_super_class_ctxs(rhs) {
for (rhs_sup, _) in sup_classes {
match self.cheap_supertype_of(lhs, rhs_sup) {
(Absolutely, true) => {
return (Absolutely, true);
}
(Maybe, _) => {
if self.structural_supertype_of(lhs, rhs_sup) {
return (Absolutely, true);
}
}
_ => {}
}
_ => {}
}
}
(Maybe, false)
@ -313,22 +314,21 @@ impl Context {
// e.g. Eq(Nat) :> Nat
// Nat.super_traits = [Add(Nat), Eq(Nat), ...]
fn trait_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if !lhs.is_trait() {
return (Maybe, false);
}
for (rhs_sup, _) in self.rec_get_nominal_super_trait_ctxs(rhs) {
match self.cheap_supertype_of(lhs, rhs_sup) {
(Absolutely, true) => {
return (Absolutely, true);
}
(Maybe, _) => {
// nominal type同士の比較なので、nominal_supertype_ofは使わない
if self.structural_supertype_of(lhs, rhs_sup) {
fn traits_supertype_of(&self, lhs: &Type, rhs: &Type) -> (Credibility, bool) {
if let Some(sup_traits) = self.rec_get_nominal_super_trait_ctxs(rhs) {
for (rhs_sup, _) in sup_traits {
match self.cheap_supertype_of(lhs, rhs_sup) {
(Absolutely, true) => {
return (Absolutely, true);
}
(Maybe, _) => {
// nominal type同士の比較なので、nominal_supertype_ofは使わない
if self.structural_supertype_of(lhs, rhs_sup) {
return (Absolutely, true);
}
}
_ => {}
}
_ => {}
}
}
(Maybe, false)
@ -339,7 +339,7 @@ impl Context {
/// assert sup_conforms(?E(<: Eq(?R)), base: T, sup_trait: Eq(U))
/// ```
fn sup_conforms(&self, free: &FreeTyVar, base: &Type, sup_trait: &Type) -> bool {
let (_sub, sup) = free.crack_bound_types().unwrap();
let (_sub, sup) = free.get_bound_types().unwrap();
free.forced_undoable_link(base);
let judge = self.supertype_of(&sup, sup_trait);
free.undo();
@ -349,7 +349,7 @@ impl Context {
/// assert!(sup_conforms(?E(<: Eq(?E)), {Nat, Eq(Nat)}))
/// assert!(sup_conforms(?E(<: Eq(?R)), {Nat, Eq(T)}))
fn _sub_conforms(&self, free: &FreeTyVar, inst_pair: &TraitInstance) -> bool {
let (_sub, sup) = free.crack_bound_types().unwrap();
let (_sub, sup) = free.get_bound_types().unwrap();
log!(info "{free}");
free.forced_undoable_link(&inst_pair.sub_type);
log!(info "{free}");
@ -371,7 +371,7 @@ impl Context {
pub(crate) fn structural_supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
log!(info "structural_supertype_of:\nlhs: {lhs}\nrhs: {rhs}");
match (lhs, rhs) {
(Subr(ls), Subr(rs)) if ls.kind.same_kind_as(&rs.kind) => {
(Subr(ls), Subr(rs)) if ls.kind == rs.kind => {
let kw_check = || {
for lpt in ls.default_params.iter() {
if let Some(rpt) = rs
@ -388,9 +388,6 @@ impl Context {
}
true
};
if ls.kind.self_t().is_some() {
todo!("method type is not supported yet")
}
// () -> Never <: () -> Int <: () -> Object
// (Object) -> Int <: (Int) -> Int <: (Never) -> Int
ls.non_default_params.len() == rs.non_default_params.len()
@ -405,24 +402,20 @@ impl Context {
&& kw_check()
// contravariant
}
// RefMut, OptionMut are invariant
(Ref(lhs), Ref(rhs)) => self.supertype_of(lhs, rhs),
// ?T(<: Nat) !:> ?U(:> Int)
// ?T(<: Nat) :> ?U(<: Int) (?U can be smaller than ?T)
(FreeVar(lfv), FreeVar(rfv)) => {
match (lfv.crack_bound_types(), rfv.crack_bound_types()) {
(Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub),
_ => {
if lfv.is_linked() {
self.supertype_of(&lfv.crack(), rhs)
} else if rfv.is_linked() {
self.supertype_of(lhs, &rfv.crack())
} else {
false
}
(FreeVar(lfv), FreeVar(rfv)) => match (lfv.get_bound_types(), rfv.get_bound_types()) {
(Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub),
_ => {
if lfv.is_linked() {
self.supertype_of(&lfv.crack(), rhs)
} else if rfv.is_linked() {
self.supertype_of(lhs, &rfv.crack())
} else {
false
}
}
}
},
// true if it can be a supertype, false if it cannot (due to type constraints)
// No type constraints are imposed here, as subsequent type decisions are made according to the possibilities
(FreeVar(lfv), rhs) => {
@ -496,7 +489,18 @@ impl Context {
}
true
}
// (MonoQuantVar(_), _) | (_, MonoQuantVar(_)) => true,
(Type::Record(lhs), Type::Record(rhs)) => {
for (k, l) in lhs.iter() {
if let Some(r) = rhs.get(k) {
if !self.supertype_of(l, r) {
return false;
}
} else {
return false;
}
}
true
}
// REVIEW: maybe this is incomplete
// ({I: Int | I >= 0} :> {N: Int | N >= 0}) == true,
// ({I: Int | I >= 0} :> {I: Int | I >= 1}) == true,
@ -571,30 +575,18 @@ impl Context {
}
(_lhs, Not(_, _)) => todo!(),
(Not(_, _), _rhs) => todo!(),
// RefMut are invariant
(Ref(l), Ref(r)) => self.supertype_of(l, r),
// TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ
// REVIEW: RefMut is invariant, maybe
(Ref(lhs), rhs) | (RefMut(lhs), rhs) => self.supertype_of(lhs, rhs),
(Ref(l), r) => self.supertype_of(l, r),
(RefMut { before: l, .. }, r) => self.supertype_of(l, r),
(
PolyClass {
Poly {
name: ln,
params: lparams,
},
PolyClass {
name: rn,
params: rparams,
},
) => {
if ln != rn || lparams.len() != rparams.len() {
return false;
}
self.poly_supertype_of(lhs, lparams, rparams)
}
(
PolyTrait {
name: ln,
params: lparams,
},
PolyTrait {
Poly {
name: rn,
params: rparams,
},
@ -619,15 +611,18 @@ impl Context {
pub(crate) fn cyclic_supertype_of(&self, lhs: &FreeTyVar, rhs: &Type) -> bool {
// if `rhs` is {S: Str | ... }, `defined_rhs` will be Str
let (defined_rhs, _) = self.rec_get_nominal_type_ctx(rhs).unwrap();
let super_traits = self.rec_get_nominal_super_trait_ctxs(rhs);
for (sup_trait, _) in super_traits.into_iter() {
if self.sup_conforms(lhs, defined_rhs, sup_trait) {
return true;
if let Some(super_traits) = self.rec_get_nominal_super_trait_ctxs(rhs) {
for (sup_trait, _) in super_traits {
if self.sup_conforms(lhs, defined_rhs, sup_trait) {
return true;
}
}
}
for (sup_class, _) in self.rec_get_nominal_super_class_ctxs(rhs) {
if self.cyclic_supertype_of(lhs, sup_class) {
return true;
if let Some(sup_classes) = self.rec_get_nominal_super_class_ctxs(rhs) {
for (sup_class, _) in sup_classes {
if self.cyclic_supertype_of(lhs, sup_class) {
return true;
}
}
}
false
@ -666,7 +661,7 @@ impl Context {
self.structural_supertype_of(rhs, lhs)
}
pub(crate) fn structural_same_type_of(&self, lhs: &Type, rhs: &Type) -> bool {
pub(crate) fn _structural_same_type_of(&self, lhs: &Type, rhs: &Type) -> bool {
self.structural_supertype_of(lhs, rhs) && self.structural_subtype_of(lhs, rhs)
}
@ -676,7 +671,7 @@ impl Context {
l.try_cmp(r).map(Into::into),
// TODO: 型を見て判断する
(TyParam::BinOp{ op, lhs, rhs }, r) => {
if let Ok(l) = self.eval.eval_bin_tp(*op, lhs, rhs) {
if let Ok(l) = self.eval_bin_tp(*op, lhs, rhs) {
self.rec_try_cmp(&l, r)
} else { Some(Any) }
},
@ -690,8 +685,8 @@ impl Context {
l @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)),
r @ (TyParam::FreeVar(_) | TyParam::Erased(_) | TyParam::MonoQVar(_)),
) /* if v.is_unbound() */ => {
let l_t = self.eval.get_tp_t(l, self).unwrap();
let r_t = self.eval.get_tp_t(r, self).unwrap();
let l_t = self.get_tp_t(l).unwrap();
let r_t = self.get_tp_t(r).unwrap();
if self.rec_supertype_of(&l_t, &r_t) || self.rec_subtype_of(&l_t, &r_t) {
Some(Any)
} else { Some(NotEqual) }
@ -702,7 +697,7 @@ impl Context {
// try_cmp((n: 2.._), 1) -> Some(Greater)
// try_cmp((n: -1.._), 1) -> Some(Any)
(l @ (TyParam::Erased(_) | TyParam::FreeVar(_) | TyParam::MonoQVar(_)), p) => {
let t = self.eval.get_tp_t(l, self).unwrap();
let t = self.get_tp_t(l).unwrap();
let inf = self.rec_inf(&t);
let sup = self.rec_sup(&t);
if let (Some(inf), Some(sup)) = (inf, sup) {
@ -772,7 +767,7 @@ impl Context {
}
}
/// 和集合(A or B)を返す
/// returns union of two types (A or B)
pub(crate) fn rec_union(&self, lhs: &Type, rhs: &Type) -> Type {
match (
self.rec_supertype_of(lhs, rhs),
@ -814,6 +809,28 @@ impl Context {
}
}
/// returns intersection of two types (A and B)
pub(crate) fn rec_intersection(&self, lhs: &Type, rhs: &Type) -> Type {
match (
self.rec_supertype_of(lhs, rhs),
self.rec_subtype_of(lhs, rhs),
) {
(true, true) => return lhs.clone(), // lhs = rhs
(true, false) => return rhs.clone(), // lhs :> rhs
(false, true) => return lhs.clone(),
(false, false) => {}
}
match (lhs, rhs) {
/*(Type::FreeVar(_), _) | (_, Type::FreeVar(_)) => {
todo!()
}*/
// {.i = Int} and {.s = Str} == {.i = Int; .s = Str}
(Type::Record(l), Type::Record(r)) => Type::Record(l.clone().concat(r.clone())),
(l, r) if self.is_trait(l) && self.is_trait(r) => and(l.clone(), r.clone()),
(_l, _r) => Type::Never,
}
}
/// see doc/LANG/compiler/refinement_subtyping.md
/// ```python
/// assert is_super_pred({I >= 0}, {I == 0})
@ -888,7 +905,7 @@ impl Context {
#[inline]
fn type_of(&self, p: &TyParam) -> Type {
self.eval.get_tp_t(p, self).unwrap()
self.get_tp_t(p).unwrap()
}
// sup/inf({±∞}) = ±∞ではあるが、Inf/NegInfにはOrdを実装しない

View file

@ -3,21 +3,19 @@ use std::mem;
use erg_common::dict::Dict;
use erg_common::rccell::RcCell;
use erg_common::set::Set;
use erg_common::traits::Stream;
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Field;
use erg_common::{fn_name, set};
use erg_common::{dict, fn_name, option_enum_unwrap, set};
use erg_common::{RcArray, Str};
use OpKind::*;
use erg_parser::ast::*;
use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{
enum_t, mono_proj, poly_class, poly_trait, ref_, ref_mut, refinement, subr_t,
};
use erg_type::constructors::{enum_t, mono, mono_proj, poly, ref_, ref_mut, refinement, subr_t};
use erg_type::typaram::{OpKind, TyParam};
use erg_type::value::ValueObj;
use erg_type::{Predicate, SubrKind, TyBound, Type};
use erg_type::{HasType, Predicate, TyBound, Type, ValueArgs};
use crate::context::instantiate::TyVarContext;
use crate::context::Context;
@ -41,7 +39,7 @@ pub fn type_from_token_kind(kind: TokenKind) -> Type {
}
}
fn try_get_op_kind_from_token(kind: TokenKind) -> Result<OpKind, ()> {
fn try_get_op_kind_from_token(kind: TokenKind) -> EvalResult<OpKind> {
match kind {
TokenKind::Plus => Ok(OpKind::Add),
TokenKind::Minus => Ok(OpKind::Sub),
@ -63,7 +61,7 @@ fn try_get_op_kind_from_token(kind: TokenKind) -> Result<OpKind, ()> {
TokenKind::Shl => Ok(OpKind::Shl),
TokenKind::Shr => Ok(OpKind::Shr),
TokenKind::Mutate => Ok(OpKind::Mutate),
_other => Err(()),
_other => todo!("{_other}"),
}
}
@ -165,150 +163,243 @@ impl SubstContext {
}
}
#[derive(Debug, Default)]
pub struct Evaluator {}
impl Evaluator {
#[inline]
pub fn new() -> Self {
Self::default()
}
fn eval_const_acc(&self, _acc: &Accessor, ctx: &Context) -> Option<ValueObj> {
match _acc {
Accessor::Local(local) => {
if let Some(val) = ctx.rec_get_const_obj(local.inspect()) {
Some(val.clone())
impl Context {
fn eval_const_acc(&self, acc: &Accessor) -> EvalResult<ValueObj> {
match acc {
Accessor::Ident(ident) => {
if let Some(val) = self.rec_get_const_obj(ident.inspect()) {
Ok(val.clone())
} else {
None
if ident.is_const() {
Err(EvalError::no_var_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
} else {
Err(EvalError::not_const_expr(
line!() as usize,
acc.loc(),
self.caused_by(),
))
}
}
}
Accessor::Attr(attr) => {
let _obj = self.eval_const_expr(&attr.obj, ctx)?;
todo!()
let obj = self.eval_const_expr(&attr.obj, None)?;
self.eval_attr(obj, &attr.ident)
}
_ => todo!(),
}
}
fn eval_const_bin(&self, bin: &BinOp) -> Option<ValueObj> {
match (bin.args[0].as_ref(), bin.args[1].as_ref()) {
(Expr::Lit(l), Expr::Lit(r)) => {
let op = try_get_op_kind_from_token(bin.op.kind).ok()?;
self.eval_bin_lit(op, eval_lit(l), eval_lit(r)).ok()
fn eval_attr(&self, obj: ValueObj, ident: &Identifier) -> EvalResult<ValueObj> {
match obj.try_get_attr(&Field::from(ident)) {
Some(val) => {
return Ok(val);
}
_ => None,
_ => {}
}
}
fn eval_const_unary(&self, unary: &UnaryOp) -> Option<ValueObj> {
match unary.args[0].as_ref() {
Expr::Lit(lit) => {
let op = try_get_op_kind_from_token(unary.op.kind).ok()?;
self.eval_unary_lit(op, eval_lit(lit)).ok()
}
_ => None,
}
}
// TODO: kw args
fn eval_args(&self, _args: &Args) -> Option<Vec<ValueObj>> {
todo!()
}
fn eval_const_call(&self, call: &Call, ctx: &Context) -> Option<ValueObj> {
if let Expr::Accessor(acc) = call.obj.as_ref() {
match acc {
Accessor::Local(name) if name.is_const() => {
if let Some(ValueObj::Subr(subr)) = ctx.rec_get_const_obj(&name.inspect()) {
let args = self.eval_args(&call.args)?;
Some(subr.call(args))
} else {
None
match &obj {
ValueObj::Type(t) => {
if let Some(sups) = self.rec_get_nominal_super_type_ctxs(t.typ()) {
for (_, ctx) in sups {
if let Some(val) = ctx.consts.get(ident.inspect()) {
return Ok(val.clone());
}
for (_, methods) in ctx.methods_list.iter() {
if let Some(v) = methods.consts.get(ident.inspect()) {
return Ok(v.clone());
}
}
}
}
Accessor::Local(_) => None,
}
_ => {}
}
Err(EvalError::no_attr_error(
line!() as usize,
ident.loc(),
self.caused_by(),
&obj.t(),
ident.inspect(),
None,
))
}
fn eval_const_bin(&self, bin: &BinOp) -> EvalResult<ValueObj> {
let lhs = self.eval_const_expr(&bin.args[0], None)?;
let rhs = self.eval_const_expr(&bin.args[1], None)?;
let op = try_get_op_kind_from_token(bin.op.kind)?;
self.eval_bin(op, lhs, rhs)
}
fn eval_const_unary(&self, unary: &UnaryOp) -> EvalResult<ValueObj> {
let val = self.eval_const_expr(&unary.args[0], None)?;
let op = try_get_op_kind_from_token(unary.op.kind)?;
self.eval_unary(op, val)
}
fn eval_args(&self, args: &Args, __name__: Option<&Str>) -> EvalResult<ValueArgs> {
let mut evaluated_pos_args = vec![];
for arg in args.pos_args().iter() {
let val = self.eval_const_expr(&arg.expr, __name__)?;
evaluated_pos_args.push(val);
}
let mut evaluated_kw_args = dict! {};
for arg in args.kw_args().iter() {
let val = self.eval_const_expr(&arg.expr, __name__)?;
evaluated_kw_args.insert(arg.keyword.inspect().clone(), val);
}
Ok(ValueArgs::new(evaluated_pos_args, evaluated_kw_args))
}
fn eval_const_call(&self, call: &Call, __name__: Option<&Str>) -> EvalResult<ValueObj> {
if let Expr::Accessor(acc) = call.obj.as_ref() {
match acc {
Accessor::Ident(ident) => {
let obj =
self.rec_get_const_obj(&ident.inspect())
.ok_or(EvalError::no_var_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))?;
let subr = option_enum_unwrap!(obj, ValueObj::Subr)
.ok_or(EvalError::type_mismatch_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
&mono("Subroutine"),
&obj.t(),
None,
))?
.clone();
let args = self.eval_args(&call.args, __name__)?;
Ok(subr.call(args, __name__.map(|n| n.clone())))
}
Accessor::Attr(_attr) => todo!(),
Accessor::TupleAttr(_attr) => todo!(),
Accessor::Public(_name) => todo!(),
Accessor::Subscr(_subscr) => todo!(),
}
} else {
None
}
}
fn eval_const_def(&self, def: &Def) -> Option<ValueObj> {
if def.is_const() {
todo!()
}
None
}
fn eval_const_array(&self, arr: &Array, ctx: &Context) -> Option<ValueObj> {
fn eval_const_def(&mut self, def: &Def) -> EvalResult<ValueObj> {
if def.is_const() {
let __name__ = def.sig.ident().map(|i| i.inspect()).unwrap();
let obj = self.eval_const_block(&def.body.block, Some(__name__))?;
self.register_gen_const(def.sig.ident().unwrap(), obj);
Ok(ValueObj::None)
} else {
Err(EvalError::not_const_expr(
line!() as usize,
def.body.block.loc(),
self.caused_by(),
))
}
}
fn eval_const_array(&self, arr: &Array) -> EvalResult<ValueObj> {
let mut elems = vec![];
match arr {
Array::Normal(arr) => {
for elem in arr.elems.pos_args().iter() {
if let Some(elem) = self.eval_const_expr(&elem.expr, ctx) {
elems.push(elem);
} else {
return None;
}
let elem = self.eval_const_expr(&elem.expr, None)?;
elems.push(elem);
}
}
_ => {
return None;
todo!()
}
}
Some(ValueObj::Array(RcArray::from(elems)))
Ok(ValueObj::Array(RcArray::from(elems)))
}
fn eval_const_record(&self, record: &NormalRecord, ctx: &Context) -> Option<ValueObj> {
fn eval_const_record(&self, record: &Record) -> EvalResult<ValueObj> {
match record {
Record::Normal(rec) => self.eval_const_normal_record(rec),
Record::Shortened(_rec) => unreachable!(), // should be desugared
}
}
fn eval_const_normal_record(&self, record: &NormalRecord) -> EvalResult<ValueObj> {
let mut attrs = vec![];
// HACK: should avoid cloning
let mut record_ctx = Context::instant(Str::ever("<unnamed record>"), 2, self.clone());
for attr in record.attrs.iter() {
if let Some(elem) = self.eval_const_block(&attr.body.block, ctx) {
let ident = match &attr.sig {
Signature::Var(var) => match &var.pat {
VarPattern::Ident(ident) => {
Field::new(ident.vis(), ident.inspect().clone())
}
_ => todo!(),
},
let name = attr.sig.ident().map(|i| i.inspect());
let elem = record_ctx.eval_const_block(&attr.body.block, name)?;
let ident = match &attr.sig {
Signature::Var(var) => match &var.pat {
VarPattern::Ident(ident) => Field::new(ident.vis(), ident.inspect().clone()),
_ => todo!(),
};
attrs.push((ident, elem));
} else {
return None;
}
},
_ => todo!(),
};
attrs.push((ident, elem));
}
Some(ValueObj::Record(attrs.into_iter().collect()))
Ok(ValueObj::Record(attrs.into_iter().collect()))
}
// ConstExprを評価するのではなく、コンパイル時関数の式(AST上ではただのExpr)を評価する
// コンパイル時評価できないならNoneを返す
pub(crate) fn eval_const_expr(&self, expr: &Expr, ctx: &Context) -> Option<ValueObj> {
pub(crate) fn eval_const_expr(
&self,
expr: &Expr,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr {
Expr::Lit(lit) => Some(eval_lit(lit)),
Expr::Accessor(acc) => self.eval_const_acc(acc, ctx),
Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
Expr::Call(call) => self.eval_const_call(call, ctx),
Expr::Def(def) => self.eval_const_def(def),
Expr::Array(arr) => self.eval_const_array(arr, ctx),
Expr::Record(rec) => self.eval_const_record(rec, ctx),
Expr::Call(call) => self.eval_const_call(call, __name__),
Expr::Array(arr) => self.eval_const_array(arr),
Expr::Record(rec) => self.eval_const_record(rec),
Expr::Lambda(lambda) => todo!("{lambda}"),
other => todo!("{other}"),
}
}
pub(crate) fn eval_const_block(&self, block: &Block, ctx: &Context) -> Option<ValueObj> {
for chunk in block.iter().rev().skip(1).rev() {
self.eval_const_expr(chunk, ctx)?;
// ConstExprを評価するのではなく、コンパイル時関数の式(AST上ではただのExpr)を評価する
// コンパイル時評価できないならNoneを返す
pub(crate) fn eval_const_chunk(
&mut self,
expr: &Expr,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
Expr::Call(call) => self.eval_const_call(call, __name__),
Expr::Def(def) => self.eval_const_def(def),
Expr::Array(arr) => self.eval_const_array(arr),
Expr::Record(rec) => self.eval_const_record(rec),
Expr::Lambda(lambda) => todo!("{lambda}"),
other => todo!("{other}"),
}
self.eval_const_expr(block.last().unwrap(), ctx)
}
fn eval_bin_lit(&self, op: OpKind, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> {
pub(crate) fn eval_const_block(
&mut self,
block: &Block,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
for chunk in block.iter().rev().skip(1).rev() {
self.eval_const_chunk(chunk, __name__)?;
}
self.eval_const_chunk(block.last().unwrap(), __name__)
}
fn eval_bin(&self, op: OpKind, lhs: ValueObj, rhs: ValueObj) -> EvalResult<ValueObj> {
match op {
Add => lhs
.try_add(rhs)
@ -346,10 +437,10 @@ impl Evaluator {
) -> EvalResult<TyParam> {
match (lhs, rhs) {
(TyParam::Value(ValueObj::Mut(lhs)), TyParam::Value(rhs)) => self
.eval_bin_lit(op, lhs.borrow().clone(), rhs.clone())
.eval_bin(op, lhs.borrow().clone(), rhs.clone())
.map(|v| TyParam::Value(ValueObj::Mut(RcCell::new(v)))),
(TyParam::Value(lhs), TyParam::Value(rhs)) => self
.eval_bin_lit(op, lhs.clone(), rhs.clone())
.eval_bin(op, lhs.clone(), rhs.clone())
.map(TyParam::value),
(TyParam::FreeVar(fv), r) => {
if fv.is_linked() {
@ -370,7 +461,7 @@ impl Evaluator {
}
}
fn eval_unary_lit(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> {
fn eval_unary(&self, op: OpKind, val: ValueObj) -> EvalResult<ValueObj> {
match op {
Pos => todo!(),
Neg => todo!(),
@ -382,9 +473,7 @@ impl Evaluator {
fn eval_unary_tp(&self, op: OpKind, val: &TyParam) -> EvalResult<TyParam> {
match val {
TyParam::Value(c) => self
.eval_unary_lit(op, c.clone())
.map(|v| TyParam::Value(v)),
TyParam::Value(c) => self.eval_unary(op, c.clone()).map(|v| TyParam::Value(v)),
TyParam::FreeVar(fv) if fv.is_linked() => self.eval_unary_tp(op, &*fv.crack()),
e @ TyParam::Erased(_) => Ok(e.clone()),
other => todo!("{op} {other}"),
@ -396,10 +485,10 @@ impl Evaluator {
}
/// 量化変数などはそのまま返す
pub(crate) fn eval_tp(&self, p: &TyParam, ctx: &Context) -> EvalResult<TyParam> {
pub(crate) fn eval_tp(&self, p: &TyParam) -> EvalResult<TyParam> {
match p {
TyParam::FreeVar(fv) if fv.is_linked() => self.eval_tp(&fv.crack(), ctx),
TyParam::Mono(name) => ctx
TyParam::FreeVar(fv) if fv.is_linked() => self.eval_tp(&fv.crack()),
TyParam::Mono(name) => self
.rec_get_const_obj(name)
.map(|v| TyParam::value(v.clone()))
.ok_or_else(|| EvalError::unreachable(fn_name!(), line!())),
@ -415,45 +504,23 @@ impl Evaluator {
}
}
pub(crate) fn eval_t_params(
&self,
substituted: Type,
ctx: &Context,
level: usize,
) -> EvalResult<Type> {
pub(crate) fn eval_t_params(&self, substituted: Type, level: usize) -> EvalResult<Type> {
match substituted {
Type::FreeVar(fv) if fv.is_linked() => {
self.eval_t_params(fv.crack().clone(), ctx, level)
}
Type::FreeVar(fv) if fv.is_linked() => self.eval_t_params(fv.crack().clone(), level),
Type::Subr(mut subr) => {
let kind = match subr.kind {
SubrKind::FuncMethod(self_t) => {
SubrKind::fn_met(self.eval_t_params(*self_t, ctx, level)?)
}
SubrKind::ProcMethod { before, after } => {
let before = self.eval_t_params(*before, ctx, level)?;
if let Some(after) = after {
let after = self.eval_t_params(*after, ctx, level)?;
SubrKind::pr_met(before, Some(after))
} else {
SubrKind::pr_met(before, None)
}
}
other => other,
};
for pt in subr.non_default_params.iter_mut() {
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), ctx, level)?;
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level)?;
}
if let Some(var_args) = subr.var_params.as_mut() {
*var_args.typ_mut() =
self.eval_t_params(mem::take(var_args.typ_mut()), ctx, level)?;
self.eval_t_params(mem::take(var_args.typ_mut()), level)?;
}
for pt in subr.default_params.iter_mut() {
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), ctx, level)?;
*pt.typ_mut() = self.eval_t_params(mem::take(pt.typ_mut()), level)?;
}
let return_t = self.eval_t_params(*subr.return_t, ctx, level)?;
let return_t = self.eval_t_params(*subr.return_t, level)?;
Ok(subr_t(
kind,
subr.kind,
subr.non_default_params,
subr.var_params.map(|v| *v),
subr.default_params,
@ -463,7 +530,7 @@ impl Evaluator {
Type::Refinement(refine) => {
let mut preds = Set::with_capacity(refine.preds.len());
for pred in refine.preds.into_iter() {
preds.insert(self.eval_pred(pred, ctx)?);
preds.insert(self.eval_pred(pred)?);
}
Ok(refinement(refine.var, *refine.t, preds))
}
@ -472,144 +539,137 @@ impl Evaluator {
// Currently Erg does not allow projection-types to be evaluated with type variables included.
// All type variables will be dereferenced or fail.
let lhs = match *lhs {
Type::FreeVar(fv) if fv.is_linked() => {
self.eval_t_params(mono_proj(fv.crack().clone(), rhs.clone()), level)?
}
Type::FreeVar(fv) if fv.is_unbound() => {
fv.lift();
ctx.deref_tyvar(Type::FreeVar(fv))?
self.deref_tyvar(Type::FreeVar(fv))?
}
_ => *lhs,
other => other,
};
for (_ty, ty_ctx) in ctx.rec_get_nominal_super_type_ctxs(&lhs) {
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &ctx.name) {
for (_ty, ty_ctx) in self
.rec_get_nominal_super_type_ctxs(&lhs)
.ok_or_else(|| todo!("{lhs}"))?
{
if let Ok(obj) = ty_ctx.get_const_local(&Token::symbol(&rhs), &self.name) {
if let ValueObj::Type(quant_t) = obj {
let subst_ctx = SubstContext::new(&lhs, ty_ctx);
let t = subst_ctx.substitute(*quant_t, ty_ctx, level, ctx)?;
let t = self.eval_t_params(t, ctx, level)?;
let t =
subst_ctx.substitute(quant_t.typ().clone(), ty_ctx, level, self)?;
let t = self.eval_t_params(t, level)?;
return Ok(t);
} else {
todo!()
}
}
}
if let Some(outer) = &ctx.outer {
self.eval_t_params(mono_proj(lhs, rhs), outer, level)
if let Some(outer) = self.outer.as_ref() {
outer.eval_t_params(mono_proj(lhs, rhs), level)
} else {
todo!(
"{lhs}.{rhs} not found in [{}]",
erg_common::fmt_iter(
ctx.rec_get_nominal_super_type_ctxs(&lhs)
self.rec_get_nominal_super_type_ctxs(&lhs)
.unwrap()
.map(|(_, ctx)| &ctx.name)
)
)
}
}
Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, ctx, level)?)),
Type::RefMut(l) => Ok(ref_mut(self.eval_t_params(*l, ctx, level)?)),
Type::PolyClass { name, mut params } => {
for p in params.iter_mut() {
*p = self.eval_tp(&mem::take(p), ctx)?;
}
Ok(poly_class(name, params))
Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level)?)),
Type::RefMut { before, after } => {
let before = self.eval_t_params(*before, level)?;
let after = if let Some(after) = after {
Some(self.eval_t_params(*after, level)?)
} else {
None
};
Ok(ref_mut(before, after))
}
Type::PolyTrait { name, mut params } => {
Type::Poly { name, mut params } => {
for p in params.iter_mut() {
*p = self.eval_tp(&mem::take(p), ctx)?;
*p = self.eval_tp(&mem::take(p))?;
}
Ok(poly_trait(name, params))
Ok(poly(name, params))
}
other if other.is_monomorphic() => Ok(other),
other => todo!("{other}"),
}
}
pub(crate) fn _eval_bound(
&self,
bound: TyBound,
ctx: &Context,
level: usize,
) -> EvalResult<TyBound> {
pub(crate) fn _eval_bound(&self, bound: TyBound, level: usize) -> EvalResult<TyBound> {
match bound {
TyBound::Sandwiched { sub, mid, sup } => {
let sub = self.eval_t_params(sub, ctx, level)?;
let mid = self.eval_t_params(mid, ctx, level)?;
let sup = self.eval_t_params(sup, ctx, level)?;
let sub = self.eval_t_params(sub, level)?;
let mid = self.eval_t_params(mid, level)?;
let sup = self.eval_t_params(sup, level)?;
Ok(TyBound::sandwiched(sub, mid, sup))
}
TyBound::Instance { name: inst, t } => {
Ok(TyBound::instance(inst, self.eval_t_params(t, ctx, level)?))
Ok(TyBound::instance(inst, self.eval_t_params(t, level)?))
}
}
}
pub(crate) fn eval_pred(&self, p: Predicate, ctx: &Context) -> EvalResult<Predicate> {
pub(crate) fn eval_pred(&self, p: Predicate) -> EvalResult<Predicate> {
match p {
Predicate::Value(_) | Predicate::Const(_) => Ok(p),
Predicate::Equal { lhs, rhs } => Ok(Predicate::eq(lhs, self.eval_tp(&rhs, ctx)?)),
Predicate::NotEqual { lhs, rhs } => Ok(Predicate::ne(lhs, self.eval_tp(&rhs, ctx)?)),
Predicate::LessEqual { lhs, rhs } => Ok(Predicate::le(lhs, self.eval_tp(&rhs, ctx)?)),
Predicate::GreaterEqual { lhs, rhs } => {
Ok(Predicate::ge(lhs, self.eval_tp(&rhs, ctx)?))
}
Predicate::And(l, r) => Ok(Predicate::and(
self.eval_pred(*l, ctx)?,
self.eval_pred(*r, ctx)?,
)),
Predicate::Or(l, r) => Ok(Predicate::or(
self.eval_pred(*l, ctx)?,
self.eval_pred(*r, ctx)?,
)),
Predicate::Not(l, r) => Ok(Predicate::not(
self.eval_pred(*l, ctx)?,
self.eval_pred(*r, ctx)?,
)),
Predicate::Equal { lhs, rhs } => Ok(Predicate::eq(lhs, self.eval_tp(&rhs)?)),
Predicate::NotEqual { lhs, rhs } => Ok(Predicate::ne(lhs, self.eval_tp(&rhs)?)),
Predicate::LessEqual { lhs, rhs } => Ok(Predicate::le(lhs, self.eval_tp(&rhs)?)),
Predicate::GreaterEqual { lhs, rhs } => Ok(Predicate::ge(lhs, self.eval_tp(&rhs)?)),
Predicate::And(l, r) => Ok(Predicate::and(self.eval_pred(*l)?, self.eval_pred(*r)?)),
Predicate::Or(l, r) => Ok(Predicate::or(self.eval_pred(*l)?, self.eval_pred(*r)?)),
Predicate::Not(l, r) => Ok(Predicate::not(self.eval_pred(*l)?, self.eval_pred(*r)?)),
}
}
pub(crate) fn get_tp_t(&self, p: &TyParam, ctx: &Context) -> EvalResult<Type> {
let p = self.eval_tp(p, ctx)?;
pub(crate) fn get_tp_t(&self, p: &TyParam) -> EvalResult<Type> {
let p = self.eval_tp(p)?;
match p {
TyParam::Value(ValueObj::Mut(v)) => Ok(v.borrow().class().mutate()),
TyParam::Value(v) => Ok(enum_t(set![v])),
TyParam::Erased(t) => Ok((*t).clone()),
TyParam::FreeVar(fv) => {
if let Some(t) = fv.type_of() {
if let Some(t) = fv.get_type() {
Ok(t)
} else {
todo!()
}
}
// TODO: Class, Trait
TyParam::Type(_) => Ok(Type::Type),
TyParam::Mono(name) => ctx
.consts
.get(&name)
TyParam::Mono(name) => self
.rec_get_const_obj(&name)
.map(|v| enum_t(set![v.clone()]))
.ok_or_else(|| EvalError::unreachable(fn_name!(), line!())),
TyParam::MonoQVar(name) => {
panic!("Not instantiated type variable: {name}")
}
TyParam::UnaryOp { op, val } => match op {
OpKind::Mutate => Ok(self.get_tp_t(&val, ctx)?.mutate()),
OpKind::Mutate => Ok(self.get_tp_t(&val)?.mutate()),
_ => todo!(),
},
other => todo!("{other}"),
}
}
pub(crate) fn _get_tp_class(&self, p: &TyParam, ctx: &Context) -> EvalResult<Type> {
let p = self.eval_tp(p, ctx)?;
pub(crate) fn _get_tp_class(&self, p: &TyParam) -> EvalResult<Type> {
let p = self.eval_tp(p)?;
match p {
TyParam::Value(v) => Ok(v.class()),
TyParam::Erased(t) => Ok((*t).clone()),
TyParam::FreeVar(fv) => {
if let Some(t) = fv.type_of() {
if let Some(t) = fv.get_type() {
Ok(t)
} else {
todo!()
}
}
TyParam::Type(_) => Ok(Type::Type),
TyParam::Mono(name) => ctx
.consts
.get(&name)
TyParam::Mono(name) => self
.rec_get_const_obj(&name)
.map(|v| v.class())
.ok_or_else(|| EvalError::unreachable(fn_name!(), line!())),
other => todo!("{other}"),
@ -617,7 +677,7 @@ impl Evaluator {
}
/// NOTE: lとrが型の場合はContextの方で判定する
pub(crate) fn shallow_eq_tp(&self, lhs: &TyParam, rhs: &TyParam, ctx: &Context) -> bool {
pub(crate) fn shallow_eq_tp(&self, lhs: &TyParam, rhs: &TyParam) -> bool {
match (lhs, rhs) {
(TyParam::Type(l), TyParam::Type(r)) => l == r,
(TyParam::Value(l), TyParam::Value(r)) => l == r,
@ -626,7 +686,9 @@ impl Evaluator {
(TyParam::Mono(l), TyParam::Mono(r)) => {
if l == r {
true
} else if let (Some(l), Some(r)) = (ctx.consts.get(l), ctx.consts.get(r)) {
} else if let (Some(l), Some(r)) =
(self.rec_get_const_obj(l), self.rec_get_const_obj(r))
{
l == r
} else {
// lとrが型の場合は...
@ -637,7 +699,7 @@ impl Evaluator {
(TyParam::UnaryOp { .. }, TyParam::UnaryOp { .. }) => todo!(),
(TyParam::App { .. }, TyParam::App { .. }) => todo!(),
(TyParam::Mono(m), TyParam::Value(l)) | (TyParam::Value(l), TyParam::Mono(m)) => {
if let Some(o) = ctx.consts.get(m) {
if let Some(o) = self.rec_get_const_obj(m) {
o == l
} else {
true

View file

@ -10,7 +10,7 @@ impl Context {
if fv.is_linked() {
fv.crack().clone()
} else {
let (_sub, sup) = fv.crack_bound_types().unwrap();
let (_sub, sup) = fv.get_bound_types().unwrap();
sup
}
} else {

View file

@ -0,0 +1,66 @@
use std::mem;
use erg_common::Str;
use erg_type::constructors::{and, mono};
use erg_type::value::{TypeKind, TypeObj, ValueObj};
use erg_type::Type;
use erg_type::ValueArgs;
fn value_obj_to_t(value: ValueObj) -> TypeObj {
match value {
ValueObj::Type(t) => t,
ValueObj::Record(rec) => TypeObj::Builtin(Type::Record(
rec.into_iter()
.map(|(k, v)| (k, value_obj_to_t(v).typ().clone()))
.collect(),
)),
other => todo!("{other}"),
}
}
/// Requirement: Type, Impl := Type -> ClassType
pub fn class_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
let require = args.remove_left_or_key("Requirement").unwrap();
let require = value_obj_to_t(require);
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| value_obj_to_t(v));
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
ValueObj::gen_t(TypeKind::Class, t, require, impls, None)
}
/// Super: Type, Impl := Type, Additional := Type -> ClassType
pub fn inherit_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
let sup = args.remove_left_or_key("Super").unwrap();
let sup = value_obj_to_t(sup);
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(|v| value_obj_to_t(v));
let additional = args.remove_left_or_key("Additional");
let additional = additional.map(|v| value_obj_to_t(v));
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
ValueObj::gen_t(TypeKind::Subclass, t, sup, impls, additional)
}
/// Class: ClassType -> ClassType (with `InheritableType`)
/// This function is used by the compiler to mark a class as inheritable and does nothing in terms of actual operation.
pub fn inheritable_func(mut args: ValueArgs, __name__: Option<Str>) -> ValueObj {
let class = args.remove_left_or_key("Class").unwrap();
match class {
ValueObj::Type(TypeObj::Generated(mut gen)) => {
if let Some(typ) = &mut gen.impls {
match typ.as_mut() {
TypeObj::Generated(gen) => {
gen.t = and(mem::take(&mut gen.t), mono("InheritableType"));
}
TypeObj::Builtin(t) => {
*t = and(mem::take(t), mono("InheritableType"));
}
}
} else {
gen.impls = Some(Box::new(TypeObj::Builtin(mono("InheritableType"))));
}
ValueObj::Type(TypeObj::Generated(gen))
}
_ => todo!(),
}
}

View file

@ -1,23 +0,0 @@
use erg_common::vis::Visibility;
use erg_type::constructors::func1;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_math_mod() -> Self {
let mut math = Context::module("math".into(), 10);
math.register_impl("pi", Float, Immutable, Public);
math.register_impl("tau", Float, Immutable, Public);
math.register_impl("e", Float, Immutable, Public);
math.register_impl("sin", func1(Float, Float), Immutable, Public);
math.register_impl("cos", func1(Float, Float), Immutable, Public);
math.register_impl("tan", func1(Float, Float), Immutable, Public);
math
}
}

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,7 @@ use Visibility::*;
impl Context {
pub(crate) fn init_py_importlib_mod() -> Self {
let mut importlib = Context::module("importlib".into(), 15);
importlib.register_impl("reload!", proc1(Module, NoneType), Immutable, Public);
importlib.register_builtin_impl("reload!", proc1(Module, NoneType), Immutable, Public);
importlib
}
}

View file

@ -1,7 +1,7 @@
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_type::constructors::{class, pr0_met};
use erg_type::constructors::{mono, pr0_met, ref_};
use erg_type::Type;
use Type::*;
@ -14,13 +14,13 @@ impl Context {
pub(crate) fn init_py_io_mod() -> Self {
let mut io = Context::module("io".into(), 15);
let mut string_io = Context::mono_class(Str::ever("StringIO!"), vec![Obj], vec![], 0);
string_io.register_impl(
string_io.register_builtin_impl(
"getvalue!",
pr0_met(class("StringIO!"), None, Str),
pr0_met(ref_(mono("StringIO!")), Str),
Immutable,
Public,
);
io.register_type(class("StringIO!"), string_io, Const);
io.register_builtin_type(mono("StringIO!"), string_io, Const);
io
}
}

View file

@ -0,0 +1,23 @@
use erg_common::vis::Visibility;
use erg_type::constructors::func1;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_math_mod() -> Self {
let mut math = Context::module("math".into(), 10);
math.register_builtin_impl("pi", Float, Immutable, Public);
math.register_builtin_impl("tau", Float, Immutable, Public);
math.register_builtin_impl("e", Float, Immutable, Public);
math.register_builtin_impl("sin", func1(Float, Float), Immutable, Public);
math.register_builtin_impl("cos", func1(Float, Float), Immutable, Public);
math.register_builtin_impl("tan", func1(Float, Float), Immutable, Public);
math
}
}

View file

@ -0,0 +1,7 @@
pub mod importlib;
pub mod io;
pub mod math;
pub mod random;
pub mod socket;
pub mod sys;
pub mod time;

View file

@ -2,7 +2,7 @@ use erg_common::set;
use erg_common::vis::Visibility;
use erg_type::constructors::{
mono_q, nd_proc, param_t, poly_trait, proc, quant, static_instance, trait_, ty_tp,
mono, mono_q, nd_proc, param_t, poly, proc, quant, static_instance, ty_tp,
};
use erg_type::Type;
use Type::*;
@ -15,13 +15,13 @@ use Visibility::*;
impl Context {
pub(crate) fn init_py_random_mod() -> Self {
let mut random = Context::module("random".into(), 10);
random.register_impl(
random.register_builtin_impl(
"seed!",
proc(
vec![],
None,
vec![
param_t("a", trait_("Num")), // TODO: NoneType, int, float, str, bytes, bytearray
param_t("a", mono("Num")), // TODO: NoneType, int, float, str, bytes, bytearray
param_t("version", Int),
],
NoneType,
@ -29,19 +29,19 @@ impl Context {
Immutable,
Public,
);
random.register_impl(
random.register_builtin_impl(
"randint!",
nd_proc(vec![param_t("a", Int), param_t("b", Int)], None, Int),
Immutable,
Public,
);
let t = nd_proc(
vec![param_t("seq", poly_trait("Seq", vec![ty_tp(mono_q("T"))]))],
vec![param_t("seq", poly("Seq", vec![ty_tp(mono_q("T"))]))],
None,
mono_q("T"),
);
let t = quant(t, set! {static_instance("T", Type)});
random.register_impl("choice!", t, Immutable, Public);
random.register_builtin_impl("choice!", t, Immutable, Public);
random
}
}

View file

@ -1,7 +1,7 @@
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_type::constructors::{class, func, option, param_t};
use erg_type::constructors::{func, mono, option, param_t};
use erg_type::Type;
use Type::*;
@ -14,7 +14,7 @@ impl Context {
pub(crate) fn init_py_socket_mod() -> Self {
let mut socket = Context::module("socket".into(), 15);
let mut sock = Context::mono_class(Str::ever("Socket!"), vec![Obj], vec![], 0);
sock.register_impl(
sock.register_builtin_impl(
"new",
func(
vec![],
@ -25,12 +25,12 @@ impl Context {
param_t("proto", Int),
param_t("fileno", option(Int)),
],
class("Socket!"),
mono("Socket!"),
),
Immutable,
Public,
);
socket.register_type(class("Socket!"), sock, Const);
socket.register_builtin_type(mono("Socket!"), sock, Const);
socket
}
}

View file

@ -0,0 +1,50 @@
use erg_common::vis::Visibility;
use erg_type::constructors::{array, array_mut, func0, func1, mono, proc1};
use erg_type::typaram::TyParam;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_sys_mod() -> Self {
let mut sys = Context::module("sys".into(), 15);
sys.register_builtin_impl("argv", array(Str, TyParam::erased(Nat)), Immutable, Public);
sys.register_builtin_impl("byteorder", Str, Immutable, Public);
sys.register_builtin_impl(
"builtin_module_names",
array(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_builtin_impl("copyright", Str, Immutable, Public);
sys.register_builtin_impl("executable", Str, Immutable, Public);
sys.register_builtin_impl("exit", func1(Int, Never), Immutable, Public);
sys.register_builtin_impl("getdefaultencoding", func0(Str), Immutable, Public);
sys.register_builtin_impl(
"path",
array_mut(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_builtin_impl("platform", Str, Immutable, Public);
sys.register_builtin_impl("prefix", Str, Immutable, Public);
sys.register_builtin_impl("ps1", mono("Str!"), Immutable, Public);
sys.register_builtin_impl("ps2", mono("Str!"), Immutable, Public);
sys.register_builtin_impl(
"setrecursionlimit!",
proc1(Int, NoneType),
Immutable,
Public,
);
sys.register_builtin_impl("stderr", mono("TextIOWrapper!"), Immutable, Public);
sys.register_builtin_impl("stdin", mono("TextIOWrapper!"), Immutable, Public);
sys.register_builtin_impl("stdout", mono("TextIOWrapper!"), Immutable, Public);
sys.register_builtin_impl("version", Str, Immutable, Public);
sys
}
}

View file

@ -12,8 +12,8 @@ use Visibility::*;
impl Context {
pub(crate) fn init_py_time_mod() -> Self {
let mut time = Context::module("time".into(), 15);
time.register_impl("sleep!", proc1(Float, NoneType), Immutable, Public);
time.register_impl("time!", proc0(Float), Immutable, Public);
time.register_builtin_impl("sleep!", proc1(Float, NoneType), Immutable, Public);
time.register_builtin_impl("time!", proc0(Float), Immutable, Public);
time
}
}

View file

@ -1,50 +0,0 @@
use erg_common::vis::Visibility;
use erg_type::constructors::{array, array_mut, class, func0, func1, proc1};
use erg_type::typaram::TyParam;
use erg_type::Type;
use Type::*;
use crate::context::Context;
use crate::varinfo::Mutability;
use Mutability::*;
use Visibility::*;
impl Context {
pub(crate) fn init_py_sys_mod() -> Self {
let mut sys = Context::module("sys".into(), 15);
sys.register_impl("argv", array(Str, TyParam::erased(Nat)), Immutable, Public);
sys.register_impl("byteorder", Str, Immutable, Public);
sys.register_impl(
"builtin_module_names",
array(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_impl("copyright", Str, Immutable, Public);
sys.register_impl("executable", Str, Immutable, Public);
sys.register_impl("exit", func1(Int, Never), Immutable, Public);
sys.register_impl("getdefaultencoding", func0(Str), Immutable, Public);
sys.register_impl(
"path",
array_mut(Str, TyParam::erased(Nat)),
Immutable,
Public,
);
sys.register_impl("platform", Str, Immutable, Public);
sys.register_impl("prefix", Str, Immutable, Public);
sys.register_impl("ps1", class("Str!"), Immutable, Public);
sys.register_impl("ps2", class("Str!"), Immutable, Public);
sys.register_impl(
"setrecursionlimit!",
proc1(Int, NoneType),
Immutable,
Public,
);
sys.register_impl("stderr", class("TextIOWrapper!"), Immutable, Public);
sys.register_impl("stdin", class("TextIOWrapper!"), Immutable, Public);
sys.register_impl("stdout", class("TextIOWrapper!"), Immutable, Public);
sys.register_impl("version", Str, Immutable, Public);
sys
}
}

View file

@ -1,7 +1,7 @@
// (type) getters & validators
use std::option::Option; // conflicting to Type::Option
use erg_common::error::ErrorCore;
use erg_common::error::{ErrorCore, ErrorKind};
use erg_common::levenshtein::levenshtein;
use erg_common::set::Set;
use erg_common::traits::Locational;
@ -11,16 +11,14 @@ use erg_common::{enum_unwrap, fmt_option, fmt_slice, log, set};
use Type::*;
use ast::VarName;
use erg_parser::ast;
use erg_parser::ast::{self, Identifier};
use erg_parser::token::Token;
use erg_type::constructors::{
class, func, mono_proj, poly_class, ref_, ref_mut, refinement, subr_t,
};
use erg_type::constructors::{func, mono, mono_proj, poly, ref_, ref_mut, refinement, subr_t};
use erg_type::free::Constraint;
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{HasType, ParamTy, SubrKind, SubrType, TyBound, Type};
use erg_type::value::{GenTypeObj, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, TyBound, Type};
use crate::context::instantiate::ConstTemplate;
use crate::context::{Context, ContextKind, RegistrationMode, TraitInstance, Variance};
@ -72,6 +70,18 @@ impl Context {
})
.map(|(_, vi)| vi)
})
.or_else(|| {
for (_, methods) in self.methods_list.iter() {
if let Some(vi) = methods.get_current_scope_var(name) {
return Some(vi);
}
}
None
})
}
pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
self.locals.get_key_value(name)
}
fn get_context(
@ -81,17 +91,17 @@ impl Context {
namespace: &Str,
) -> TyCheckResult<&Context> {
match obj {
hir::Expr::Accessor(hir::Accessor::Local(name)) => {
hir::Expr::Accessor(hir::Accessor::Ident(ident)) => {
if kind == Some(ContextKind::Module) {
if let Some(ctx) = self.rec_get_mod(name.inspect()) {
if let Some(ctx) = self.rec_get_mod(ident.inspect()) {
Ok(ctx)
} else {
Err(TyCheckError::no_var_error(
line!() as usize,
obj.loc(),
namespace.clone(),
name.inspect(),
self.get_similar_name(name.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
}
} else {
@ -119,9 +129,9 @@ impl Context {
pos_arg.loc(),
self.caused_by(),
"match",
&class("LambdaFunc"),
&mono("LambdaFunc"),
t,
self.get_type_mismatch_hint(&class("LambdaFunc"), t),
self.get_type_mismatch_hint(&mono("LambdaFunc"), t),
));
}
}
@ -184,37 +194,26 @@ impl Context {
if let Some(ctx) = self.rec_get_mod(name.inspect()) {
return Some(ctx.name.clone());
}
if let Some((_, ctx)) = self.rec_get_type(name.inspect()) {
return Some(ctx.name.clone());
}
None
}
pub(crate) fn rec_get_var_t(
&self,
name: &Token,
vis: Visibility,
namespace: &Str,
) -> TyCheckResult<Type> {
if let Some(vi) = self.get_current_scope_var(&name.inspect()[..]) {
if vi.vis == vis {
Ok(vi.t())
} else {
Err(TyCheckError::visibility_error(
line!() as usize,
name.loc(),
namespace.clone(),
name.inspect(),
vi.vis,
))
}
pub(crate) fn rec_get_var_t(&self, ident: &Identifier, namespace: &Str) -> TyCheckResult<Type> {
if let Some(vi) = self.get_current_scope_var(&ident.inspect()[..]) {
self.validate_visibility(ident, vi, namespace)?;
Ok(vi.t())
} else {
if let Some(parent) = self.outer.as_ref() {
return parent.rec_get_var_t(name, vis, namespace);
return parent.rec_get_var_t(ident, namespace);
}
Err(TyCheckError::no_var_error(
line!() as usize,
name.loc(),
ident.loc(),
namespace.clone(),
name.inspect(),
self.get_similar_name(name.inspect()),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
}
}
@ -222,43 +221,48 @@ impl Context {
pub(crate) fn rec_get_attr_t(
&self,
obj: &hir::Expr,
name: &Token,
ident: &Identifier,
namespace: &Str,
) -> TyCheckResult<Type> {
let self_t = obj.t();
match self_t {
Type => todo!(),
Type::Record(rec) => {
// REVIEW: `rec.get(name.inspect())` returns None (Borrow<Str> is implemented for Field). Why?
if let Some(attr) = rec.get(&Field::new(Public, name.inspect().clone())) {
return Ok(attr.clone());
} else {
let t = Type::Record(rec);
return Err(TyCheckError::no_attr_error(
line!() as usize,
name.loc(),
namespace.clone(),
&t,
name.inspect(),
self.get_similar_attr(&t, name.inspect()),
));
let name = ident.name.token();
match self.get_attr_t_from_attributive_t(obj, &self_t, ident, namespace) {
Ok(t) => {
return Ok(t);
}
Err(e) if e.core.kind == ErrorKind::DummyError => {}
Err(e) => {
return Err(e);
}
}
if let Some(singular_ctx) = self.rec_get_singular_ctx(obj) {
match singular_ctx.rec_get_var_t(ident, namespace) {
Ok(t) => {
return Ok(t);
}
Err(e) if e.core.kind == ErrorKind::NameError => {}
Err(e) => {
return Err(e);
}
}
Module => {
let mod_ctx = self.get_context(obj, Some(ContextKind::Module), namespace)?;
let t = mod_ctx.rec_get_var_t(name, Public, namespace)?;
return Ok(t);
}
_ => {}
}
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(&self_t) {
if let Ok(t) = ctx.rec_get_var_t(name, Public, namespace) {
return Ok(t);
for (_, ctx) in self
.rec_get_nominal_super_type_ctxs(&self_t)
.ok_or_else(|| todo!())?
{
match ctx.rec_get_var_t(ident, namespace) {
Ok(t) => {
return Ok(t);
}
Err(e) if e.core.kind == ErrorKind::NameError => {}
Err(e) => {
return Err(e);
}
}
}
// TODO: dependent type widening
if let Some(parent) = self.outer.as_ref() {
parent.rec_get_attr_t(obj, name, namespace)
parent.rec_get_attr_t(obj, ident, namespace)
} else {
Err(TyCheckError::no_attr_error(
line!() as usize,
@ -271,27 +275,119 @@ impl Context {
}
}
fn get_attr_t_from_attributive_t(
&self,
obj: &hir::Expr,
t: &Type,
ident: &Identifier,
namespace: &Str,
) -> TyCheckResult<Type> {
match t {
Type::FreeVar(fv) if fv.is_linked() => {
self.get_attr_t_from_attributive_t(obj, &fv.crack(), ident, namespace)
}
Type::FreeVar(fv) => {
let sup = fv.get_sup().unwrap();
self.get_attr_t_from_attributive_t(obj, &sup, ident, namespace)
}
Type::Ref(t) => self.get_attr_t_from_attributive_t(obj, t, ident, namespace),
Type::RefMut { before, .. } => {
self.get_attr_t_from_attributive_t(obj, before, ident, namespace)
}
Type::Refinement(refine) => {
self.get_attr_t_from_attributive_t(obj, &refine.t, ident, namespace)
}
Type::Record(record) => {
// REVIEW: `rec.get(name.inspect())` returns None (Borrow<Str> is implemented for Field). Why?
if let Some(attr) = record.get(&Field::new(Public, ident.inspect().clone())) {
Ok(attr.clone())
} else {
let t = Type::Record(record.clone());
Err(TyCheckError::no_attr_error(
line!() as usize,
ident.loc(),
namespace.clone(),
&t,
ident.inspect(),
self.get_similar_attr(&t, ident.inspect()),
))
}
}
Module => {
let mod_ctx = self.get_context(obj, Some(ContextKind::Module), namespace)?;
let t = mod_ctx.rec_get_var_t(ident, namespace)?;
Ok(t)
}
other => {
if let Some(v) = self.rec_get_const_obj(&other.name()) {
match v {
ValueObj::Type(TypeObj::Generated(gen)) => self
.get_gen_t_require_attr_t(gen, &ident.inspect()[..])
.map(|t| t.clone())
.ok_or(TyCheckError::dummy(line!() as usize)),
ValueObj::Type(TypeObj::Builtin(_t)) => {
// FIXME:
Err(TyCheckError::dummy(line!() as usize))
}
other => todo!("{other}"),
}
} else {
Err(TyCheckError::dummy(line!() as usize))
}
}
}
}
/// 戻り値ではなく、call全体の型を返す
fn search_callee_t(
&self,
obj: &hir::Expr,
method_name: &Option<Token>,
method_name: &Option<Identifier>,
namespace: &Str,
) -> TyCheckResult<Type> {
if let Some(method_name) = method_name.as_ref() {
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(obj.ref_t()) {
if let Some(vi) = ctx.locals.get(method_name.inspect()) {
return Ok(vi.t());
} else if let Some(vi) = ctx.decls.get(method_name.inspect()) {
for (_, ctx) in self
.rec_get_nominal_super_type_ctxs(obj.ref_t())
.ok_or_else(|| todo!())?
{
if let Some(vi) = ctx
.locals
.get(method_name.inspect())
.or_else(|| ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t());
}
for (_, methods_ctx) in ctx.methods_list.iter() {
if let Some(vi) = methods_ctx
.locals
.get(method_name.inspect())
.or_else(|| methods_ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t());
}
}
}
if let Some(ctx) = self.rec_get_singular_ctx(obj) {
if let Some(vi) = ctx.locals.get(method_name.inspect()) {
return Ok(vi.t());
} else if let Some(vi) = ctx.decls.get(method_name.inspect()) {
if let Some(singular_ctx) = self.rec_get_singular_ctx(obj) {
if let Some(vi) = singular_ctx
.locals
.get(method_name.inspect())
.or_else(|| singular_ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t());
}
for (_, method_ctx) in singular_ctx.methods_list.iter() {
if let Some(vi) = method_ctx
.locals
.get(method_name.inspect())
.or_else(|| method_ctx.decls.get(method_name.inspect()))
{
self.validate_visibility(method_name, vi, namespace)?;
return Ok(vi.t());
}
}
return Err(TyCheckError::singular_no_attr_error(
line!() as usize,
method_name.loc(),
@ -316,6 +412,38 @@ impl Context {
}
}
fn validate_visibility(
&self,
ident: &Identifier,
vi: &VarInfo,
namespace: &str,
) -> TyCheckResult<()> {
if ident.vis() != vi.vis {
Err(TyCheckError::visibility_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
vi.vis,
))
// check if the private variable is loaded from the other scope
} else if vi.vis.is_private()
&& &self.name[..] != "<builtins>"
&& &self.name[..] != namespace
&& !namespace.contains(&self.name[..])
{
Err(TyCheckError::visibility_error(
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
Private,
))
} else {
Ok(())
}
}
pub(crate) fn get_binop_t(
&self,
op: &Token,
@ -325,14 +453,17 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 2);
let cont = binop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?;
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
let t = self.rec_get_var_t(
&Identifier::new(None, VarName::new(symbol.clone())),
namespace,
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_)));
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_)));
let lhs = args[0].expr.clone();
let rhs = args[1].expr.clone();
let bin = hir::BinOp::new(op.name, lhs, rhs, op.t);
let bin = hir::BinOp::new(op.name.into_token(), lhs, rhs, op.t.clone());
// HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする
let core = ErrorCore::new(
e.core.errno,
@ -354,13 +485,16 @@ impl Context {
erg_common::debug_power_assert!(args.len() == 1);
let cont = unaryop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?;
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
let t = self.rec_get_var_t(
&Identifier::new(None, VarName::new(symbol.clone())),
namespace,
)?;
let op = hir::Expr::Accessor(hir::Accessor::private(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_)));
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Ident:(_)));
let expr = args[0].expr.clone();
let unary = hir::UnaryOp::new(op.name, expr, op.t);
let unary = hir::UnaryOp::new(op.name.into_token(), expr, op.t.clone());
let core = ErrorCore::new(
e.core.errno,
e.core.kind,
@ -374,15 +508,17 @@ impl Context {
/// 可変依存型の変更を伝搬させる
fn propagate(&self, t: &Type, callee: &hir::Expr) -> TyCheckResult<()> {
if let Type::Subr(SubrType {
kind: SubrKind::ProcMethod {
after: Some(after), ..
},
..
}) = t
{
log!(info "{}, {}", callee.ref_t(), after);
self.reunify(callee.ref_t(), after, Some(callee.loc()), None)?;
if let Type::Subr(subr) = t {
if let Some(after) = subr.self_t().and_then(|self_t| {
if let RefMut { after, .. } = self_t {
after.as_ref()
} else {
None
}
}) {
log!(info "{}, {}", callee.ref_t(), after);
self.reunify(callee.ref_t(), after, Some(callee.loc()), None)?;
}
}
Ok(())
}
@ -415,14 +551,14 @@ impl Context {
}
);
let (new_sub, new_sup) = (self.resolve_trait(sub)?, self.resolve_trait(sup)?);
let new_constraint = Constraint::sandwiched(new_sub, new_sup, cyclic);
let new_constraint = Constraint::new_sandwiched(new_sub, new_sup, cyclic);
fv.update_constraint(new_constraint);
Ok(Type::FreeVar(fv))
}
Type::PolyTrait { name, params } if params.iter().all(|tp| tp.has_no_unbound_var()) => {
Type::Poly { name, params } if params.iter().all(|tp| tp.has_no_unbound_var()) => {
let t_name = name.clone();
let t_params = params.clone();
let maybe_trait = Type::PolyTrait { name, params };
let maybe_trait = Type::Poly { name, params };
let mut min = Type::Obj;
for pair in self.rec_get_trait_impls(&t_name) {
if self.rec_supertype_of(&pair.sup_trait, &maybe_trait) {
@ -444,7 +580,7 @@ impl Context {
}
}
}
Ok(poly_class(t_name, new_params))
Ok(poly(t_name, new_params))
} else {
Ok(min)
}
@ -491,9 +627,14 @@ impl Context {
let new_t = self.resolve_trait(*t)?;
Ok(ref_(new_t))
}
Type::RefMut(t) => {
let new_t = self.resolve_trait(*t)?;
Ok(ref_mut(new_t))
Type::RefMut { before, after } => {
let new_before = self.resolve_trait(*before)?;
let new_after = if let Some(after) = after {
Some(self.resolve_trait(*after)?)
} else {
None
};
Ok(ref_mut(new_before, new_after))
}
Type::Callable { .. } => todo!(),
Type::And(_, _) | Type::Or(_, _) | Type::Not(_, _) => todo!(),
@ -511,15 +652,25 @@ impl Context {
fn substitute_call(
&self,
obj: &hir::Expr,
method_name: &Option<Token>,
method_name: &Option<Identifier>,
instance: &Type,
pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg],
) -> TyCheckResult<()> {
match instance {
Type::FreeVar(fv) if fv.is_linked() => {
self.substitute_call(obj, method_name, &fv.crack(), pos_args, kw_args)
}
Type::Refinement(refine) => {
self.substitute_call(obj, method_name, &refine.t, pos_args, kw_args)
}
Type::Subr(subr) => {
let callee = if let Some(name) = method_name {
let attr = hir::Attribute::new(obj.clone(), name.clone(), Type::Ellipsis);
let callee = if let Some(ident) = method_name {
let attr = hir::Attribute::new(
obj.clone(),
hir::Identifier::bare(ident.dot.clone(), ident.name.clone()),
Type::Uninited,
);
let acc = hir::Expr::Accessor(hir::Accessor::Attr(attr));
acc
} else {
@ -540,12 +691,34 @@ impl Context {
));
}
let mut passed_params = set! {};
if pos_args.len() >= subr.non_default_params.len() {
let (non_default_args, var_args) =
pos_args.split_at(subr.non_default_params.len());
for (nd_arg, nd_param) in
non_default_args.iter().zip(subr.non_default_params.iter())
let non_default_params_len = if method_name.is_some() {
subr.non_default_params.len() - 1
} else {
subr.non_default_params.len()
};
if pos_args.len() >= non_default_params_len {
let (non_default_args, var_args) = pos_args.split_at(non_default_params_len);
let non_default_params = if subr
.non_default_params
.iter()
.next()
.map(|p| p.name().map(|s| &s[..]) == Some("self"))
.unwrap_or(false)
{
let mut non_default_params = subr.non_default_params.iter();
let self_pt = non_default_params.next().unwrap();
self.sub_unify(
obj.ref_t(),
self_pt.typ(),
Some(obj.loc()),
None,
self_pt.name(),
)?;
non_default_params
} else {
subr.non_default_params.iter()
};
for (nd_arg, nd_param) in non_default_args.iter().zip(non_default_params) {
self.substitute_pos_arg(
&callee,
&nd_arg.expr,
@ -609,7 +782,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}");
log!(err "errno: {}", e.core.errno);
// REVIEW:
let name = callee.var_full_name().unwrap_or_else(|| "".to_string());
let name = callee.show_acc().unwrap_or_else(|| "".to_string());
let name = name + "::" + param.name().map(|s| readable_name(&s[..])).unwrap_or("");
TyCheckError::type_mismatch_error(
line!() as usize,
@ -650,7 +823,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {param_t}");
log!(err "errno: {}", e.core.errno);
// REVIEW:
let name = callee.var_full_name().unwrap_or_else(|| "".to_string());
let name = callee.show_acc().unwrap_or_else(|| "".to_string());
let name = name + "::" + param.name().map(|s| readable_name(&s[..])).unwrap_or("");
TyCheckError::type_mismatch_error(
line!() as usize,
@ -693,7 +866,7 @@ impl Context {
log!(err "semi-unification failed with {callee}\n{arg_t} !<: {}", pt.typ());
log!(err "errno: {}", e.core.errno);
// REVIEW:
let name = callee.var_full_name().unwrap_or_else(|| "".to_string());
let name = callee.show_acc().unwrap_or_else(|| "".to_string());
let name = name + "::" + readable_name(kw_name);
TyCheckError::type_mismatch_error(
line!() as usize,
@ -720,21 +893,23 @@ impl Context {
pub(crate) fn get_call_t(
&self,
obj: &hir::Expr,
method_name: &Option<Token>,
method_name: &Option<Identifier>,
pos_args: &[hir::PosArg],
kw_args: &[hir::KwArg],
namespace: &Str,
) -> TyCheckResult<Type> {
match obj {
hir::Expr::Accessor(hir::Accessor::Local(local)) if &local.inspect()[..] == "match" => {
return self.get_match_call_t(pos_args, kw_args)
hir::Expr::Accessor(hir::Accessor::Ident(local))
if local.vis().is_private() && &local.inspect()[..] == "match" =>
{
return self.get_match_call_t(pos_args, kw_args);
}
_ => {}
}
let found = self.search_callee_t(obj, method_name, namespace)?;
log!(
"Found:\ncallee: {obj}{}\nfound: {found}",
fmt_option!(pre ".", method_name.as_ref().map(|t| &t.content))
fmt_option!(pre ".", method_name.as_ref().map(|ident| &ident.name))
);
let instance = self.instantiate(found, obj)?;
log!(
@ -744,7 +919,8 @@ impl Context {
);
self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?;
log!(info "Substituted:\ninstance: {instance}");
let res = self.eval.eval_t_params(instance, &self, self.level)?;
let level = self.level;
let res = self.eval_t_params(instance, level)?;
log!(info "Params evaluated:\nres: {res}\n");
self.propagate(&res, obj)?;
log!(info "Propagated:\nres: {res}\n");
@ -777,7 +953,10 @@ impl Context {
namespace: &Str,
) -> TyCheckResult<ValueObj> {
let self_t = obj.ref_t();
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(self_t) {
for (_, ctx) in self
.rec_get_nominal_super_type_ctxs(self_t)
.ok_or_else(|| todo!())?
{
if let Ok(t) = ctx.get_const_local(name, namespace) {
return Ok(t);
}
@ -833,7 +1012,7 @@ impl Context {
}
pub(crate) fn get_similar_attr<'a>(&'a self, self_t: &'a Type, name: &str) -> Option<&'a Str> {
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(self_t) {
for (_, ctx) in self.rec_get_nominal_super_type_ctxs(self_t)? {
if let Some(name) = ctx.get_similar_name(name) {
return Some(name);
}
@ -943,49 +1122,40 @@ impl Context {
pub(crate) fn rec_get_nominal_super_trait_ctxs<'a>(
&'a self,
t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> {
if let Some((_ctx_t, ctx)) = self.rec_get_nominal_type_ctx(t) {
ctx.super_traits.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
})
} else {
todo!("{t} has no trait, or not a nominal type")
}
) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
let (_ctx_t, ctx) = self.rec_get_nominal_type_ctx(t)?;
Some(ctx.super_traits.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
}))
}
pub(crate) fn rec_get_nominal_super_class_ctxs<'a>(
&'a self,
t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> {
) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
// if `t` is {S: Str | ...}, `ctx_t` will be Str
// else if `t` is Array(Int, 10), `ctx_t` will be Array(T, N) (if Array(Int, 10) is not specialized)
if let Some((_ctx_t, ctx)) = self.rec_get_nominal_type_ctx(t) {
// t: {S: Str | ...} => ctx.super_traits: [Eq(Str), Mul(Nat), ...]
// => return: [(Str, Eq(Str)), (Str, Mul(Nat)), ...] (the content of &'a Type isn't {S: Str | ...})
ctx.super_classes.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
})
} else {
todo!("{t} has no class, or not a nominal type")
}
let (_ctx_t, ctx) = self.rec_get_nominal_type_ctx(t)?;
// t: {S: Str | ...} => ctx.super_traits: [Eq(Str), Mul(Nat), ...]
// => return: [(Str, Eq(Str)), (Str, Mul(Nat)), ...] (the content of &'a Type isn't {S: Str | ...})
Some(ctx.super_classes.iter().map(|sup| {
let (_t, sup_ctx) = self.rec_get_nominal_type_ctx(sup).unwrap();
(sup, sup_ctx)
}))
}
pub(crate) fn rec_get_nominal_super_type_ctxs<'a>(
&'a self,
t: &Type,
) -> impl Iterator<Item = (&'a Type, &'a Context)> {
if let Some((t, ctx)) = self.rec_get_nominal_type_ctx(t) {
vec![(t, ctx)].into_iter().chain(
ctx.super_classes
.iter()
.chain(ctx.super_traits.iter())
.map(|sup| self.rec_get_nominal_type_ctx(&sup).unwrap()),
)
} else {
todo!("{t} not found")
}
) -> Option<impl Iterator<Item = (&'a Type, &'a Context)>> {
let (t, ctx) = self.rec_get_nominal_type_ctx(t)?;
let sups = ctx
.super_classes
.iter()
.chain(ctx.super_traits.iter())
.map(|sup| self.rec_get_nominal_type_ctx(&sup).unwrap());
Some(vec![(t, ctx)].into_iter().chain(sups))
}
pub(crate) fn rec_get_nominal_type_ctx<'a>(
@ -993,32 +1163,52 @@ impl Context {
typ: &Type,
) -> Option<(&'a Type, &'a Context)> {
match typ {
Type::FreeVar(fv) if fv.is_linked() => {
if let Some(res) = self.rec_get_nominal_type_ctx(&fv.crack()) {
return Some(res);
}
}
Type::FreeVar(fv) => {
let sup = fv.get_sup().unwrap();
if let Some(res) = self.rec_get_nominal_type_ctx(&sup) {
return Some(res);
}
}
Type::Refinement(refine) => {
return self.rec_get_nominal_type_ctx(&refine.t);
if let Some(res) = self.rec_get_nominal_type_ctx(&refine.t) {
return Some(res);
}
}
Type::Quantified(_) => {
return self.rec_get_nominal_type_ctx(&class("QuantifiedFunction"));
if let Some(res) = self.rec_get_nominal_type_ctx(&mono("QuantifiedFunction")) {
return Some(res);
}
}
Type::PolyClass { name, params: _ } => {
if let Some((t, ctx)) = self.poly_classes.get(name) {
Type::Poly { name, params: _ } => {
if let Some((t, ctx)) = self.rec_get_poly_type(name) {
return Some((t, ctx));
}
}
Type::PolyTrait { name, params: _ } => {
if let Some((t, ctx)) = self.poly_traits.get(name) {
return Some((t, ctx));
/*Type::Record(rec) if rec.values().all(|attr| self.supertype_of(&Type, attr)) => {
// TODO: reference RecordType (inherits Type)
if let Some(res) = self.rec_get_nominal_type_ctx(&Type) {
return Some(res);
}
}
Type::Record(rec) if rec.values().all(|attr| self.supertype_of(&Type, attr)) => {
return self.rec_get_nominal_type_ctx(&Type)
}
}*/
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => {
if let Some((t, ctx)) = self.mono_types.get(&typ.name()) {
if let Some((t, ctx)) = self.rec_get_mono_type(&other.name()) {
return Some((t, ctx));
}
}
other => todo!("{other}"),
Type::Ref(t) | Type::RefMut { before: t, .. } => {
if let Some(res) = self.rec_get_nominal_type_ctx(t) {
return Some(res);
}
}
other => {
log!("{other} has no nominal definition");
}
}
if let Some(outer) = &self.outer {
outer.rec_get_nominal_type_ctx(typ)
@ -1027,12 +1217,83 @@ impl Context {
}
}
pub(crate) fn rec_get_mut_nominal_type_ctx<'a>(
&'a mut self,
typ: &Type,
) -> Option<(&'a Type, &'a mut Context)> {
// SAFETY: `rec_get_nominal_type_ctx` is called only when `self` is not borrowed
let outer = unsafe {
(&mut self.outer as *mut Option<Box<Context>>)
.as_mut()
.unwrap()
};
match typ {
Type::FreeVar(fv) if fv.is_linked() => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&fv.crack()) {
return Some(res);
}
}
Type::FreeVar(fv) => {
let sup = fv.get_sup().unwrap();
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&sup) {
return Some(res);
}
}
Type::Refinement(refine) => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&refine.t) {
return Some(res);
}
}
Type::Quantified(_) => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(&mono("QuantifiedFunction")) {
return Some(res);
}
}
Type::Poly { name, params: _ } => {
if let Some((t, ctx)) = self.rec_get_mut_poly_type(name) {
return Some((t, ctx));
}
}
/*Type::Record(rec) if rec.values().all(|attr| self.supertype_of(&Type, attr)) => {
// TODO: reference RecordType (inherits Type)
if let Some(res) = self.rec_get_nominal_type_ctx(&Type) {
return Some(res);
}
}*/
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => {
if let Some((t, ctx)) = self.rec_get_mut_mono_type(&other.name()) {
return Some((t, ctx));
}
}
Type::Ref(t) | Type::RefMut { before: t, .. } => {
if let Some(res) = self.rec_get_mut_nominal_type_ctx(t) {
return Some(res);
}
}
other => {
log!("{other} has no nominal definition");
}
}
if let Some(outer) = outer {
outer.rec_get_mut_nominal_type_ctx(typ)
} else {
None
}
}
fn rec_get_singular_ctx(&self, obj: &hir::Expr) -> Option<&Context> {
match obj.ref_t() {
// TODO: attr
Type::Module => self.rec_get_mod(&obj.var_full_name()?),
Type::Class => todo!(),
Type::Module => self.rec_get_mod(&obj.show_acc()?),
Type::Type | Type::Class => {
let typ = Type::Mono(Str::from(obj.show_acc().unwrap()));
self.rec_get_nominal_type_ctx(&typ).map(|(_, ctx)| ctx)
}
Type::Trait => todo!(),
Type::Refinement(refine) => {
self.rec_get_nominal_type_ctx(&refine.t).map(|(_, ctx)| ctx)
}
_ => None,
}
}
@ -1073,8 +1334,14 @@ impl Context {
// rec_get_const_localとは違い、位置情報を持たないしエラーとならない
pub(crate) fn rec_get_const_obj(&self, name: &str) -> Option<&ValueObj> {
if let Some(val) = self.consts.get(name) {
Some(val)
} else if let Some(outer) = &self.outer {
return Some(val);
}
for (_, ctx) in self.methods_list.iter() {
if let Some(val) = ctx.consts.get(name) {
return Some(val);
}
}
if let Some(outer) = &self.outer {
outer.rec_get_const_obj(name)
} else {
None
@ -1083,12 +1350,123 @@ impl Context {
pub(crate) fn rec_get_const_param_defaults(&self, name: &str) -> Option<&Vec<ConstTemplate>> {
if let Some(impls) = self.const_param_defaults.get(name) {
return Some(impls);
}
if let Some(outer) = &self.outer {
Some(impls)
} else if let Some(outer) = &self.outer {
outer.rec_get_const_param_defaults(name)
} else {
None
}
}
pub(crate) fn rec_get_self_t(&self) -> Option<Type> {
if self.kind.is_method_def() || self.kind.is_type() {
// TODO: poly type
let name = self.name.split(&[':', '.']).last().unwrap();
let mono_t = mono(Str::rc(name));
if let Some((t, _)) = self.rec_get_nominal_type_ctx(&mono_t) {
Some(t.clone())
} else {
None
}
} else {
if let Some(outer) = &self.outer {
outer.rec_get_self_t()
} else {
None
}
}
}
fn rec_get_mono_type(&self, name: &str) -> Option<(&Type, &Context)> {
if let Some((t, ctx)) = self.mono_types.get(name) {
Some((t, ctx))
} else if let Some(outer) = &self.outer {
outer.rec_get_mono_type(name)
} else {
None
}
}
fn rec_get_poly_type(&self, name: &str) -> Option<(&Type, &Context)> {
if let Some((t, ctx)) = self.poly_types.get(name) {
Some((t, ctx))
} else if let Some(outer) = &self.outer {
outer.rec_get_poly_type(name)
} else {
None
}
}
fn rec_get_mut_mono_type(&mut self, name: &str) -> Option<(&mut Type, &mut Context)> {
if let Some((t, ctx)) = self.mono_types.get_mut(name) {
Some((t, ctx))
} else if let Some(outer) = self.outer.as_mut() {
outer.rec_get_mut_mono_type(name)
} else {
None
}
}
fn rec_get_mut_poly_type(&mut self, name: &str) -> Option<(&mut Type, &mut Context)> {
if let Some((t, ctx)) = self.poly_types.get_mut(name) {
Some((t, ctx))
} else if let Some(outer) = self.outer.as_mut() {
outer.rec_get_mut_poly_type(name)
} else {
None
}
}
fn rec_get_type(&self, name: &str) -> Option<(&Type, &Context)> {
if let Some((t, ctx)) = self.mono_types.get(name) {
Some((t, ctx))
} else if let Some((t, ctx)) = self.poly_types.get(name) {
Some((t, ctx))
} else if let Some(outer) = &self.outer {
outer.rec_get_type(name)
} else {
None
}
}
fn get_gen_t_require_attr_t<'a>(&'a self, gen: &'a GenTypeObj, attr: &str) -> Option<&'a Type> {
match gen.require_or_sup.typ() {
Type::Record(rec) => {
if let Some(t) = rec.get(attr) {
return Some(t);
}
}
other => {
let obj = self.rec_get_const_obj(&other.name());
let obj = enum_unwrap!(obj, Some:(ValueObj::Type:(TypeObj::Generated:(_))));
if let Some(t) = self.get_gen_t_require_attr_t(obj, attr) {
return Some(t);
}
}
}
if let Some(additional) = &gen.additional {
if let Type::Record(gen) = additional.typ() {
if let Some(t) = gen.get(attr) {
return Some(t);
}
}
}
None
}
pub(crate) fn _is_class(&self, typ: &Type) -> bool {
if let Some((_, ctx)) = self.rec_get_nominal_type_ctx(typ) {
ctx.kind.is_class()
} else {
todo!()
}
}
pub(crate) fn is_trait(&self, typ: &Type) -> bool {
if let Some((_, ctx)) = self.rec_get_nominal_type_ctx(typ) {
ctx.kind.is_trait()
} else {
todo!()
}
}
}

View file

@ -7,25 +7,25 @@ use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_common::{assume_unreachable, enum_unwrap, set, try_map};
use erg_type::free::{Constraint, Cyclicity, FreeTyVar};
use TyParamOrdering::*;
use Type::*;
use ast::{
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, SubrKindSpec, TypeBoundSpec,
TypeBoundSpecs, TypeSpec,
ParamSignature, ParamTySpec, PreDeclTypeSpec, SimpleTypeSpec, TypeBoundSpec, TypeBoundSpecs,
TypeSpec,
};
use erg_parser::ast;
use erg_parser::token::TokenKind;
use erg_type::constructors::*;
use erg_type::free::{Constraint, Cyclicity, FreeTyVar};
use erg_type::typaram::{IntervalOp, TyParam, TyParamOrdering};
use erg_type::value::ValueObj;
use erg_type::{HasType, ParamTy, Predicate, SubrKind, TyBound, Type};
use TyParamOrdering::*;
use Type::*;
use crate::context::eval::eval_lit;
use crate::context::{Context, RegistrationMode};
use crate::error::TyCheckResult;
use crate::eval::eval_lit;
use crate::hir;
use RegistrationMode::*;
@ -78,16 +78,16 @@ impl TyVarContext {
) -> TyParam {
match ct {
ConstTemplate::Obj(o) => match o {
ValueObj::Type(t) if t.is_mono_q() => {
if &t.name()[..] == "Self" {
let constraint = Constraint::type_of(Type);
ValueObj::Type(t) if t.typ().is_mono_q() => {
if &t.typ().name()[..] == "Self" {
let constraint = Constraint::new_type_of(Type);
let t = named_free_var(Str::rc(var_name), self.level, constraint);
TyParam::t(t)
} else {
todo!()
}
}
ValueObj::Type(t) => TyParam::t(*t.clone()),
ValueObj::Type(t) => TyParam::t(t.typ().clone()),
v => TyParam::Value(v.clone()),
},
ConstTemplate::App { .. } => {
@ -105,7 +105,7 @@ impl TyVarContext {
) -> Type {
if let Some(temp_defaults) = ctx.rec_get_const_param_defaults(&name) {
let (_, ctx) = ctx
.rec_get_nominal_type_ctx(&poly_trait(name.clone(), params.clone()))
.rec_get_nominal_type_ctx(&poly(name.clone(), params.clone()))
.unwrap_or_else(|| panic!("{} not found", name));
let defined_params_len = ctx.params.len();
let given_params_len = params.len();
@ -130,9 +130,9 @@ impl TyVarContext {
self.push_or_init_typaram(&tp.tvar_name().unwrap(), &tp);
inst_defaults.push(tp);
}
poly_trait(name, [inst_non_defaults, inst_defaults].concat())
poly(name, [inst_non_defaults, inst_defaults].concat())
} else {
poly_trait(
poly(
name,
params
.into_iter()
@ -154,23 +154,22 @@ impl TyVarContext {
match bound {
TyBound::Sandwiched { sub, mid, sup } => {
let sub_instance = match sub {
Type::PolyTrait { name, params } => {
Type::Poly { name, params } => {
self.instantiate_poly(mid.name(), &name, params, ctx)
}
Type::PolyClass { .. } => todo!(),
Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs),
sub => sub,
};
let sup_instance = match sup {
Type::PolyTrait { name, params } => {
Type::Poly { name, params } => {
self.instantiate_poly(mid.name(), &name, params, ctx)
}
Type::PolyClass { .. } => todo!(),
Type::MonoProj { lhs, rhs } => mono_proj(self.instantiate_qvar(*lhs), rhs),
sup => sup,
};
let name = mid.name();
let constraint = Constraint::sandwiched(sub_instance, sup_instance, Cyclicity::Not);
let constraint =
Constraint::new_sandwiched(sub_instance, sup_instance, Cyclicity::Not);
self.push_or_init_tyvar(
&name,
&named_free_var(name.clone(), self.level, constraint),
@ -178,13 +177,12 @@ impl TyVarContext {
}
TyBound::Instance { name, t } => {
let t = match t {
Type::PolyClass { .. } => todo!(),
Type::PolyTrait { name, params } => {
Type::Poly { name, params } => {
self.instantiate_poly(name.clone(), &name, params, ctx)
}
t => t,
};
let constraint = Constraint::type_of(t.clone());
let constraint = Constraint::new_type_of(t.clone());
// TODO: type-like types
if t == Type {
if let Some(tv) = self.tyvar_instances.get(&name) {
@ -305,7 +303,7 @@ impl TyVarContext {
}
fn check_cyclicity_and_link(&self, name: &str, fv_inst: &FreeTyVar, tv: &Type) {
let (sub, sup) = enum_unwrap!(tv, Type::FreeVar).crack_bound_types().unwrap();
let (sub, sup) = enum_unwrap!(tv, Type::FreeVar).get_bound_types().unwrap();
let new_cyclicity = match (sup.contains_tvar(name), sub.contains_tvar(name)) {
(true, true) => Cyclicity::Both,
// T <: Super
@ -377,7 +375,7 @@ impl Context {
let spec_t = if let Some(s) = t_spec {
self.instantiate_typespec(s, mode)?
} else {
free_var(self.level, Constraint::type_of(Type))
free_var(self.level, Constraint::new_type_of(Type))
};
if let Some(eval_t) = opt_eval_t {
self.sub_unify(&eval_t, &spec_t, None, t_spec.map(|s| s.loc()), None)?;
@ -428,7 +426,7 @@ impl Context {
} else {
self.level + 1
};
free_var(level, Constraint::type_of(Type))
free_var(level, Constraint::new_type_of(Type))
};
if let Some(eval_ret_t) = eval_ret_t {
self.sub_unify(
@ -465,7 +463,7 @@ impl Context {
} else {
self.level + 1
};
free_var(level, Constraint::type_of(Type))
free_var(level, Constraint::new_type_of(Type))
}
}
};
@ -510,10 +508,10 @@ impl Context {
let len = self.instantiate_const_expr(&len.expr);
Ok(array(t, len))
} else {
Ok(class("GenericArray"))
Ok(mono("GenericArray"))
}
}
other if simple.args.is_empty() => Ok(class(Str::rc(other))),
other if simple.args.is_empty() => Ok(mono(Str::rc(other))),
other => {
// FIXME: kw args
let params = simple.args.pos_args().map(|arg| match &arg.expr {
@ -523,7 +521,7 @@ impl Context {
}
});
// FIXME: if type is a trait
Ok(poly_class(Str::rc(other), params.collect()))
Ok(poly(Str::rc(other), params.collect()))
}
}
}
@ -543,7 +541,7 @@ impl Context {
expr: &ast::ConstExpr,
) -> TyCheckResult<Type> {
match expr {
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => Ok(class(name.inspect())),
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => Ok(mono(name.inspect())),
_ => todo!(),
}
}
@ -608,9 +606,9 @@ impl Context {
_ => assume_unreachable!(),
};
let l = self.instantiate_const_expr(lhs);
let l = self.eval.eval_tp(&l, self)?;
let l = self.eval_tp(&l)?;
let r = self.instantiate_const_expr(rhs);
let r = self.eval.eval_tp(&r, self)?;
let r = self.eval_tp(&r)?;
if let Some(Greater) = self.rec_try_cmp(&l, &r) {
panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)")
}
@ -632,7 +630,11 @@ impl Context {
.collect();
let return_t = self.instantiate_typespec(&subr.return_t, mode)?;
Ok(subr_t(
self.instantiate_subr_kind(&subr.kind)?,
if subr.arrow.is(TokenKind::FuncArrow) {
SubrKind::Func
} else {
SubrKind::Proc
},
non_defaults,
var_args,
defaults,
@ -642,23 +644,6 @@ impl Context {
}
}
fn instantiate_subr_kind(&self, kind: &SubrKindSpec) -> TyCheckResult<SubrKind> {
match kind {
SubrKindSpec::Func => Ok(SubrKind::Func),
SubrKindSpec::Proc => Ok(SubrKind::Proc),
SubrKindSpec::FuncMethod(spec) => {
Ok(SubrKind::fn_met(self.instantiate_typespec(spec, Normal)?))
}
SubrKindSpec::ProcMethod { before, after } => Ok(SubrKind::pr_met(
self.instantiate_typespec(before, Normal)?,
after
.as_ref()
.map(|after| self.instantiate_typespec(after, Normal))
.transpose()?,
)),
}
}
pub(crate) fn instantiate_ty_bound(
&self,
bound: &TypeBoundSpec,
@ -759,23 +744,6 @@ impl Context {
Type::Refinement(refine)
}
Subr(mut subr) => {
let kind = match subr.kind {
SubrKind::FuncMethod(self_t) => {
let res = Self::instantiate_t(*self_t, tv_ctx);
SubrKind::FuncMethod(Box::new(res))
}
SubrKind::ProcMethod { before, after } => {
let before = Self::instantiate_t(*before, tv_ctx);
let after = if let Some(after) = after {
let after = Self::instantiate_t(*after, tv_ctx);
Some(after)
} else {
None
};
SubrKind::pr_met(before, after)
}
other => other,
};
for pt in subr.non_default_params.iter_mut() {
*pt.typ_mut() = Self::instantiate_t(mem::take(pt.typ_mut()), tv_ctx);
}
@ -788,7 +756,7 @@ impl Context {
}
let return_t = Self::instantiate_t(*subr.return_t, tv_ctx);
subr_t(
kind,
subr.kind,
subr.non_default_params,
subr.var_params.map(|p| *p),
subr.default_params,
@ -805,25 +773,24 @@ impl Context {
let t = Self::instantiate_t(*t, tv_ctx);
ref_(t)
}
RefMut(t) => {
let t = Self::instantiate_t(*t, tv_ctx);
ref_mut(t)
RefMut { before, after } => {
let before = Self::instantiate_t(*before, tv_ctx);
let after = if let Some(after) = after {
Some(Self::instantiate_t(*after, tv_ctx))
} else {
None
};
ref_mut(before, after)
}
MonoProj { lhs, rhs } => {
let lhs = Self::instantiate_t(*lhs, tv_ctx);
mono_proj(lhs, rhs)
}
PolyClass { name, mut params } => {
Poly { name, mut params } => {
for param in params.iter_mut() {
*param = Self::instantiate_tp(mem::take(param), tv_ctx);
}
poly_class(name, params)
}
PolyTrait { name, mut params } => {
for param in params.iter_mut() {
*param = Self::instantiate_tp(mem::take(param), tv_ctx);
}
poly_trait(name, params)
poly(name, params)
}
Quantified(_) => {
panic!("a quantified type should not be instantiated, instantiate the inner type")
@ -839,9 +806,15 @@ impl Context {
let mut tv_ctx = TyVarContext::new(self.level, quant.bounds, &self);
let t = Self::instantiate_t(*quant.unbound_callable, &mut tv_ctx);
match &t {
Type::Subr(subr) => match subr.kind.self_t() {
Some(l) => {
self.unify(l, callee.ref_t(), None, Some(callee.loc()))?;
Type::Subr(subr) => match subr.self_t() {
Some(self_t) => {
self.sub_unify(
callee.ref_t(),
self_t,
None,
Some(callee.loc()),
Some(&Str::ever("self")),
)?;
}
_ => {}
},

View file

@ -2,6 +2,7 @@
//! `Context` is used for type inference and type checking.
pub mod cache;
pub mod compare;
pub mod eval;
pub mod hint;
pub mod initialize;
pub mod inquire;
@ -33,7 +34,6 @@ use erg_parser::token::Token;
use crate::context::instantiate::ConstTemplate;
use crate::error::{TyCheckError, TyCheckErrors, TyCheckResult};
use crate::eval::Evaluator;
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
use Mutability::*;
use Visibility::*;
@ -85,7 +85,7 @@ pub enum TyParamIdx {
impl TyParamIdx {
pub fn search(search_from: &Type, target: &Type) -> Option<Self> {
match search_from {
Type::PolyClass { params, .. } => {
Type::Poly { params, .. } => {
for (i, tp) in params.iter().enumerate() {
match tp {
TyParam::Type(t) if t.as_ref() == target => return Some(Self::Nth(i)),
@ -193,6 +193,7 @@ pub enum ContextKind {
Func,
Proc,
Class,
MethodDefs,
Trait,
StructuralTrait,
Patch(Type),
@ -203,6 +204,24 @@ pub enum ContextKind {
Dummy,
}
impl ContextKind {
pub const fn is_method_def(&self) -> bool {
matches!(self, Self::MethodDefs)
}
pub const fn is_type(&self) -> bool {
matches!(self, Self::Class | Self::Trait | Self::StructuralTrait)
}
pub fn is_class(&self) -> bool {
matches!(self, Self::Class)
}
pub fn is_trait(&self) -> bool {
matches!(self, Self::Trait | Self::StructuralTrait)
}
}
/// 記号表に登録されているモードを表す
/// Preregister: サブルーチンまたは定数式、前方参照できる
/// Normal: 前方参照できない
@ -215,7 +234,7 @@ pub enum RegistrationMode {
/// Represents the context of the current scope
///
/// Recursive functions/methods are highlighted with the prefix `rec_`, as performance may be significantly degraded.
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Context {
pub(crate) name: Str,
pub(crate) kind: ContextKind,
@ -231,8 +250,9 @@ pub struct Context {
// patchによってsuper class/traitになったものはここに含まれない
pub(crate) super_classes: Vec<Type>, // if self is a patch, means patch classes
pub(crate) super_traits: Vec<Type>, // if self is not a trait, means implemented traits
// specialized contexts, If self is a type
pub(crate) specializations: Vec<(Type, Context)>,
// method definitions, if the context is a type
// specializations are included and needs to be separated out
pub(crate) methods_list: Vec<(Type, Context)>,
/// K: method name, V: impl patch
/// Provided methods can switch implementations on a scope-by-scope basis
/// K: メソッド名, V: それを実装するパッチたち
@ -254,15 +274,12 @@ pub struct Context {
pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
pub(crate) locals: Dict<VarName, VarInfo>,
pub(crate) consts: Dict<VarName, ValueObj>,
pub(crate) eval: Evaluator,
// {"Nat": ctx, "Int": ctx, ...}
pub(crate) mono_types: Dict<VarName, (Type, Context)>,
// Implementation Contexts for Polymorphic Types
// Vec<TyParam> are specialization parameters
// e.g. {"Array": [(Array(Nat), ctx), (Array(Int), ctx), (Array(Str), ctx), (Array(Obj), ctx), (Array('T), ctx)], ...}
pub(crate) poly_classes: Dict<VarName, (Type, Context)>,
// Traits cannot be specialized
pub(crate) poly_traits: Dict<VarName, (Type, Context)>,
pub(crate) poly_types: Dict<VarName, (Type, Context)>,
// patches can be accessed like normal records
// but when used as a fallback to a type, values are traversed instead of accessing by keys
pub(crate) patches: Dict<VarName, Context>,
@ -296,9 +313,8 @@ impl fmt::Display for Context {
.field("decls", &self.decls)
.field("locals", &self.params)
.field("consts", &self.consts)
.field("eval", &self.eval)
.field("mono_types", &self.mono_types)
.field("poly_types", &self.poly_classes)
.field("poly_types", &self.poly_types)
.field("patches", &self.patches)
.field("mods", &self.mods)
.finish()
@ -345,12 +361,12 @@ impl Context {
let idx = ParamIdx::Nth(idx);
let kind = VarKind::parameter(id, idx, param.default_info);
// TODO: is_const { Const } else { Immutable }
let vi = VarInfo::new(param.t, Immutable, Private, kind);
let vi = VarInfo::new(param.t, Immutable, Private, kind, None);
params_.push((Some(VarName::new(Token::static_symbol(name))), vi));
} else {
let idx = ParamIdx::Nth(idx);
let kind = VarKind::parameter(id, idx, param.default_info);
let vi = VarInfo::new(param.t, Immutable, Private, kind);
let vi = VarInfo::new(param.t, Immutable, Private, kind, None);
params_.push((None, vi));
}
}
@ -362,7 +378,7 @@ impl Context {
outer: outer.map(Box::new),
super_classes,
super_traits,
specializations: vec![],
methods_list: vec![],
const_param_defaults: Dict::default(),
method_impl_patches: Dict::default(),
trait_impls: Dict::default(),
@ -370,10 +386,8 @@ impl Context {
decls: Dict::default(),
locals: Dict::with_capacity(capacity),
consts: Dict::default(),
eval: Evaluator::default(),
mono_types: Dict::default(),
poly_classes: Dict::default(),
poly_traits: Dict::default(),
poly_types: Dict::default(),
mods: Dict::default(),
patches: Dict::default(),
_nlocals: 0,
@ -476,6 +490,20 @@ impl Context {
Self::poly_class(name, vec![], super_classes, super_traits, level)
}
#[inline]
pub fn methods<S: Into<Str>>(name: S, level: usize) -> Self {
Self::with_capacity(
name.into(),
ContextKind::MethodDefs,
vec![],
None,
vec![],
vec![],
2,
level,
)
}
#[inline]
pub fn poly_patch<S: Into<Str>>(
name: S,
@ -509,6 +537,20 @@ impl Context {
)
}
#[inline]
pub fn instant(name: Str, capacity: usize, outer: Context) -> Self {
Self::with_capacity(
name,
ContextKind::Instant,
vec![],
Some(outer),
vec![],
vec![],
capacity,
Self::TOP_LEVEL,
)
}
#[inline]
pub fn caused_by(&self) -> Str {
self.name.clone()
@ -532,7 +574,7 @@ impl Context {
Ok(())
}
pub(crate) fn pop(&mut self) -> Result<(), TyCheckErrors> {
pub(crate) fn pop(&mut self) -> Result<Context, TyCheckErrors> {
let mut uninited_errs = TyCheckErrors::empty();
for (name, vi) in self.decls.iter() {
uninited_errs.push(TyCheckError::uninitialized_error(
@ -544,12 +586,14 @@ impl Context {
));
}
if let Some(parent) = &mut self.outer {
*self = mem::take(parent);
let parent = mem::take(parent);
let ctx = mem::take(self);
*self = *parent;
log!(info "{}: current namespace: {}", fn_name!(), self.name);
if !uninited_errs.is_empty() {
Err(uninited_errs)
} else {
Ok(())
Ok(ctx)
}
} else {
Err(TyCheckErrors::from(TyCheckError::checker_bug(

View file

@ -1,20 +1,20 @@
use std::option::Option; // conflicting to Type::Option
use erg_common::traits::Locational;
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_common::{enum_unwrap, get_hash, log, set};
use erg_type::free::HasLevel;
use ast::{DefId, VarName};
use ast::{DefId, Identifier, VarName};
use erg_parser::ast;
use erg_type::constructors::{enum_t, func, proc};
use erg_type::value::ValueObj;
use erg_type::constructors::{enum_t, func, func1, proc, ref_, ref_mut};
use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, SubrType, TyBound, Type};
use Type::*;
use crate::context::{Context, DefaultInfo, RegistrationMode};
use crate::context::{Context, DefaultInfo, RegistrationMode, TraitInstance};
use crate::error::readable_name;
use crate::error::{TyCheckError, TyCheckResult};
use crate::hir;
@ -24,7 +24,8 @@ use RegistrationMode::*;
use Visibility::*;
impl Context {
fn registered(&self, name: &Str, recursive: bool) -> bool {
/// If it is a constant that is defined, there must be no variable of the same name defined across all scopes
fn registered(&self, name: &Str, is_const: bool) -> bool {
if self.params.iter().any(|(maybe_name, _)| {
maybe_name
.as_ref()
@ -34,9 +35,9 @@ impl Context {
{
return true;
}
if recursive {
if is_const {
if let Some(outer) = &self.outer {
outer.registered(name, recursive)
outer.registered(name, is_const)
} else {
false
}
@ -45,7 +46,7 @@ impl Context {
}
}
fn declare_var(
fn _declare_var(
&mut self,
sig: &ast::VarSignature,
opt_t: Option<Type>,
@ -54,30 +55,22 @@ impl Context {
let muty = Mutability::from(&sig.inspect().unwrap()[..]);
match &sig.pat {
ast::VarPattern::Ident(ident) => {
if sig.t_spec.is_none() && opt_t.is_none() {
Err(TyCheckError::no_type_spec_error(
if self.registered(ident.inspect(), ident.is_const()) {
return Err(TyCheckError::duplicate_decl_error(
line!() as usize,
sig.loc(),
self.caused_by(),
ident.inspect(),
))
} else {
if self.registered(ident.inspect(), ident.is_const()) {
return Err(TyCheckError::duplicate_decl_error(
line!() as usize,
sig.loc(),
self.caused_by(),
ident.inspect(),
));
}
let vis = ident.vis();
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
let sig_t =
self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?;
self.decls
.insert(ident.name.clone(), VarInfo::new(sig_t, muty, vis, kind));
Ok(())
));
}
let vis = ident.vis();
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
let sig_t = self.instantiate_var_sig_t(sig.t_spec.as_ref(), opt_t, PreRegister)?;
self.decls.insert(
ident.name.clone(),
VarInfo::new(sig_t, muty, vis, kind, None),
);
Ok(())
}
_ => todo!(),
}
@ -102,7 +95,17 @@ impl Context {
));
}
let t = self.instantiate_sub_sig_t(sig, opt_ret_t, PreRegister)?;
let vi = VarInfo::new(t, muty, vis, kind);
let comptime_decos = sig
.decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
Some(local.inspect().clone())
}
_ => None,
})
.collect();
let vi = VarInfo::new(t, muty, vis, kind, Some(comptime_decos));
if let Some(_decl) = self.decls.remove(name) {
return Err(TyCheckError::duplicate_decl_error(
line!() as usize,
@ -122,6 +125,10 @@ impl Context {
body_t: &Type,
id: DefId,
) -> TyCheckResult<()> {
// already defined as const
if sig.is_const() {
return Ok(());
}
let ident = match &sig.pat {
ast::VarPattern::Ident(ident) => ident,
_ => todo!(),
@ -141,7 +148,7 @@ impl Context {
// something to do?
}
let vis = ident.vis();
let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id));
let vi = VarInfo::new(generalized, muty, vis, VarKind::Defined(id), None);
self.locals.insert(ident.name.clone(), vi);
Ok(())
}
@ -156,18 +163,29 @@ impl Context {
opt_decl_t: Option<&ParamTy>,
) -> TyCheckResult<()> {
match &sig.pat {
ast::ParamPattern::Lit(_) => Ok(()),
ast::ParamPattern::Discard(_token) => Ok(()),
ast::ParamPattern::VarName(v) => {
if self.registered(v.inspect(), v.inspect().is_uppercase()) {
ast::ParamPattern::VarName(name) => {
if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error(
line!() as usize,
v.loc(),
name.loc(),
self.caused_by(),
v.inspect(),
name.inspect(),
))
} else {
// ok, not defined
let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?;
if &name.inspect()[..] == "self" {
let self_t = self.rec_get_self_t().unwrap();
self.sub_unify(
&spec_t,
&self_t,
Some(name.loc()),
None,
Some(name.inspect()),
)?;
}
let idx = if let Some(outer) = outer {
ParamIdx::nested(outer, nth)
} else {
@ -178,16 +196,101 @@ impl Context {
} else {
DefaultInfo::NonDefault
};
let kind = VarKind::parameter(DefId(get_hash(&(&self.name, v))), idx, default);
let kind =
VarKind::parameter(DefId(get_hash(&(&self.name, name))), idx, default);
self.params.push((
Some(v.clone()),
VarInfo::new(spec_t, Immutable, Private, kind),
Some(name.clone()),
VarInfo::new(spec_t, Immutable, Private, kind, None),
));
Ok(())
}
}
ast::ParamPattern::Lit(_) => Ok(()),
_ => unreachable!(),
ast::ParamPattern::Ref(name) => {
if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error(
line!() as usize,
name.loc(),
self.caused_by(),
name.inspect(),
))
} else {
// ok, not defined
let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?;
if &name.inspect()[..] == "self" {
let self_t = self.rec_get_self_t().unwrap();
self.sub_unify(
&spec_t,
&self_t,
Some(name.loc()),
None,
Some(name.inspect()),
)?;
}
let spec_t = ref_(spec_t);
let idx = if let Some(outer) = outer {
ParamIdx::nested(outer, nth)
} else {
ParamIdx::Nth(nth)
};
let default = if sig.opt_default_val.is_some() {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
};
let kind =
VarKind::parameter(DefId(get_hash(&(&self.name, name))), idx, default);
self.params.push((
Some(name.clone()),
VarInfo::new(spec_t, Immutable, Private, kind, None),
));
Ok(())
}
}
ast::ParamPattern::RefMut(name) => {
if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error(
line!() as usize,
name.loc(),
self.caused_by(),
name.inspect(),
))
} else {
// ok, not defined
let spec_t = self.instantiate_param_sig_t(sig, opt_decl_t, Normal)?;
if &name.inspect()[..] == "self" {
let self_t = self.rec_get_self_t().unwrap();
self.sub_unify(
&spec_t,
&self_t,
Some(name.loc()),
None,
Some(name.inspect()),
)?;
}
let spec_t = ref_mut(spec_t.clone(), Some(spec_t));
let idx = if let Some(outer) = outer {
ParamIdx::nested(outer, nth)
} else {
ParamIdx::Nth(nth)
};
let default = if sig.opt_default_val.is_some() {
DefaultInfo::WithDefault
} else {
DefaultInfo::NonDefault
};
let kind =
VarKind::parameter(DefId(get_hash(&(&self.name, name))), idx, default);
self.params.push((
Some(name.clone()),
VarInfo::new(spec_t, Immutable, Private, kind, None),
));
Ok(())
}
}
other => {
log!(err "{other}");
unreachable!()
}
}
}
@ -236,6 +339,10 @@ impl Context {
id: DefId,
body_t: &Type,
) -> TyCheckResult<()> {
// already defined as const
if sig.is_const() {
return Ok(());
}
let muty = if sig.ident.is_const() {
Mutability::Const
} else {
@ -263,7 +370,7 @@ impl Context {
)
})?;
}
if self.registered(name.inspect(), name.inspect().is_uppercase()) {
if self.registered(name.inspect(), name.is_const()) {
Err(TyCheckError::reassign_error(
line!() as usize,
name.loc(),
@ -307,48 +414,263 @@ impl Context {
));
}
}
// TODO: visibility
let vi = VarInfo::new(found_t, muty, Private, VarKind::Defined(id));
let comptime_decos = sig
.decorators
.iter()
.filter_map(|deco| match &deco.0 {
ast::Expr::Accessor(ast::Accessor::Ident(local)) if local.is_const() => {
Some(local.inspect().clone())
}
_ => None,
})
.collect();
let vi = VarInfo::new(
found_t,
muty,
sig.ident.vis(),
VarKind::Defined(id),
Some(comptime_decos),
);
log!(info "Registered {}::{name}: {}", self.name, &vi.t);
self.params.push((Some(name.clone()), vi));
self.locals.insert(name.clone(), vi);
Ok(())
}
}
// 再帰サブルーチン/型の推論を可能にするため、予め登録しておく
pub(crate) fn preregister(&mut self, block: &[ast::Expr]) -> TyCheckResult<()> {
// To allow forward references and recursive definitions
pub(crate) fn preregister(&mut self, block: &ast::Block) -> TyCheckResult<()> {
for expr in block.iter() {
if let ast::Expr::Def(def) = expr {
let id = Some(def.body.id);
let eval_body_t = || {
self.eval
.eval_const_block(&def.body.block, self)
.map(|c| enum_t(set![c]))
};
match &def.sig {
ast::Signature::Subr(sig) => {
let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() {
Some(self.instantiate_typespec(spec, PreRegister)?)
} else {
eval_body_t()
};
self.declare_sub(sig, opt_ret_t, id)?;
}
ast::Signature::Var(sig) if sig.is_const() => {
let t = if let Some(spec) = sig.t_spec.as_ref() {
Some(self.instantiate_typespec(spec, PreRegister)?)
} else {
eval_body_t()
};
self.declare_var(sig, t, id)?;
}
_ => {}
match expr {
ast::Expr::Def(def) => {
self.preregister_def(def)?;
}
ast::Expr::ClassDef(class_def) => {
self.preregister_def(&class_def.def)?;
}
_ => {}
}
}
Ok(())
}
pub(crate) fn preregister_def(&mut self, def: &ast::Def) -> TyCheckResult<()> {
let id = Some(def.body.id);
let __name__ = def.sig.ident().map(|i| i.inspect());
match &def.sig {
ast::Signature::Subr(sig) => {
if sig.is_const() {
let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) {
Ok(obj) => (obj.clone(), enum_t(set! {obj})),
Err(e) => {
return Err(e);
}
};
if let Some(spec) = sig.return_t_spec.as_ref() {
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?;
}
self.register_gen_const(def.sig.ident().unwrap(), obj);
} else {
let opt_ret_t = if let Some(spec) = sig.return_t_spec.as_ref() {
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
Some(spec_t)
} else {
None
};
self.declare_sub(sig, opt_ret_t, id)?;
}
}
ast::Signature::Var(sig) if sig.is_const() => {
let (obj, const_t) = match self.eval_const_block(&def.body.block, __name__) {
Ok(obj) => (obj.clone(), enum_t(set! {obj})),
Err(e) => {
return Err(e);
}
};
if let Some(spec) = sig.t_spec.as_ref() {
let spec_t = self.instantiate_typespec(spec, PreRegister)?;
self.sub_unify(&const_t, &spec_t, Some(def.body.loc()), None, None)?;
}
self.register_gen_const(sig.ident().unwrap(), obj);
}
_ => {}
}
Ok(())
}
/// e.g. .new
fn register_auto_impl(
&mut self,
name: &'static str,
t: Type,
muty: Mutability,
vis: Visibility,
) {
let name = VarName::from_static(name);
if self.locals.get(&name).is_some() {
panic!("already registered: {name}");
} else {
self.locals
.insert(name, VarInfo::new(t, muty, vis, VarKind::Auto, None));
}
}
/// e.g. ::__new__
fn register_fixed_auto_impl(
&mut self,
name: &'static str,
t: Type,
muty: Mutability,
vis: Visibility,
) {
let name = VarName::from_static(name);
if self.locals.get(&name).is_some() {
panic!("already registered: {name}");
} else {
self.locals
.insert(name, VarInfo::new(t, muty, vis, VarKind::FixedAuto, None));
}
}
fn _register_gen_decl(&mut self, name: VarName, t: Type, vis: Visibility) {
if self.decls.get(&name).is_some() {
panic!("already registered: {name}");
} else {
self.decls.insert(
name,
VarInfo::new(t, Immutable, vis, VarKind::Declared, None),
);
}
}
fn _register_gen_impl(&mut self, name: VarName, t: Type, muty: Mutability, vis: Visibility) {
if self.locals.get(&name).is_some() {
panic!("already registered: {name}");
} else {
let id = DefId(get_hash(&(&self.name, &name)));
self.locals
.insert(name, VarInfo::new(t, muty, vis, VarKind::Defined(id), None));
}
}
pub(crate) fn register_gen_const(&mut self, ident: &Identifier, obj: ValueObj) {
if self.rec_get_const_obj(ident.inspect()).is_some() {
panic!("already registered: {ident}");
} else {
match obj {
ValueObj::Type(t) => {
let gen = enum_unwrap!(t, TypeObj::Generated);
self.register_gen_type(gen);
}
// TODO: not all value objects are comparable
other => {
let id = DefId(get_hash(ident));
let vi = VarInfo::new(
enum_t(set! {other.clone()}),
Const,
ident.vis(),
VarKind::Defined(id),
None,
);
self.consts.insert(ident.name.clone(), other);
self.locals.insert(ident.name.clone(), vi);
}
}
}
}
fn register_gen_type(&mut self, gen: GenTypeObj) {
match gen.kind {
TypeKind::Class => {
if gen.t.is_monomorphic() {
let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect();
let mut ctx = Self::mono_class(gen.t.name(), vec![], super_traits, self.level);
let mut methods = Self::methods(gen.t.name(), self.level);
let require = gen.require_or_sup.typ().clone();
let new_t = func1(require, gen.t.clone());
methods.register_fixed_auto_impl("__new__", new_t.clone(), Immutable, Private);
// 必要なら、ユーザーが独自に上書きする
methods.register_auto_impl("new", new_t, Immutable, Public);
ctx.methods_list.push((gen.t.clone(), methods));
self.register_gen_mono_type(gen, ctx, Const);
} else {
todo!()
}
}
TypeKind::Subclass => {
if gen.t.is_monomorphic() {
let super_classes = vec![gen.require_or_sup.typ().clone()];
let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect();
let mut ctx =
Self::mono_class(gen.t.name(), super_classes, super_traits, self.level);
let mut methods = Self::methods(gen.t.name(), self.level);
if let Some(sup) = self.rec_get_const_obj(&gen.require_or_sup.typ().name()) {
let sup = enum_unwrap!(sup, ValueObj::Type);
let param_t = match sup {
TypeObj::Builtin(t) => t,
TypeObj::Generated(t) => t.require_or_sup.as_ref().typ(),
};
// `Super.Requirement := {x = Int}` and `Self.Additional := {y = Int}`
// => `Self.Requirement := {x = Int; y = Int}`
let param_t = if let Some(additional) = &gen.additional {
self.rec_intersection(&param_t, additional.typ())
} else {
param_t.clone()
};
let new_t = func1(param_t, gen.t.clone());
methods.register_fixed_auto_impl(
"__new__",
new_t.clone(),
Immutable,
Private,
);
// 必要なら、ユーザーが独自に上書きする
methods.register_auto_impl("new", new_t, Immutable, Public);
ctx.methods_list.push((gen.t.clone(), methods));
self.register_gen_mono_type(gen, ctx, Const);
} else {
todo!("super class not found")
}
} else {
todo!()
}
}
other => todo!("{other:?}"),
}
}
fn register_gen_mono_type(&mut self, gen: GenTypeObj, ctx: Self, muty: Mutability) {
// FIXME: not panic but error
// FIXME: recursive search
if self.mono_types.contains_key(&gen.t.name()) {
panic!("{} has already been registered", gen.t.name());
} else if self.rec_get_const_obj(&gen.t.name()).is_some() {
panic!("{} has already been registered as const", gen.t.name());
} else {
let t = gen.t.clone();
let meta_t = gen.meta_type();
let name = VarName::from_str(gen.t.name());
let id = DefId(get_hash(&(&self.name, &name)));
self.locals.insert(
name.clone(),
VarInfo::new(meta_t, muty, Private, VarKind::Defined(id), None),
);
self.consts
.insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen)));
for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) {
impls.push(TraitInstance::new(t.clone(), impl_trait.clone()));
} else {
self.trait_impls.insert(
impl_trait.name(),
vec![TraitInstance::new(t.clone(), impl_trait.clone())],
);
}
}
self.mono_types.insert(name, (t, ctx));
}
}
pub(crate) fn import_mod(
&mut self,
var_name: &VarName,

View file

@ -2,7 +2,7 @@
use erg_common::Str;
use erg_common::{enum_unwrap, set};
use erg_type::constructors::{func1, mono_q, poly_trait, quant, refinement};
use erg_type::constructors::{func1, mono_q, poly, quant, refinement};
use erg_type::typaram::TyParam;
use erg_type::{Predicate, TyBound, Type};
use Type::*;
@ -28,7 +28,7 @@ impl Context {
}
pub fn test_resolve_trait(&self) -> Result<(), ()> {
let t = poly_trait("Add", vec![TyParam::t(Nat)]);
let t = poly("Add", vec![TyParam::t(Nat)]);
match self.resolve_trait(t) {
Ok(Nat) => Ok(()),
Ok(other) => {
@ -46,7 +46,7 @@ impl Context {
pub fn test_resolve_trait_inner1(&self) -> Result<(), ()> {
let name = Str::ever("Add");
let params = vec![TyParam::t(Nat)];
let maybe_trait = poly_trait(name.clone(), params);
let maybe_trait = poly(name.clone(), params);
let mut min = Type::Obj;
for pair in self.rec_get_trait_impls(&name) {
if self.rec_supertype_of(&pair.sup_trait, &maybe_trait) {
@ -62,7 +62,7 @@ impl Context {
pub fn test_instantiation_and_generalization(&self) -> Result<(), ()> {
let t = mono_q("T");
let eq = poly_trait("Eq", vec![TyParam::t(t.clone())]);
let eq = poly("Eq", vec![TyParam::t(t.clone())]);
let bound = TyBound::subtype_of(t.clone(), eq.clone());
let bounds = set! {bound};
let unbound_t = func1(t.clone(), t.clone());

View file

@ -12,7 +12,7 @@ use erg_type::constructors::*;
use erg_type::free::{Constraint, Cyclicity, FreeKind, HasLevel};
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::{HasType, Predicate, SubrKind, TyBound, Type};
use erg_type::{HasType, Predicate, TyBound, Type};
use crate::context::{Context, Variance};
use crate::error::{TyCheckError, TyCheckResult};
@ -118,22 +118,6 @@ impl Context {
_ => assume_unreachable!(),
},
Subr(mut subr) => {
let kind = match subr.kind {
SubrKind::FuncMethod(self_t) => {
let t = self.generalize_t_inner(*self_t, bounds, lazy_inits);
SubrKind::fn_met(t)
}
SubrKind::ProcMethod { before, after } => {
let before = self.generalize_t_inner(*before, bounds, lazy_inits);
if let Some(after) = after {
let after = self.generalize_t_inner(*after, bounds, lazy_inits);
SubrKind::pr_met(before, Some(after))
} else {
SubrKind::pr_met(before, None)
}
}
other => other,
};
subr.non_default_params.iter_mut().for_each(|nd_param| {
*nd_param.typ_mut() =
self.generalize_t_inner(mem::take(nd_param.typ_mut()), bounds, lazy_inits);
@ -148,7 +132,7 @@ impl Context {
});
let return_t = self.generalize_t_inner(*subr.return_t, bounds, lazy_inits);
subr_t(
kind,
subr.kind,
subr.non_default_params,
subr.var_params.map(|x| *x),
subr.default_params,
@ -157,20 +141,20 @@ impl Context {
}
Callable { .. } => todo!(),
Ref(t) => ref_(self.generalize_t_inner(*t, bounds, lazy_inits)),
RefMut(t) => ref_mut(self.generalize_t_inner(*t, bounds, lazy_inits)),
PolyClass { name, mut params } => {
let params = params
.iter_mut()
.map(|p| self.generalize_tp(mem::take(p), bounds, lazy_inits))
.collect::<Vec<_>>();
poly_class(name, params)
RefMut { before, after } => {
let after = if let Some(after) = after {
Some(self.generalize_t_inner(*after, bounds, lazy_inits))
} else {
None
};
ref_mut(self.generalize_t_inner(*before, bounds, lazy_inits), after)
}
PolyTrait { name, mut params } => {
Poly { name, mut params } => {
let params = params
.iter_mut()
.map(|p| self.generalize_tp(mem::take(p), bounds, lazy_inits))
.collect::<Vec<_>>();
poly_trait(name, params)
poly(name, params)
}
// REVIEW: その他何でもそのまま通していいのか?
other => other,
@ -246,13 +230,13 @@ impl Context {
if cyclic.is_cyclic() {
return Err(TyCheckError::dummy_infer_error(fn_name!(), line!()));
}
Ok(Constraint::sandwiched(
Ok(Constraint::new_sandwiched(
self.deref_tyvar(sub)?,
self.deref_tyvar(sup)?,
cyclic,
))
}
Constraint::TypeOf(t) => Ok(Constraint::type_of(self.deref_tyvar(t)?)),
Constraint::TypeOf(t) => Ok(Constraint::new_type_of(self.deref_tyvar(t)?)),
_ => unreachable!(),
}
}
@ -269,7 +253,7 @@ impl Context {
// ?T(:> Never, <: Nat)[n] => Nat
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
let constraint = fv.crack_constraint();
let (sub_t, super_t) = constraint.get_sub_sup_type().unwrap();
let (sub_t, super_t) = constraint.get_sub_sup().unwrap();
if self.rec_same_type_of(sub_t, super_t) {
self.unify(sub_t, super_t, None, None)?;
let t = if sub_t == &Never {
@ -280,7 +264,7 @@ impl Context {
drop(constraint);
fv.link(&t);
self.deref_tyvar(Type::FreeVar(fv))
} else if self.level == 0 || self.level <= fv.level().unwrap() {
} else if self.level <= fv.level().unwrap() {
let new_t = if sub_t == &Never {
super_t.clone()
} else {
@ -313,32 +297,14 @@ impl Context {
let t = fv.unwrap_linked();
self.deref_tyvar(t)
}
Type::PolyClass { name, mut params } => {
Type::Poly { name, mut params } => {
for param in params.iter_mut() {
*param = self.deref_tp(mem::take(param))?;
}
Ok(Type::PolyClass { name, params })
}
Type::PolyTrait { name, mut params } => {
for param in params.iter_mut() {
*param = self.deref_tp(mem::take(param))?;
}
let t = Type::PolyTrait { name, params };
let t = Type::Poly { name, params };
self.resolve_trait(t)
}
Type::Subr(mut subr) => {
match &mut subr.kind {
SubrKind::FuncMethod(t) => {
*t = Box::new(self.deref_tyvar(mem::take(t))?);
}
SubrKind::ProcMethod { before, after } => {
*before = Box::new(self.deref_tyvar(mem::take(before))?);
if let Some(after) = after {
*after = Box::new(self.deref_tyvar(mem::take(after))?);
}
}
_ => {}
}
for param in subr.non_default_params.iter_mut() {
*param.typ_mut() = self.deref_tyvar(mem::take(param.typ_mut()))?;
}
@ -355,9 +321,14 @@ impl Context {
let t = self.deref_tyvar(*t)?;
Ok(ref_(t))
}
Type::RefMut(t) => {
let t = self.deref_tyvar(*t)?;
Ok(ref_mut(t))
Type::RefMut { before, after } => {
let before = self.deref_tyvar(*before)?;
let after = if let Some(after) = after {
Some(self.deref_tyvar(*after)?)
} else {
None
};
Ok(ref_mut(before, after))
}
Type::Callable { .. } => todo!(),
Type::Record(mut rec) => {
@ -400,7 +371,7 @@ impl Context {
self.deref_expr_t(&mut subscr.obj)?;
self.deref_expr_t(&mut subscr.index)?;
}
hir::Accessor::Local(_) | hir::Accessor::Public(_) => {}
hir::Accessor::Ident(_) => {}
}
Ok(())
}
@ -490,6 +461,29 @@ impl Context {
}
Ok(())
}
hir::Expr::ClassDef(type_def) => {
for def in type_def.public_methods.iter_mut() {
match &mut def.sig {
hir::Signature::Var(var) => {
var.t = self.deref_tyvar(mem::take(&mut var.t))?;
}
hir::Signature::Subr(subr) => {
subr.t = self.deref_tyvar(mem::take(&mut subr.t))?;
}
}
for chunk in def.body.block.iter_mut() {
self.deref_expr_t(chunk)?;
}
}
Ok(())
}
hir::Expr::AttrDef(attr_def) => {
// REVIEW: attr_def.attr is not dereferenced
for chunk in attr_def.block.iter_mut() {
self.deref_expr_t(chunk)?;
}
Ok(())
}
}
}
@ -523,7 +517,7 @@ impl Context {
(TyParam::FreeVar(fv), tp) | (tp, TyParam::FreeVar(fv)) => {
match &*fv.borrow() {
FreeKind::Linked(l) | FreeKind::UndoableLinked { t: l, .. } => {
return self.unify_tp(l, tp, lhs_variance, allow_divergence)
return self.unify_tp(l, tp, lhs_variance, allow_divergence);
}
FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => {}
} // &fv is dropped
@ -534,11 +528,11 @@ impl Context {
.get_type()
.unwrap()
.clone(); // fvを参照しないよいにcloneする(あとでborrow_mutするため)
let tp_t = self.eval.get_tp_t(tp, self)?;
let tp_t = self.get_tp_t(tp)?;
if self.rec_supertype_of(&fv_t, &tp_t) {
// 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md)
if fv.level() < Some(self.level) {
let new_constraint = Constraint::subtype_of(tp_t, Cyclicity::Not);
let new_constraint = Constraint::new_subtype_of(tp_t, Cyclicity::Not);
if self.is_sub_constraint_of(
fv.borrow().constraint().unwrap(),
&new_constraint,
@ -553,7 +547,7 @@ impl Context {
} else if allow_divergence
&& (self.eq_tp(tp, &TyParam::value(Inf))
|| self.eq_tp(tp, &TyParam::value(NegInf)))
&& self.rec_subtype_of(&fv_t, &trait_("Num"))
&& self.rec_subtype_of(&fv_t, &mono("Num"))
{
fv.link(tp);
Ok(())
@ -730,7 +724,7 @@ impl Context {
(Type::FreeVar(fv), t) | (t, Type::FreeVar(fv)) => {
match &mut *fv.borrow_mut() {
FreeKind::Linked(l) | FreeKind::UndoableLinked { t: l, .. } => {
return self.unify(l, t, lhs_loc, rhs_loc)
return self.unify(l, t, lhs_loc, rhs_loc);
}
FreeKind::Unbound {
lev, constraint, ..
@ -740,7 +734,7 @@ impl Context {
} => {
t.update_level(*lev);
// TODO: constraint.type_of()
if let Some(sup) = constraint.get_super_type_mut() {
if let Some(sup) = constraint.get_super_mut() {
// 下のような場合は制約を弱化する
// unify(?T(<: Nat), Int): (?T(<: Int))
if self.rec_subtype_of(sup, t) {
@ -751,7 +745,7 @@ impl Context {
}
}
} // &fv is dropped
let new_constraint = Constraint::subtype_of(t.clone(), fv.cyclicity());
let new_constraint = Constraint::new_subtype_of(t.clone(), fv.cyclicity());
// 外部未連携型変数の場合、linkしないで制約を弱めるだけにする(see compiler/inference.md)
// fv == ?T(: Type)の場合は?T(<: U)にする
if fv.level() < Some(self.level) {
@ -794,10 +788,7 @@ impl Context {
let lhs_t = self.into_refinement(l.clone());
self.unify(&Type::Refinement(lhs_t), rhs_t, lhs_loc, rhs_loc)
}
(Type::Subr(ls), Type::Subr(rs)) if ls.kind.same_kind_as(&rs.kind) => {
if let (Some(l), Some(r)) = (ls.kind.self_t(), rs.kind.self_t()) {
self.unify(l, r, lhs_loc, rhs_loc)?;
}
(Type::Subr(ls), Type::Subr(rs)) if ls.kind == rs.kind => {
for (l, r) in ls
.non_default_params
.iter()
@ -821,18 +812,38 @@ impl Context {
}
self.unify(&ls.return_t, &rs.return_t, lhs_loc, rhs_loc)
}
(Type::Ref(l), Type::Ref(r)) | (Type::RefMut(l), Type::RefMut(r)) => {
self.unify(l, r, lhs_loc, rhs_loc)
(Type::Ref(l), Type::Ref(r)) => self.unify(l, r, lhs_loc, rhs_loc),
(
Type::RefMut {
before: lbefore,
after: lafter,
},
Type::RefMut {
before: rbefore,
after: rafter,
},
) => {
self.unify(lbefore, rbefore, lhs_loc, rhs_loc)?;
match (lafter, rafter) {
(Some(lafter), Some(rafter)) => {
self.unify(lafter, rafter, lhs_loc, rhs_loc)?;
}
(None, None) => {}
_ => todo!(),
}
Ok(())
}
(Type::Ref(l), r) => self.unify(l, r, lhs_loc, rhs_loc),
// REVIEW:
(Type::Ref(l), r) | (Type::RefMut(l), r) => self.unify(l, r, lhs_loc, rhs_loc),
(l, Type::Ref(r)) | (l, Type::RefMut(r)) => self.unify(l, r, lhs_loc, rhs_loc),
(Type::RefMut { before, .. }, r) => self.unify(before, r, lhs_loc, rhs_loc),
(l, Type::Ref(r)) => self.unify(l, r, lhs_loc, rhs_loc),
(l, Type::RefMut { before, .. }) => self.unify(l, before, lhs_loc, rhs_loc),
(
Type::PolyClass {
Type::Poly {
name: ln,
params: lps,
},
Type::PolyClass {
Type::Poly {
name: rn,
params: rps,
},
@ -852,32 +863,7 @@ impl Context {
}
Ok(())
}
(
Type::PolyTrait {
name: ln,
params: lps,
},
Type::PolyTrait {
name: rn,
params: rps,
},
) => {
if ln != rn {
return Err(TyCheckError::unification_error(
line!() as usize,
lhs_t,
rhs_t,
lhs_loc,
rhs_loc,
self.caused_by(),
));
}
for (l, r) in lps.iter().zip(rps.iter()) {
self.unify_tp(l, r, None, false)?;
}
Ok(())
}
(Type::PolyClass { name: _, params: _ }, _r) => {
(Type::Poly { name: _, params: _ }, _r) => {
todo!()
}
(l, r) => Err(TyCheckError::unification_error(
@ -908,50 +894,44 @@ impl Context {
(l, Type::FreeVar(fv)) if fv.is_linked() => {
self.reunify(l, &fv.crack(), bef_loc, aft_loc)
}
(Type::Ref(l), Type::Ref(r)) | (Type::RefMut(l), Type::RefMut(r)) => {
self.reunify(l, r, bef_loc, aft_loc)
}
// REVIEW:
(Type::Ref(l), r) | (Type::RefMut(l), r) => self.reunify(l, r, bef_loc, aft_loc),
(l, Type::Ref(r)) | (l, Type::RefMut(r)) => self.reunify(l, r, bef_loc, aft_loc),
(Type::Ref(l), Type::Ref(r)) => self.reunify(l, r, bef_loc, aft_loc),
(
Type::PolyClass {
name: ln,
params: lps,
Type::RefMut {
before: lbefore,
after: lafter,
},
Type::PolyClass {
name: rn,
params: rps,
Type::RefMut {
before: rbefore,
after: rafter,
},
) => {
if ln != rn {
let before_t = poly_class(ln.clone(), lps.clone());
return Err(TyCheckError::re_unification_error(
line!() as usize,
&before_t,
after_t,
bef_loc,
aft_loc,
self.caused_by(),
));
}
for (l, r) in lps.iter().zip(rps.iter()) {
self.reunify_tp(l, r)?;
self.reunify(lbefore, rbefore, bef_loc, aft_loc)?;
match (lafter, rafter) {
(Some(lafter), Some(rafter)) => {
self.reunify(lafter, rafter, bef_loc, aft_loc)?;
}
(None, None) => {}
_ => todo!(),
}
Ok(())
}
(Type::Ref(l), r) => self.reunify(l, r, bef_loc, aft_loc),
// REVIEW:
(Type::RefMut { before, .. }, r) => self.reunify(before, r, bef_loc, aft_loc),
(l, Type::Ref(r)) => self.reunify(l, r, bef_loc, aft_loc),
(l, Type::RefMut { before, .. }) => self.reunify(l, before, bef_loc, aft_loc),
(
Type::PolyTrait {
Type::Poly {
name: ln,
params: lps,
},
Type::PolyTrait {
Type::Poly {
name: rn,
params: rps,
},
) => {
if ln != rn {
let before_t = poly_trait(ln.clone(), lps.clone());
let before_t = poly(ln.clone(), lps.clone());
return Err(TyCheckError::re_unification_error(
line!() as usize,
&before_t,
@ -987,7 +967,7 @@ impl Context {
/// sub_unify({I: Int | I == 0}, ?T(<: Ord)): (/* OK */)
/// sub_unify(Int, ?T(:> Nat)): (?T :> Int)
/// sub_unify(Nat, ?T(:> Int)): (/* OK */)
/// sub_unify(Nat, Add(?R, ?O)): (?R => Nat, ?O => Nat)
/// sub_unify(Nat, Add(?R)): (?R => Nat, Nat.AddO => Nat)
/// sub_unify([?T; 0], Mutate): (/* OK */)
/// ```
pub(crate) fn sub_unify(
@ -1029,20 +1009,29 @@ impl Context {
// lfvのsupは縮小可能(minを取る)、rfvのsubは拡大可能(unionを取る)
// sub_unify(?T[0](:> Never, <: Int), ?U[1](:> Never, <: Nat)): (/* ?U[1] --> ?T[0](:> Never, <: Nat))
// sub_unify(?T[1](:> Never, <: Nat), ?U[0](:> Never, <: Int)): (/* ?T[1] --> ?U[0](:> Never, <: Nat))
// sub_unify(?T[0](:> Never, <: Str), ?U[1](:> Never, <: Int)): (/* Error */)
// sub_unify(?T[0](:> Never, <: Str), ?U[1](:> Never, <: Int)): (?T[0](:> Never, <: Str and Int) --> Error!)
// sub_unify(?T[0](:> Int, <: Add()), ?U[1](:> Never, <: Mul())): (?T[0](:> Int, <: Add() and Mul()))
// sub_unify(?T[0](:> Str, <: Obj), ?U[1](:> Int, <: Obj)): (/* ?U[1] --> ?T[0](:> Str or Int) */)
(Type::FreeVar(lfv), Type::FreeVar(rfv))
if lfv.constraint_is_sandwiched() && rfv.constraint_is_sandwiched() =>
{
let (lsub, lsup) = lfv.crack_bound_types().unwrap();
let (lsub, lsup) = lfv.get_bound_types().unwrap();
let l_cyc = lfv.cyclicity();
let (rsub, rsup) = rfv.crack_bound_types().unwrap();
let (rsub, rsup) = rfv.get_bound_types().unwrap();
let r_cyc = rfv.cyclicity();
let cyclicity = l_cyc.combine(r_cyc);
let new_constraint = if let Some(min) = self.min(&lsup, &rsup) {
Constraint::sandwiched(self.rec_union(&lsub, &rsub), min.clone(), cyclicity)
let intersec = self.rec_intersection(&lsup, &rsup);
let new_constraint = if intersec != Type::Never {
Constraint::new_sandwiched(self.rec_union(&lsub, &rsub), intersec, cyclicity)
} else {
todo!()
return Err(TyCheckError::subtyping_error(
line!() as usize,
maybe_sub,
maybe_sup,
sub_loc,
sup_loc,
self.caused_by(),
));
};
if lfv.level().unwrap() <= rfv.level().unwrap() {
lfv.update_constraint(new_constraint);
@ -1067,7 +1056,7 @@ impl Context {
// sub = max(l, sub) if max exists
// * sub_unify(Nat, ?T(:> Int, <: _)): (/* OK */)
// * sub_unify(Int, ?T(:> Nat, <: Obj)): (?T(:> Int, <: Obj))
// * sub_unify(Nat, ?T(:> Never, <: Add(?R, ?O))): (?T(:> Nat, <: Add(?R, ?O))
// * sub_unify(Nat, ?T(:> Never, <: Add(?R))): (?T(:> Nat, <: Add(?R))
// sub = union(l, sub) if max does not exist
// * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj))
// * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat))
@ -1089,16 +1078,16 @@ impl Context {
}
if let Some(new_sub) = self.rec_max(maybe_sub, sub) {
*constraint =
Constraint::sandwiched(new_sub.clone(), mem::take(sup), *cyclicity);
Constraint::new_sandwiched(new_sub.clone(), mem::take(sup), *cyclicity);
} else {
let new_sub = self.rec_union(maybe_sub, sub);
*constraint = Constraint::sandwiched(new_sub, mem::take(sup), *cyclicity);
*constraint = Constraint::new_sandwiched(new_sub, mem::take(sup), *cyclicity);
}
}
// sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */)
Constraint::TypeOf(ty) => {
if self.rec_supertype_of(&Type, ty) {
*constraint = Constraint::supertype_of(maybe_sub.clone(), Cyclicity::Not);
*constraint = Constraint::new_supertype_of(maybe_sub.clone(), Cyclicity::Not);
} else {
todo!()
}
@ -1138,16 +1127,16 @@ impl Context {
}
if let Some(new_sup) = self.rec_min(sup, maybe_sup) {
*constraint =
Constraint::sandwiched(mem::take(sub), new_sup.clone(), *cyclicity);
Constraint::new_sandwiched(mem::take(sub), new_sup.clone(), *cyclicity);
} else {
let new_sup = self.rec_union(sup, maybe_sup);
*constraint = Constraint::sandwiched(mem::take(sub), new_sup, *cyclicity);
*constraint = Constraint::new_sandwiched(mem::take(sub), new_sup, *cyclicity);
}
}
// sub_unify(?T(: Type), Int): (?T(<: Int))
Constraint::TypeOf(ty) => {
if self.rec_supertype_of(&Type, ty) {
*constraint = Constraint::subtype_of(maybe_sup.clone(), Cyclicity::Not);
*constraint = Constraint::new_subtype_of(maybe_sup.clone(), Cyclicity::Not);
} else {
todo!()
}
@ -1159,6 +1148,23 @@ impl Context {
return Ok(());
}
(Type::FreeVar(_fv), _r) => todo!(),
(Type::Record(lrec), Type::Record(rrec)) => {
for (k, l) in lrec.iter() {
if let Some(r) = rrec.get(k) {
self.sub_unify(l, r, sub_loc, sup_loc, param_name)?;
} else {
return Err(TyCheckError::subtyping_error(
line!() as usize,
maybe_sub,
maybe_sup,
sub_loc,
sup_loc,
self.caused_by(),
));
}
}
return Ok(());
}
(Type::Subr(lsub), Type::Subr(rsub)) => {
for lpt in lsub.default_params.iter() {
if let Some(rpt) = rsub.default_params.iter().find(|rpt| rpt.name() == lpt.name()) {
@ -1171,6 +1177,14 @@ impl Context {
self.unify(&lsub.return_t, &rsub.return_t, sub_loc, sup_loc)?;
return Ok(());
}
(_, Type::Ref(t)) => {
self.unify(maybe_sub, t, sub_loc, sup_loc)?;
return Ok(());
}
(_, Type::RefMut{ before, .. }) => {
self.unify(maybe_sub, before, sub_loc, sup_loc)?;
return Ok(());
}
(Type::MonoProj { .. }, _) => todo!(),
(_, Type::MonoProj { .. }) => todo!(),
(Refinement(_), Refinement(_)) => todo!(),

View file

@ -9,7 +9,7 @@ use erg_common::Str;
use Visibility::*;
use crate::error::{EffectError, EffectErrors, EffectResult};
use crate::hir::{Accessor, Def, Expr, Signature, HIR};
use crate::hir::{Accessor, Array, Def, Expr, Signature, Tuple, HIR};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum BlockKind {
@ -84,6 +84,12 @@ impl SideEffectChecker {
Expr::Def(def) => {
self.check_def(def);
}
Expr::ClassDef(type_def) => {
// TODO: grow
for def in type_def.public_methods.iter() {
self.check_def(def);
}
}
Expr::Call(call) => {
for parg in call.args.pos_args.iter() {
self.check_expr(&parg.expr);
@ -174,6 +180,31 @@ impl SideEffectChecker {
Expr::Def(def) => {
self.check_def(def);
}
Expr::ClassDef(type_def) => {
for def in type_def.public_methods.iter() {
self.check_def(def);
}
}
Expr::Array(array) => match array {
Array::Normal(arr) => {
for arg in arr.elems.pos_args.iter() {
self.check_expr(&arg.expr);
}
}
other => todo!("{other}"),
},
Expr::Tuple(tuple) => match tuple {
Tuple::Normal(tup) => {
for arg in tup.elems.pos_args.iter() {
self.check_expr(&arg.expr);
}
}
},
Expr::Record(record) => {
for attr in record.attrs.iter() {
self.check_def(attr);
}
}
// 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => {
if (self.is_procedural(&call.obj)
@ -228,10 +259,10 @@ impl SideEffectChecker {
Expr::Lambda(lambda) => lambda.is_procedural(),
// 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => self.is_procedural(&call.obj),
Expr::Accessor(Accessor::Local(local)) => local.name.is_procedural(),
Expr::Accessor(Accessor::Ident(ident)) => ident.name.is_procedural(),
// procedural: x.y! (e.g. Array.sample!)
// !procedural: !x.y
Expr::Accessor(Accessor::Attr(attr)) => attr.name.is_procedural(),
Expr::Accessor(Accessor::Attr(attr)) => attr.ident.is_procedural(),
Expr::Accessor(_) => todo!(),
_ => false,
}

View file

@ -255,6 +255,10 @@ impl TyCheckError {
Self { core, caused_by }
}
pub fn dummy(errno: usize) -> Self {
Self::new(ErrorCore::dummy(errno), "".into())
}
pub fn unreachable(fn_name: &str, line: u32) -> Self {
Self::new(ErrorCore::unreachable(fn_name, line), "".into())
}
@ -327,6 +331,30 @@ impl TyCheckError {
)
}
pub fn duplicate_definition_error(
errno: usize,
loc: Location,
caused_by: Str,
name: &str,
) -> Self {
let name = readable_name(name);
Self::new(
ErrorCore::new(
errno,
NameError,
loc,
switch_lang!(
"japanese" => format!("{name}は既に定義されています"),
"simplified_chinese" => format!("{name}已定义"),
"traditional_chinese" => format!("{name}已定義"),
"english" => format!("{name} is already defined"),
),
Option::<Str>::None,
),
caused_by,
)
}
pub fn violate_decl_error(
errno: usize,
loc: Location,
@ -521,10 +549,10 @@ impl TyCheckError {
TypeError,
loc,
switch_lang!(
"japanese" => format!("{name}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}"),
"simplified_chinese" => format!("{name}的类型不匹配:\n预期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"traditional_chinese" => format!("{name}的類型不匹配:\n預期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"english" => format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
"japanese" => format!("{YELLOW}{name}{RESET}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}"),
"simplified_chinese" => format!("{YELLOW}{name}{RESET}的类型不匹配:\n预期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"traditional_chinese" => format!("{YELLOW}{name}{RESET}的類型不匹配:\n預期:{GREEN}{expect}{RESET}\n但找到:{RED}{found}{RESET}"),
"english" => format!("the type of {YELLOW}{name}{RESET} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"),
),
hint,
),
@ -657,10 +685,10 @@ impl TyCheckError {
AssignError,
loc,
switch_lang!(
"japanese" => format!("定数{name}には再代入できません"),
"simplified_chinese" => format!("不能为不可变变量{name}分配两次"),
"traditional_chinese" => format!("不能為不可變變量{name}分配兩次"),
"english" => format!("cannot assign twice to the immutable variable {name}"),
"japanese" => format!("変数{name}に再代入されています"),
"simplified_chinese" => format!("不能为变量{name}分配两次"),
"traditional_chinese" => format!("不能為變量{name}分配兩次"),
"english" => format!("cannot assign twice to the variable {name}"),
),
None,
),
@ -1006,7 +1034,7 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
Self::new(
ErrorCore::new(
errno,
NameError,
VisibilityError,
loc,
switch_lang!(
"japanese" => format!("{RED}{name}{RESET}{visibility}変数です"),
@ -1019,6 +1047,79 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
caused_by,
)
}
pub fn not_const_expr(errno: usize, loc: Location, caused_by: Str) -> Self {
Self::new(
ErrorCore::new(
errno,
NotConstExpr,
loc,
switch_lang!(
"japanese" => "定数式ではありません",
"simplified_chinese" => "不是常量表达式",
"traditional_chinese" => "不是常量表達式",
"english" => "not a constant expression",
),
None,
),
caused_by,
)
}
pub fn override_error<S: Into<Str>>(
errno: usize,
name: &str,
name_loc: Location,
superclass: &Type,
caused_by: S,
) -> Self {
Self::new(
ErrorCore::new(
errno,
NameError,
name_loc,
switch_lang!(
"japanese" => format!(
"{RED}{name}{RESET}は{YELLOW}{superclass}{RESET}で既に定義されています",
),
"simplified_chinese" => format!(
"{RED}{name}{RESET}已在{YELLOW}{superclass}{RESET}中定义",
),
"traditional_chinese" => format!(
"{RED}{name}{RESET}已在{YELLOW}{superclass}{RESET}中定義",
),
"english" => format!(
"{RED}{name}{RESET} is already defined in {YELLOW}{superclass}{RESET}",
),
),
Some(switch_lang!(
"japanese" => "デフォルトでオーバーライドはできません(`Override`デコレータを使用してください)",
"simplified_chinese" => "默认不可重写(请使用`Override`装饰器)",
"traditional_chinese" => "默認不可重寫(請使用`Override`裝飾器)",
"english" => "cannot override by default (use `Override` decorator)",
).into()),
),
caused_by.into(),
)
}
pub fn inheritance_error(errno: usize, class: String, loc: Location, caused_by: Str) -> Self {
Self::new(
ErrorCore::new(
errno,
InheritanceError,
loc,
switch_lang!(
"japanese" => format!("{class}は継承できません"),
"simplified_chinese" => format!("{class}不可继承"),
"traditional_chinese" => format!("{class}不可繼承"),
"english" => format!("{class} is not inheritable"),
),
None,
),
caused_by,
)
}
}
#[derive(Debug)]

View file

@ -11,16 +11,16 @@ use erg_common::{
impl_stream_for_wrapper,
};
use erg_parser::ast::{fmt_lines, DefId, Identifier, Params};
use erg_parser::ast::{fmt_lines, DefId, Params, TypeSpec, VarName};
use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{array, tuple};
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::value::{TypeKind, ValueObj};
use erg_type::{impl_t, impl_t_for_enum, HasType, Type};
use crate::context::eval::type_from_token_kind;
use crate::error::readable_name;
use crate::eval::type_from_token_kind;
#[derive(Debug, Clone)]
pub struct Literal {
@ -119,6 +119,7 @@ impl KwArg {
#[derive(Debug, Clone)]
pub struct Args {
pub pos_args: Vec<PosArg>,
pub var_args: Option<Box<PosArg>>,
pub kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
}
@ -128,6 +129,10 @@ impl NestedDisplay for Args {
if !self.pos_args.is_empty() {
fmt_lines(self.pos_args.iter(), f, level)?;
}
if let Some(var_args) = &self.var_args {
writeln!(f, "...")?;
var_args.fmt_nest(f, level)?;
}
if !self.kw_args.is_empty() {
fmt_lines(self.kw_args.iter(), f, level)?;
}
@ -139,6 +144,7 @@ impl From<Vec<Expr>> for Args {
fn from(exprs: Vec<Expr>) -> Self {
Self {
pos_args: exprs.into_iter().map(PosArg::new).collect(),
var_args: None,
kw_args: Vec::new(),
paren: None,
}
@ -167,30 +173,33 @@ impl Locational for Args {
// impl_stream!(Args, KwArg, kw_args);
impl Args {
pub const fn new(
pub fn new(
pos_args: Vec<PosArg>,
var_args: Option<PosArg>,
kw_args: Vec<KwArg>,
paren: Option<(Token, Token)>,
) -> Self {
Self {
pos_args,
var_args: var_args.map(Box::new),
kw_args,
paren,
}
}
pub const fn empty() -> Self {
Self::new(vec![], vec![], None)
pub fn empty() -> Self {
Self::new(vec![], None, vec![], None)
}
#[inline]
pub fn len(&self) -> usize {
self.pos_args.len() + self.kw_args.len()
let var_argc = if self.var_args.is_none() { 0 } else { 1 };
self.pos_args.len() + var_argc + self.kw_args.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.pos_args.is_empty() && self.kw_args.is_empty()
self.pos_args.is_empty() && self.var_args.is_none() && self.kw_args.is_empty()
}
#[inline]
@ -243,86 +252,89 @@ impl Args {
.map(|a| &a.expr)
}
}
}
/// represents local variables
#[derive(Debug, Clone)]
pub struct Local {
pub name: Token,
/// オブジェクト自身の名前
__name__: Option<Str>,
pub(crate) t: Type,
}
impl NestedDisplay for Local {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
let __name__ = if let Some(__name__) = self.__name__() {
format!("(__name__ = {__name__})")
pub fn remove_left_or_key(&mut self, key: &str) -> Option<Expr> {
if !self.pos_args.is_empty() {
Some(self.pos_args.remove(0).expr)
} else {
"".to_string()
};
write!(f, "{} (: {}){}", self.name.content, self.t, __name__)
}
}
impl_display_from_nested!(Local);
impl_t!(Local);
impl Locational for Local {
#[inline]
fn loc(&self) -> Location {
self.name.loc()
}
}
impl Local {
pub const fn new(name: Token, __name__: Option<Str>, t: Type) -> Self {
Self { name, __name__, t }
if let Some(pos) = self
.kw_args
.iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(self.kw_args.remove(pos).expr)
} else {
None
}
}
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
#[inline]
pub fn inspect(&self) -> &Str {
&self.name.content
}
pub const fn __name__(&self) -> Option<&Str> {
self.__name__.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct Public {
pub dot: Token,
pub name: Token,
/// オブジェクト自身の名前
__name__: Option<Str>,
t: Type,
}
impl NestedDisplay for Public {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
let __name__ = if let Some(__name__) = self.__name__() {
format!("(__name__ = {__name__})")
pub fn get_left_or_key(&self, key: &str) -> Option<&Expr> {
if !self.pos_args.is_empty() {
Some(&self.pos_args.get(0)?.expr)
} else {
"".to_string()
};
write!(f, ".{} (: {}){}", self.name.content, self.t, __name__)
if let Some(pos) = self
.kw_args
.iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(&self.kw_args.get(pos)?.expr)
} else {
None
}
}
}
}
impl_display_from_nested!(Public);
impl_t!(Public);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Identifier {
pub dot: Option<Token>,
pub name: VarName,
pub __name__: Option<Str>,
pub t: Type,
}
impl Locational for Public {
#[inline]
impl NestedDisplay for Identifier {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
match &self.dot {
Some(_dot) => {
write!(f, ".{}", self.name)?;
}
None => {
write!(f, "::{}", self.name)?;
}
}
if let Some(__name__) = &self.__name__ {
write!(f, "(__name__: {})", __name__)?;
}
if self.t != Type::Uninited {
write!(f, "(: {})", self.t)?;
}
Ok(())
}
}
impl_display_from_nested!(Identifier);
impl_t!(Identifier);
impl Locational for Identifier {
fn loc(&self) -> Location {
Location::concat(&self.dot, &self.name)
if let Some(dot) = &self.dot {
Location::concat(dot, &self.name)
} else {
self.name.loc()
}
}
}
impl Public {
pub const fn new(dot: Token, name: Token, __name__: Option<Str>, t: Type) -> Self {
impl From<&Identifier> for Field {
fn from(ident: &Identifier) -> Self {
Self::new(ident.vis(), ident.inspect().clone())
}
}
impl Identifier {
pub const fn new(dot: Option<Token>, name: VarName, __name__: Option<Str>, t: Type) -> Self {
Self {
dot,
name,
@ -331,39 +343,75 @@ impl Public {
}
}
// &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで
#[inline]
pub fn inspect(&self) -> &Str {
&self.name.content
pub fn public(name: &'static str) -> Self {
Self::bare(
Some(Token::from_str(TokenKind::Dot, ".")),
VarName::from_static(name),
)
}
pub const fn __name__(&self) -> Option<&Str> {
self.__name__.as_ref()
pub fn private(name: Str) -> Self {
Self::bare(None, VarName::from_str(name))
}
pub fn private_with_line(name: Str, line: usize) -> Self {
Self::bare(None, VarName::from_str_and_line(name, line))
}
pub fn public_with_line(dot: Token, name: Str, line: usize) -> Self {
Self::bare(Some(dot), VarName::from_str_and_line(name, line))
}
pub const fn bare(dot: Option<Token>, name: VarName) -> Self {
Self::new(dot, name, None, Type::Uninited)
}
pub fn is_const(&self) -> bool {
self.name.is_const()
}
pub const fn vis(&self) -> Visibility {
match &self.dot {
Some(_) => Visibility::Public,
None => Visibility::Private,
}
}
pub const fn inspect(&self) -> &Str {
&self.name.inspect()
}
pub fn is_procedural(&self) -> bool {
self.name.is_procedural()
}
}
#[derive(Debug, Clone)]
pub struct Attribute {
pub obj: Box<Expr>,
pub name: Token,
pub ident: Identifier,
t: Type,
}
impl NestedDisplay for Attribute {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
write!(f, "({}).{}(: {})", self.obj, self.name.content, self.t)
if self.t != Type::Uninited {
write!(f, "({}){}(: {})", self.obj, self.ident, self.t)
} else {
write!(f, "({}){}", self.obj, self.ident)
}
}
}
impl_display_from_nested!(Attribute);
impl_locational!(Attribute, obj, name);
impl_locational!(Attribute, obj, ident);
impl_t!(Attribute);
impl Attribute {
pub fn new(obj: Expr, name: Token, t: Type) -> Self {
pub fn new(obj: Expr, ident: Identifier, t: Type) -> Self {
Self {
obj: Box::new(obj),
name,
ident,
t,
}
}
@ -426,55 +474,64 @@ impl Subscript {
#[derive(Debug, Clone)]
pub enum Accessor {
Local(Local),
Public(Public),
Ident(Identifier),
Attr(Attribute),
TupleAttr(TupleAttribute),
Subscr(Subscript),
}
impl_nested_display_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_nested_display_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_display_from_nested!(Accessor);
impl_locational_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_t_for_enum!(Accessor; Local, Public, Attr, TupleAttr, Subscr);
impl_locational_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl_t_for_enum!(Accessor; Ident, Attr, TupleAttr, Subscr);
impl Accessor {
pub const fn local(symbol: Token, t: Type) -> Self {
Self::Local(Local::new(symbol, None, t))
pub fn private_with_line(name: Str, line: usize) -> Self {
Self::Ident(Identifier::private_with_line(name, line))
}
pub const fn public(dot: Token, name: Token, t: Type) -> Self {
Self::Public(Public::new(dot, name, None, t))
pub fn public_with_line(name: Str, line: usize) -> Self {
Self::Ident(Identifier::public_with_line(Token::dummy(), name, line))
}
pub fn attr(obj: Expr, name: Token, t: Type) -> Self {
Self::Attr(Attribute::new(obj, name, t))
pub const fn private(name: Token, t: Type) -> Self {
Self::Ident(Identifier::new(None, VarName::new(name), None, t))
}
pub fn attr(obj: Expr, ident: Identifier, t: Type) -> Self {
Self::Attr(Attribute::new(obj, ident, t))
}
pub fn subscr(obj: Expr, index: Expr, t: Type) -> Self {
Self::Subscr(Subscript::new(obj, index, t))
}
pub fn var_full_name(&self) -> Option<String> {
pub fn show(&self) -> String {
match self {
Self::Local(local) => Some(readable_name(local.inspect()).to_string()),
Self::Attr(attr) => attr
.obj
.var_full_name()
.map(|n| n + "." + readable_name(attr.name.inspect())),
Self::TupleAttr(t_attr) => t_attr
.obj
.var_full_name()
.map(|n| n + "." + t_attr.index.token.inspect()),
Self::Subscr(_) | Self::Public(_) => todo!(),
Self::Ident(ident) => readable_name(ident.inspect()).to_string(),
Self::Attr(attr) => {
attr.obj
.show_acc()
.unwrap_or_else(|| attr.obj.ref_t().to_string())
+ "." // TODO: visibility
+ readable_name(attr.ident.inspect())
}
Self::TupleAttr(t_attr) => {
t_attr
.obj
.show_acc()
.unwrap_or_else(|| t_attr.obj.ref_t().to_string())
+ "."
+ t_attr.index.token.inspect()
}
Self::Subscr(_) => todo!(),
}
}
// 参照するオブジェクト自体が持っている固有の名前
// 参照するオブジェクト自体が持っている固有の名前(クラス、モジュールなど)
pub fn __name__(&self) -> Option<&str> {
match self {
Self::Local(local) => local.__name__().map(|s| &s[..]),
Self::Public(public) => public.__name__().map(|s| &s[..]),
Self::Ident(ident) => ident.__name__.as_ref().map(|s| &s[..]),
_ => None,
}
}
@ -688,6 +745,15 @@ impl NestedDisplay for RecordAttrs {
}
}
impl_display_from_nested!(RecordAttrs);
impl_stream_for_wrapper!(RecordAttrs, Def);
impl Locational for RecordAttrs {
fn loc(&self) -> Location {
Location::concat(self.0.first().unwrap(), self.0.last().unwrap())
}
}
impl From<Vec<Def>> for RecordAttrs {
fn from(attrs: Vec<Def>) -> Self {
Self(attrs)
@ -695,10 +761,6 @@ impl From<Vec<Def>> for RecordAttrs {
}
impl RecordAttrs {
pub const fn new() -> Self {
Self(vec![])
}
pub fn len(&self) -> usize {
self.0.len()
}
@ -718,6 +780,10 @@ impl RecordAttrs {
pub fn push(&mut self, attr: Def) {
self.0.push(attr);
}
pub fn extend(&mut self, attrs: RecordAttrs) {
self.0.extend(attrs.0);
}
}
#[derive(Clone, Debug)]
@ -875,7 +941,7 @@ impl UnaryOp {
#[derive(Debug, Clone)]
pub struct Call {
pub obj: Box<Expr>,
pub method_name: Option<Token>,
pub method_name: Option<Identifier>,
pub args: Args,
/// 全体の型(引数自体の型は関係ない)、e.g. `abs(-1)` -> `Neg -> Nat`
pub sig_t: Type,
@ -885,9 +951,9 @@ impl NestedDisplay for Call {
fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result {
writeln!(
f,
"({}){}(: {}):",
"({}){} (: {}):",
self.obj,
fmt_option!(pre ".", self.method_name),
fmt_option!(self.method_name),
self.sig_t
)?;
self.args.fmt_nest(f, level + 1)
@ -930,7 +996,7 @@ impl Locational for Call {
}
impl Call {
pub fn new(obj: Expr, method_name: Option<Token>, args: Args, sig_t: Type) -> Self {
pub fn new(obj: Expr, method_name: Option<Identifier>, args: Args, sig_t: Type) -> Self {
Self {
obj: Box::new(obj),
method_name,
@ -941,7 +1007,7 @@ impl Call {
pub fn is_import_call(&self) -> bool {
self.obj
.var_full_name()
.show_acc()
.map(|s| &s[..] == "import" || &s[..] == "pyimport" || &s[..] == "py")
.unwrap_or(false)
}
@ -1002,6 +1068,7 @@ impl NestedDisplay for VarSignature {
impl_display_from_nested!(VarSignature);
impl_locational!(VarSignature, ident);
impl_t!(VarSignature);
impl VarSignature {
pub const fn new(ident: Identifier, t: Type) -> Self {
@ -1032,6 +1099,7 @@ impl NestedDisplay for SubrSignature {
impl_display_from_nested!(SubrSignature);
impl_locational!(SubrSignature, ident, params);
impl_t!(SubrSignature);
impl SubrSignature {
pub const fn new(ident: Identifier, params: Params, t: Type) -> Self {
@ -1087,6 +1155,7 @@ pub enum Signature {
impl_nested_display_for_chunk_enum!(Signature; Var, Subr);
impl_display_for_enum!(Signature; Var, Subr,);
impl_t_for_enum!(Signature; Var, Subr);
impl_locational_for_enum!(Signature; Var, Subr,);
impl Signature {
@ -1121,6 +1190,13 @@ impl Signature {
Self::Subr(s) => &s.ident,
}
}
pub fn ident_mut(&mut self) -> &mut Identifier {
match self {
Self::Var(v) => &mut v.ident,
Self::Subr(s) => &mut s.ident,
}
}
}
/// represents a declaration of a variable
@ -1188,19 +1264,6 @@ impl DefBody {
pub const fn new(op: Token, block: Block, id: DefId) -> Self {
Self { op, block, id }
}
pub fn is_type(&self) -> bool {
match self.block.first().unwrap() {
Expr::Call(call) => {
if let Expr::Accessor(Accessor::Local(local)) = call.obj.as_ref() {
&local.inspect()[..] == "Type"
} else {
false
}
}
_ => false,
}
}
}
#[derive(Debug, Clone)]
@ -1244,6 +1307,155 @@ impl Def {
}
}
#[derive(Debug, Clone)]
pub struct Methods {
pub class: TypeSpec,
pub vis: Token, // `.` or `::`
pub defs: RecordAttrs, // TODO: allow declaration
}
impl NestedDisplay for Methods {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
writeln!(f, "{}{}", self.class, self.vis.content)?;
self.defs.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(Methods);
impl_locational!(Methods, class, defs);
impl HasType for Methods {
#[inline]
fn ref_t(&self) -> &Type {
Type::NONE
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
None
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl Methods {
pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self {
Self { class, vis, defs }
}
}
#[derive(Debug, Clone)]
pub struct ClassDef {
pub kind: TypeKind,
pub sig: Signature,
pub require_or_sup: Box<Expr>,
/// The type of `new` that is automatically defined if not defined
pub need_to_gen_new: bool,
pub __new__: Type,
pub private_methods: RecordAttrs,
pub public_methods: RecordAttrs,
}
impl NestedDisplay for ClassDef {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
self.sig.fmt_nest(f, level)?;
writeln!(f, ":")?;
self.private_methods.fmt_nest(f, level + 1)?;
self.public_methods.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(ClassDef);
impl_locational!(ClassDef, sig);
impl HasType for ClassDef {
#[inline]
fn ref_t(&self) -> &Type {
Type::NONE
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
None
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl ClassDef {
pub fn new(
kind: TypeKind,
sig: Signature,
require_or_sup: Expr,
need_to_gen_new: bool,
__new__: Type,
private_methods: RecordAttrs,
public_methods: RecordAttrs,
) -> Self {
Self {
kind,
sig,
require_or_sup: Box::new(require_or_sup),
need_to_gen_new,
__new__,
private_methods,
public_methods,
}
}
}
#[derive(Debug, Clone)]
pub struct AttrDef {
pub attr: Accessor,
pub block: Block,
}
impl NestedDisplay for AttrDef {
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result {
self.attr.fmt_nest(f, level)?;
writeln!(f, " = ")?;
self.block.fmt_nest(f, level + 1)
}
}
impl_display_from_nested!(AttrDef);
impl_locational!(AttrDef, attr, block);
impl HasType for AttrDef {
#[inline]
fn ref_t(&self) -> &Type {
Type::NONE
}
#[inline]
fn ref_mut_t(&mut self) -> &mut Type {
todo!()
}
#[inline]
fn signature_t(&self) -> Option<&Type> {
None
}
#[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> {
None
}
}
impl AttrDef {
pub const fn new(attr: Accessor, block: Block) -> Self {
Self { attr, block }
}
}
#[derive(Debug, Clone)]
pub enum Expr {
Lit(Literal),
@ -1259,12 +1471,14 @@ pub enum Expr {
Lambda(Lambda),
Decl(Decl),
Def(Def),
ClassDef(ClassDef),
AttrDef(AttrDef),
}
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def);
impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def, ClassDef, AttrDef);
impl_display_from_nested!(Expr);
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def);
impl_t_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def);
impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def, ClassDef, AttrDef);
impl_t_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Record, BinOp, UnaryOp, Call, Lambda, Decl, Def, ClassDef, AttrDef);
impl Expr {
pub fn receiver_t(&self) -> Option<&Type> {
@ -1274,9 +1488,9 @@ impl Expr {
}
}
pub fn var_full_name(&self) -> Option<String> {
pub fn show_acc(&self) -> Option<String> {
match self {
Expr::Accessor(acc) => acc.var_full_name(),
Expr::Accessor(acc) => Some(acc.show()),
_ => None,
}
}
@ -1285,7 +1499,7 @@ impl Expr {
pub fn __name__(&self) -> Option<&str> {
match self {
Expr::Accessor(acc) => acc.__name__(),
_ => todo!(),
_ => None,
}
}
}

View file

@ -7,8 +7,8 @@ pub use compile::*;
mod codegen;
pub mod effectcheck;
pub mod error;
pub mod eval;
pub mod hir;
pub mod link;
pub mod lower;
pub use lower::ASTLowerer;
pub mod context;

View file

@ -0,0 +1,93 @@
use erg_common::dict::Dict;
use erg_common::log;
use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_parser::ast::{ClassDef, Expr, Module, PreDeclTypeSpec, TypeSpec, AST};
use crate::error::{TyCheckError, TyCheckErrors};
/// Combine method definitions across multiple modules, specialized class contexts, etc.
#[derive(Debug)]
pub struct Linker {
// TODO: inner scope types
pub def_root_pos_map: Dict<Str, usize>,
pub errs: TyCheckErrors,
}
impl Linker {
pub fn new() -> Self {
Self {
def_root_pos_map: Dict::new(),
errs: TyCheckErrors::empty(),
}
}
pub fn link(mut self, mut ast: AST) -> Result<AST, TyCheckErrors> {
log!(info "the linking process has started.");
let mut new = vec![];
while let Some(chunk) = ast.module.lpop() {
match chunk {
Expr::Def(def) => {
match def.body.block.first().unwrap() {
Expr::Call(call) => {
match call.obj.get_name().map(|s| &s[..]) {
// TODO: decorator
Some("Class" | "Inherit" | "Inheritable") => {
self.def_root_pos_map.insert(
def.sig.ident().unwrap().inspect().clone(),
new.len(),
);
let type_def = ClassDef::new(def, vec![]);
new.push(Expr::ClassDef(type_def));
}
_ => {
new.push(Expr::Def(def));
}
}
}
_ => {
new.push(Expr::Def(def));
}
}
}
Expr::Methods(methods) => match &methods.class {
TypeSpec::PreDeclTy(PreDeclTypeSpec::Simple(simple)) => {
if let Some(pos) = self.def_root_pos_map.get(simple.name.inspect()) {
let mut class_def = match new.remove(*pos) {
Expr::ClassDef(class_def) => class_def,
_ => unreachable!(),
};
class_def.methods_list.push(methods);
new.insert(*pos, Expr::ClassDef(class_def));
} else {
let similar_name = Str::from(
self.def_root_pos_map
.keys()
.fold("".to_string(), |acc, key| acc + &key[..] + ","),
);
self.errs.push(TyCheckError::no_var_error(
line!() as usize,
methods.class.loc(),
"".into(),
simple.name.inspect(),
Some(&similar_name),
));
}
}
other => todo!("{other}"),
},
other => {
new.push(other);
}
}
}
let ast = AST::new(ast.name, Module::new(new));
log!(info "the linking process has completed:\n{}", ast);
if self.errs.is_empty() {
Ok(ast)
} else {
Err(self.errs)
}
}
}

View file

@ -9,18 +9,48 @@ use erg_common::{enum_unwrap, fmt_option, fn_name, get_hash, log, switch_lang, S
use erg_parser::ast;
use erg_parser::ast::AST;
use erg_type::constructors::{array, array_mut, class, free_var, func, poly_class, proc, quant};
use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{array, array_mut, free_var, func, mono, poly, proc, quant};
use erg_type::free::Constraint;
use erg_type::typaram::TyParam;
use erg_type::value::ValueObj;
use erg_type::value::{TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, Type};
use crate::context::{Context, ContextKind, RegistrationMode};
use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings};
use crate::hir;
use crate::hir::HIR;
use crate::varinfo::VarKind;
use Visibility::*;
/// HACK: Cannot be methodized this because a reference has been taken immediately before.
macro_rules! check_inheritable {
($self: ident, $type_obj: expr, $sup_class: expr, $sub_sig: expr) => {
match $type_obj.require_or_sup.as_ref() {
TypeObj::Generated(gen) => {
if let Some(impls) = gen.impls.as_ref() {
if !impls.contains_intersec(&mono("InheritableType")) {
$self.errs.push(LowerError::inheritance_error(
line!() as usize,
$sup_class.to_string(),
$sup_class.loc(),
$sub_sig.ident().inspect().clone(),
));
}
} else {
$self.errs.push(LowerError::inheritance_error(
line!() as usize,
$sup_class.to_string(),
$sup_class.loc(),
$sub_sig.ident().inspect().clone(),
));
}
}
_ => {}
}
};
}
/// Singleton that checks types of an AST, and convert (lower) it into a HIR
#[derive(Debug)]
pub struct ASTLowerer {
@ -137,7 +167,7 @@ impl ASTLowerer {
new_array.push(elem);
}
let elem_t = if union == Type::Never {
free_var(self.ctx.level, Constraint::type_of(Type::Type))
free_var(self.ctx.level, Constraint::new_type_of(Type::Type))
} else {
union
};
@ -162,11 +192,11 @@ impl ASTLowerer {
}
fn gen_array_with_length_type(&self, elem: &hir::Expr, len: &ast::Expr) -> Type {
let maybe_len = self.ctx.eval.eval_const_expr(len, &self.ctx);
let maybe_len = self.ctx.eval_const_expr(len, None);
match maybe_len {
Some(v @ ValueObj::Nat(_)) => {
Ok(v @ ValueObj::Nat(_)) => {
if elem.ref_t().is_mut() {
poly_class(
poly(
"ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
@ -174,9 +204,9 @@ impl ASTLowerer {
array(elem.t(), TyParam::Value(v))
}
}
Some(v @ ValueObj::Mut(_)) if v.class() == class("Nat!") => {
Ok(v @ ValueObj::Mut(_)) if v.class() == mono("Nat!") => {
if elem.ref_t().is_mut() {
poly_class(
poly(
"ArrayWithMutTypeAndLength!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
@ -184,11 +214,11 @@ impl ASTLowerer {
array_mut(elem.t(), TyParam::Value(v))
}
}
Some(other) => todo!("{other} is not a Nat object"),
// TODO: [T; !_]
None => {
Ok(other) => todo!("{other} is not a Nat object"),
// REVIEW: is it ok to ignore the error?
Err(_e) => {
if elem.ref_t().is_mut() {
poly_class(
poly(
"ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::erased(Type::Nat)],
)
@ -217,13 +247,24 @@ impl ASTLowerer {
Ok(hir::NormalTuple::new(hir::Args::from(new_tuple)))
}
fn lower_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
fn lower_record(&mut self, record: ast::Record) -> LowerResult<hir::Record> {
log!(info "entered {}({record})", fn_name!());
match record {
ast::Record::Normal(rec) => self.lower_normal_record(rec),
ast::Record::Shortened(_rec) => unreachable!(), // should be desugared
}
}
fn lower_normal_record(&mut self, record: ast::NormalRecord) -> LowerResult<hir::Record> {
log!(info "entered {}({record})", fn_name!());
let mut hir_record =
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::new());
hir::Record::new(record.l_brace, record.r_brace, hir::RecordAttrs::empty());
self.ctx.grow("<record>", ContextKind::Dummy, Private)?;
for attr in record.attrs.into_iter() {
let attr = self.lower_def(attr)?;
let attr = self.lower_def(attr).map_err(|e| {
self.pop_append_errs();
e
})?;
hir_record.push(attr);
}
self.pop_append_errs();
@ -233,37 +274,16 @@ impl ASTLowerer {
fn lower_acc(&mut self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
log!(info "entered {}({acc})", fn_name!());
match acc {
ast::Accessor::Local(local) => {
// `match` is an untypable special form
// `match`は型付け不可能な特殊形式
let (t, __name__) = if &local.inspect()[..] == "match" {
(Type::Failure, None)
} else {
(
self.ctx
.rec_get_var_t(&local.symbol, Private, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(&local.symbol),
)
};
let acc = hir::Accessor::Local(hir::Local::new(local.symbol, __name__, t));
Ok(acc)
}
ast::Accessor::Public(public) => {
let (t, __name__) = (
self.ctx
.rec_get_var_t(&public.symbol, Public, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(&public.symbol),
);
let public = hir::Public::new(public.dot, public.symbol, __name__, t);
let acc = hir::Accessor::Public(public);
ast::Accessor::Ident(ident) => {
let ident = self.lower_ident(ident)?;
let acc = hir::Accessor::Ident(ident);
Ok(acc)
}
ast::Accessor::Attr(attr) => {
let obj = self.lower_expr(*attr.obj)?;
let t = self
.ctx
.rec_get_attr_t(&obj, &attr.name.symbol, &self.ctx.name)?;
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, attr.name.symbol, t));
let t = self.ctx.rec_get_attr_t(&obj, &attr.ident, &self.ctx.name)?;
let ident = hir::Identifier::bare(attr.ident.dot, attr.ident.name);
let acc = hir::Accessor::Attr(hir::Attribute::new(obj, ident, t));
Ok(acc)
}
ast::Accessor::TupleAttr(t_attr) => {
@ -291,6 +311,21 @@ impl ASTLowerer {
}
}
fn lower_ident(&self, ident: ast::Identifier) -> LowerResult<hir::Identifier> {
// `match` is an untypable special form
// `match`は型付け不可能な特殊形式
let (t, __name__) = if ident.vis().is_private() && &ident.inspect()[..] == "match" {
(Type::Failure, None)
} else {
(
self.ctx.rec_get_var_t(&ident, &self.ctx.name)?,
self.ctx.get_local_uniq_obj_name(ident.name.token()),
)
};
let ident = hir::Identifier::new(ident.dot, ident.name, __name__, t);
Ok(ident)
}
fn lower_bin(&mut self, bin: ast::BinOp) -> LowerResult<hir::BinOp> {
log!(info "entered {}({bin})", fn_name!());
let mut args = bin.args.into_iter();
@ -320,6 +355,7 @@ impl ASTLowerer {
let (pos_args, kw_args, paren) = call.args.deconstruct();
let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()),
None,
Vec::with_capacity(kw_args.len()),
paren,
);
@ -330,14 +366,55 @@ impl ASTLowerer {
hir_args.push_kw(hir::KwArg::new(arg.keyword, self.lower_expr(arg.expr)?));
}
let obj = self.lower_expr(*call.obj)?;
let t = self.ctx.get_call_t(
let sig_t = self.ctx.get_call_t(
&obj,
&call.method_name,
&hir_args.pos_args,
&hir_args.kw_args,
&self.ctx.name,
)?;
Ok(hir::Call::new(obj, call.method_name, hir_args, t))
let method_name = if let Some(method_name) = call.method_name {
Some(hir::Identifier::new(
method_name.dot,
method_name.name,
None,
Type::Uninited,
))
} else {
None
};
Ok(hir::Call::new(obj, method_name, hir_args, sig_t))
}
fn lower_pack(&mut self, pack: ast::DataPack) -> LowerResult<hir::Call> {
log!(info "entered {}({pack})", fn_name!());
let class = self.lower_expr(*pack.class)?;
let args = self.lower_record(pack.args)?;
let args = vec![hir::PosArg::new(hir::Expr::Record(args))];
let method_name = ast::Identifier::new(
Some(Token::new(
TokenKind::Dot,
Str::ever("."),
pack.connector.lineno,
pack.connector.col_begin,
)),
ast::VarName::new(Token::new(
TokenKind::Symbol,
Str::ever("new"),
pack.connector.lineno,
pack.connector.col_begin,
)),
);
let sig_t = self.ctx.get_call_t(
&class,
&Some(method_name.clone()),
&args,
&[],
&self.ctx.name,
)?;
let args = hir::Args::new(args, None, vec![], None);
let method_name = hir::Identifier::bare(method_name.dot, method_name.name);
Ok(hir::Call::new(class, Some(method_name), args, sig_t))
}
/// TODO: varargs
@ -358,12 +435,10 @@ impl ASTLowerer {
self.pop_append_errs();
e
})?;
self.ctx
.preregister(lambda.body.ref_payload())
.map_err(|e| {
self.pop_append_errs();
e
})?;
self.ctx.preregister(&lambda.body).map_err(|e| {
self.pop_append_errs();
e
})?;
let body = self.lower_block(lambda.body).map_err(|e| {
self.pop_append_errs();
e
@ -406,20 +481,24 @@ impl ASTLowerer {
fn lower_def(&mut self, def: ast::Def) -> LowerResult<hir::Def> {
log!(info "entered {}({})", fn_name!(), def.sig);
if let Some(name) = def.sig.name_as_str() {
self.ctx.grow(name, ContextKind::Instant, Private)?;
if def.body.block.len() >= 1 {
let name = if let Some(name) = def.sig.name_as_str() {
name
} else {
"<lambda>"
};
self.ctx.grow(name, ContextKind::Instant, def.sig.vis())?;
let res = match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
};
// TODO: Context上の関数に型境界情報を追加
self.pop_append_errs();
res
} else {
match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
}
return res;
}
match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),
}
}
@ -429,7 +508,7 @@ impl ASTLowerer {
body: ast::DefBody,
) -> LowerResult<hir::Def> {
log!(info "entered {}({sig})", fn_name!());
self.ctx.preregister(body.block.ref_payload())?;
self.ctx.preregister(&body.block)?;
let block = self.lower_block(body.block)?;
let found_body_t = block.ref_t();
let opt_expect_body_t = self
@ -444,10 +523,14 @@ impl ASTLowerer {
_ => unreachable!(),
};
if let Some(expect_body_t) = opt_expect_body_t {
if let Err(e) =
self.return_t_check(sig.loc(), ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
// TODO: expect_body_t is smaller for constants
// TODO: 定数の場合、expect_body_tのほうが小さくなってしまう
if !sig.is_const() {
if let Err(e) =
self.return_t_check(sig.loc(), ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
}
}
}
let id = body.id;
@ -469,7 +552,8 @@ impl ASTLowerer {
}
_other => {}
}
let sig = hir::VarSignature::new(ident.clone(), found_body_t.clone());
let ident = hir::Identifier::bare(ident.dot.clone(), ident.name.clone());
let sig = hir::VarSignature::new(ident, found_body_t.clone());
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Var(sig), body))
}
@ -487,22 +571,20 @@ impl ASTLowerer {
.as_ref()
.unwrap()
.get_current_scope_var(sig.ident.inspect())
.unwrap_or_else(|| {
log!(info "{}\n", sig.ident.inspect());
log!(info "{}\n", self.ctx.outer.as_ref().unwrap());
panic!()
}) // FIXME: or instantiate
.unwrap()
.t
.clone();
self.ctx.assign_params(&sig.params, None)?;
self.ctx.preregister(body.block.ref_payload())?;
self.ctx.preregister(&body.block)?;
let block = self.lower_block(body.block)?;
let found_body_t = block.ref_t();
let expect_body_t = t.return_t().unwrap();
if let Err(e) =
self.return_t_check(sig.loc(), sig.ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
if !sig.is_const() {
if let Err(e) =
self.return_t_check(sig.loc(), sig.ident.inspect(), &expect_body_t, found_body_t)
{
self.errs.push(e);
}
}
let id = body.id;
self.ctx
@ -510,11 +592,156 @@ impl ASTLowerer {
.as_mut()
.unwrap()
.assign_subr(&sig, id, found_body_t)?;
let sig = hir::SubrSignature::new(sig.ident, sig.params, t);
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, t);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}
fn lower_class_def(&mut self, class_def: ast::ClassDef) -> LowerResult<hir::ClassDef> {
log!(info "entered {}({class_def})", fn_name!());
let mut hir_def = self.lower_def(class_def.def)?;
let mut private_methods = hir::RecordAttrs::empty();
let mut public_methods = hir::RecordAttrs::empty();
for mut methods in class_def.methods_list.into_iter() {
let class = self
.ctx
.instantiate_typespec(&methods.class, RegistrationMode::Normal)?;
self.ctx
.grow(&class.name(), ContextKind::MethodDefs, Private)?;
for def in methods.defs.iter_mut() {
if methods.vis.is(TokenKind::Dot) {
def.sig.ident_mut().unwrap().dot = Some(Token::new(
TokenKind::Dot,
".",
def.sig.ln_begin().unwrap(),
def.sig.col_begin().unwrap(),
));
}
self.ctx.preregister_def(def)?;
}
for def in methods.defs.into_iter() {
if methods.vis.is(TokenKind::Dot) {
let def = self.lower_def(def).map_err(|e| {
self.pop_append_errs();
e
})?;
public_methods.push(def);
} else {
let def = self.lower_def(def).map_err(|e| {
self.pop_append_errs();
e
})?;
private_methods.push(def);
}
}
match self.ctx.pop() {
Ok(methods) => {
self.check_override(&class, &methods);
if let Some((_, class_root)) = self.ctx.rec_get_mut_nominal_type_ctx(&class) {
for (newly_defined_name, _vi) in methods.locals.iter() {
for (_, already_defined_methods) in class_root.methods_list.iter_mut() {
// TODO: 特殊化なら同じ名前でもOK
// TODO: 定義のメソッドもエラー表示
if let Some((_already_defined_name, already_defined_vi)) =
already_defined_methods
.get_local_kv(&newly_defined_name.inspect())
{
if already_defined_vi.kind != VarKind::Auto {
self.errs.push(LowerError::duplicate_definition_error(
line!() as usize,
newly_defined_name.loc(),
methods.name.clone(),
newly_defined_name.inspect(),
));
} else {
already_defined_methods
.locals
.remove(&newly_defined_name.inspect()[..]);
}
}
}
}
class_root.methods_list.push((class, methods));
} else {
todo!()
}
}
Err(mut errs) => {
self.errs.append(&mut errs);
}
}
}
let (_, ctx) = self
.ctx
.rec_get_nominal_type_ctx(&mono(hir_def.sig.ident().inspect()))
.unwrap();
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)
.args
.get_left_or_key("Super")
.unwrap();
check_inheritable!(self, 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)) = (
ctx.get_current_scope_var("__new__"),
ctx.get_current_scope_var("new"),
) {
(dunder_new_vi.t.clone(), new_vi.kind == VarKind::Auto)
} else {
todo!()
};
let require_or_sup = self.get_require_or_sup(hir_def.body.block.remove(0));
Ok(hir::ClassDef::new(
type_obj.kind,
hir_def.sig,
require_or_sup,
need_to_gen_new,
__new__,
private_methods,
public_methods,
))
}
fn check_override(&mut self, class: &Type, ctx: &Context) {
if let Some(sups) = self.ctx.rec_get_nominal_super_type_ctxs(class) {
for (sup_t, sup) in sups.skip(1) {
for (method_name, vi) in ctx.locals.iter() {
if let Some(_sup_vi) = sup.get_current_scope_var(&method_name.inspect()) {
// must `@Override`
if let Some(decos) = &vi.comptime_decos {
if decos.contains("Override") {
continue;
}
}
self.errs.push(LowerError::override_error(
line!() as usize,
method_name.inspect(),
method_name.loc(),
sup_t,
ctx.caused_by(),
));
}
}
}
}
}
fn get_require_or_sup(&self, expr: hir::Expr) -> hir::Expr {
match expr {
acc @ hir::Expr::Accessor(_) => acc,
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("Inherit") => call.args.remove_left_or_key("Super").unwrap(),
Some("Inheritable") => {
self.get_require_or_sup(call.args.remove_left_or_key("Class").unwrap())
}
_ => todo!(),
},
other => todo!("{other}"),
}
}
// Call.obj == Accessor cannot be type inferred by itself (it can only be inferred with arguments)
// so turn off type checking (check=false)
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
@ -528,8 +755,10 @@ impl ASTLowerer {
ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin)?)),
ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary)?)),
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)),
ast::Expr::DataPack(pack) => Ok(hir::Expr::Call(self.lower_pack(pack)?)),
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)),
ast::Expr::Def(def) => Ok(hir::Expr::Def(self.lower_def(def)?)),
ast::Expr::ClassDef(defs) => Ok(hir::Expr::ClassDef(self.lower_class_def(defs)?)),
other => todo!("{other}"),
}
}
@ -548,7 +777,7 @@ impl ASTLowerer {
log!(info "the AST lowering process has started.");
log!(info "the type-checking process has started.");
let mut module = hir::Module::with_capacity(ast.module.len());
self.ctx.preregister(ast.module.ref_payload())?;
self.ctx.preregister(ast.module.block())?;
for expr in ast.module.into_iter() {
match self.lower_expr(expr).and_then(|e| self.use_check(e, mode)) {
Ok(expr) => {

View file

@ -99,11 +99,12 @@ impl OwnershipChecker {
// TODO: referenced
Expr::Call(call) => {
let args_owns = call.signature_t().unwrap().args_ownership();
if let Some(ownership) = args_owns.self_ {
self.check_expr(&call.obj, ownership);
}
let (non_default_args, var_args) =
call.args.pos_args.split_at(args_owns.non_defaults.len());
let non_defaults_len = if call.method_name.is_some() {
args_owns.non_defaults.len() - 1
} else {
args_owns.non_defaults.len()
};
let (non_default_args, var_args) = call.args.pos_args.split_at(non_defaults_len);
for (nd_arg, ownership) in
non_default_args.iter().zip(args_owns.non_defaults.iter())
{
@ -185,26 +186,15 @@ impl OwnershipChecker {
fn check_acc(&mut self, acc: &Accessor, ownership: Ownership) {
match acc {
Accessor::Local(local) => {
self.check_if_dropped(local.inspect(), local.loc());
Accessor::Ident(ident) => {
self.check_if_dropped(ident.inspect(), ident.loc());
if acc.ref_t().is_mut() && ownership.is_owned() {
log!(
"drop: {} (in {})",
local.inspect(),
local.ln_begin().unwrap_or(0)
ident.inspect(),
ident.ln_begin().unwrap_or(0)
);
self.drop(local.inspect(), acc.loc());
}
}
Accessor::Public(public) => {
self.check_if_dropped(public.inspect(), public.loc());
if acc.ref_t().is_mut() && ownership.is_owned() {
log!(
"drop: {} (in {})",
public.inspect(),
public.ln_begin().unwrap_or(0)
);
self.drop(public.inspect(), acc.loc());
self.drop(ident.inspect(), acc.loc());
}
}
Accessor::Attr(attr) => {

View file

@ -17,14 +17,14 @@ fn test_instantiation_and_generalization() -> Result<(), ()> {
/*
#[test]
fn test_resolve_trait() -> Result<(), ()> {
let context = Context::new_root_module();
let context = Context::new_main_module();
context.test_resolve_trait()?;
Ok(())
}
#[test]
fn test_resolve_trait_inner1() -> Result<(), ()> {
let context = Context::new_root_module();
let context = Context::new_main_module();
context.test_resolve_trait_inner1()?;
Ok(())
}

View file

@ -1,6 +1,8 @@
use std::fmt;
use erg_common::set::Set;
use erg_common::vis::Visibility;
use erg_common::Str;
use Visibility::*;
use erg_parser::ast::DefId;
@ -59,12 +61,14 @@ impl ParamIdx {
pub enum VarKind {
Defined(DefId),
Declared,
// TODO: flatten
Parameter {
def_id: DefId,
idx: ParamIdx,
default: DefaultInfo,
},
Generated,
Auto,
FixedAuto,
DoesNotExist,
Builtin,
}
@ -108,6 +112,7 @@ pub struct VarInfo {
pub muty: Mutability,
pub vis: Visibility,
pub kind: VarKind,
pub comptime_decos: Option<Set<Str>>,
}
impl fmt::Display for VarInfo {
@ -140,11 +145,28 @@ impl HasType for VarInfo {
}
impl VarInfo {
pub const ILLEGAL: &'static Self =
&VarInfo::new(Type::Failure, Immutable, Private, VarKind::DoesNotExist);
pub const ILLEGAL: &'static Self = &VarInfo::new(
Type::Failure,
Immutable,
Private,
VarKind::DoesNotExist,
None,
);
pub const fn new(t: Type, muty: Mutability, vis: Visibility, kind: VarKind) -> Self {
Self { t, muty, vis, kind }
pub const fn new(
t: Type,
muty: Mutability,
vis: Visibility,
kind: VarKind,
comptime_decos: Option<Set<Str>>,
) -> Self {
Self {
t,
muty,
vis,
kind,
comptime_decos,
}
}
pub fn same_id_as(&self, id: DefId) -> bool {