diff --git a/Cargo.lock b/Cargo.lock index 5ee397d5..6a94ef02 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "erg" -version = "0.3.2" +version = "0.4.0-beta.1" dependencies = [ "erg_common", "erg_compiler", @@ -25,14 +25,14 @@ dependencies = [ [[package]] name = "erg_common" -version = "0.3.2" +version = "0.4.0-beta.1" dependencies = [ "atty", ] [[package]] name = "erg_compiler" -version = "0.3.2" +version = "0.4.0-beta.1" dependencies = [ "erg_common", "erg_parser", @@ -41,14 +41,14 @@ dependencies = [ [[package]] name = "erg_parser" -version = "0.3.2" +version = "0.4.0-beta.1" dependencies = [ "erg_common", ] [[package]] name = "erg_type" -version = "0.3.2" +version = "0.4.0-beta.1" dependencies = [ "erg_common", ] diff --git a/Cargo.toml b/Cargo.toml index be687770..0069e30f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg" -version = "0.3.2" +version = "0.4.0-beta.1" description = "The Erg programming language" authors = ["Shunsuke Shibayama "] license = "MIT OR Apache-2.0" @@ -46,10 +46,10 @@ traditional_chinese = [ ] [dependencies] -erg_common = { version = "0.3.2", path = "./compiler/erg_common" } -erg_parser = { version = "0.3.2", path = "./compiler/erg_parser" } -erg_compiler = { version = "0.3.2", path = "./compiler/erg_compiler" } -erg_type = { version = "0.3.2", path = "./compiler/erg_type" } +erg_common = { version = "0.4.0-beta.1", path = "./compiler/erg_common" } +erg_parser = { version = "0.4.0-beta.1", path = "./compiler/erg_parser" } +erg_compiler = { version = "0.4.0-beta.1", path = "./compiler/erg_compiler" } +erg_type = { version = "0.4.0-beta.1", path = "./compiler/erg_type" } # [workspace] # member = ["cm", "dyne"] diff --git a/cargo_publish.bat b/cargo_publish.bat index c09eeaa2..ea5ac73a 100644 --- a/cargo_publish.bat +++ b/cargo_publish.bat @@ -4,7 +4,7 @@ if %~dp0 == C:%homepath%\GitHub\erg\ ( cd compiler/erg_common echo publish erg_common ... cargo publish - timeout 10 + timeout 12 cd ../erg_type echo publish erg_type ... cargo publish diff --git a/compiler/erg_common/Cargo.toml b/compiler/erg_common/Cargo.toml index 913bb1e4..f95c3f54 100644 --- a/compiler/erg_common/Cargo.toml +++ b/compiler/erg_common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_common" -version = "0.3.2" +version = "0.4.0-beta.1" description = "A common components library of Erg" authors = ["Shunsuke Shibayama "] license = "MIT OR Apache-2.0" diff --git a/compiler/erg_common/dict.rs b/compiler/erg_common/dict.rs index 98920f17..6785e9d4 100644 --- a/compiler/erg_common/dict.rs +++ b/compiler/erg_common/dict.rs @@ -153,6 +153,14 @@ impl Dict { self.dict.get_mut(k) } + pub fn get_key_value(&self, k: &Q) -> Option<(&K, &V)> + where + K: Borrow, + Q: Hash + Eq, + { + self.dict.get_key_value(k) + } + #[inline] pub fn contains_key(&self, k: &Q) -> bool where diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 7d54df97..1e6a0e8f 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -35,6 +35,10 @@ pub enum ErrorKind { PurityError, HasEffect, MoveError, + NotConstExpr, + InheritanceError, + VisibilityError, + DummyError, /* compile warnings */ AttributeWarning = 60, CastWarning, @@ -201,9 +205,9 @@ impl From<&str> for ErrorKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Location { RangePair { - ln_begin: usize, + ln_first: (usize, usize), col_first: (usize, usize), - ln_end: usize, + ln_second: (usize, usize), col_second: (usize, usize), }, Range { @@ -238,16 +242,19 @@ impl Location { pub fn pair(lhs: Self, rhs: Self) -> Self { Self::RangePair { - ln_begin: lhs.ln_begin().unwrap(), + ln_first: (lhs.ln_begin().unwrap(), lhs.ln_end().unwrap()), col_first: (lhs.col_begin().unwrap(), lhs.col_end().unwrap()), - ln_end: rhs.ln_end().unwrap(), + ln_second: (rhs.ln_begin().unwrap(), rhs.ln_end().unwrap()), col_second: (rhs.col_begin().unwrap(), rhs.col_end().unwrap()), } } pub const fn ln_begin(&self) -> Option { match self { - Self::RangePair { ln_begin, .. } + Self::RangePair { + ln_first: (ln_begin, _), + .. + } | Self::Range { ln_begin, .. } | Self::LineRange(ln_begin, _) | Self::Line(ln_begin) => Some(*ln_begin), @@ -257,7 +264,10 @@ impl Location { pub const fn ln_end(&self) -> Option { match self { - Self::RangePair { ln_end, .. } + Self::RangePair { + ln_second: (_, ln_end), + .. + } | Self::Range { ln_end, .. } | Self::LineRange(ln_end, _) | Self::Line(ln_end) => Some(*ln_end), @@ -316,8 +326,18 @@ impl ErrorCore { } } + pub fn dummy(errno: usize) -> Self { + Self::new( + errno, + DummyError, + Location::Line(errno as usize), + "", + None, + ) + } + pub fn unreachable(fn_name: &str, line: u32) -> Self { - Self::bug(line as usize, Location::Unknown, fn_name, line) + Self::bug(line as usize, Location::Line(line as usize), fn_name, line) } pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { @@ -339,6 +359,41 @@ impl ErrorCore { pub const VBAR_UNICODE: &str = "│"; pub const VBAR_BREAK_UNICODE: &str = "·"; +fn format_code_and_pointer( + e: &E, + ln_begin: usize, + ln_end: usize, + col_begin: usize, + col_end: usize, +) -> String { + let codes = if e.input() == &Input::REPL { + vec![e.input().reread()] + } else { + e.input().reread_lines(ln_begin, ln_end) + }; + let mut res = CYAN.to_string(); + let final_step = ln_end - ln_begin; + for (i, lineno) in (ln_begin..=ln_end).enumerate() { + let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| ` + if i == 0 && i == final_step { + pointer += &" ".repeat(col_begin); + pointer += &"^".repeat(cmp::max(1, col_end - col_begin)); + } else if i == 0 { + pointer += &" ".repeat(col_begin); + pointer += &"^".repeat(cmp::max(1, codes[i].len() - col_begin)); + } else if i == final_step { + pointer += &"^".repeat(col_end); + } else { + pointer += &"^".repeat(cmp::max(1, codes[i].len())); + } + res += &format!( + "{lineno}{VBAR_UNICODE} {code}\n{pointer}\n", + code = codes[i] + ); + } + res + RESET +} + /// format: /// ```console /// Error[#{.errno}]: File {file}, line {.loc (as line)}, in {.caused_by} @@ -418,13 +473,15 @@ pub trait ErrorDisplay { Location::Range { ln_begin, ln_end, .. } if ln_begin == ln_end => format!(", line {ln_begin}"), - Location::RangePair { - ln_begin, ln_end, .. - } - | Location::Range { + Location::Range { ln_begin, ln_end, .. } | Location::LineRange(ln_begin, ln_end) => format!(", line {ln_begin}..{ln_end}"), + Location::RangePair { + ln_first: (l1, l2), + ln_second: (l3, l4), + .. + } => format!(", line {l1}..{l2}, {l3}..{l4}"), Location::Line(lineno) => format!(", line {lineno}"), Location::Unknown => "".to_string(), }; @@ -442,33 +499,37 @@ pub trait ErrorDisplay { fn format_code_and_pointer(&self) -> String { match self.core().loc { - Location::RangePair { .. } => todo!(), + Location::RangePair { + ln_first, + col_first, + ln_second, + col_second, + } => { + format_code_and_pointer(self, ln_first.0, ln_first.1, col_first.0, col_first.1) + + &format_code_and_pointer( + self, + ln_second.0, + ln_second.1, + col_second.0, + col_second.1, + ) + } Location::Range { ln_begin, col_begin, ln_end, col_end, - } => { + } => format_code_and_pointer(self, ln_begin, ln_end, col_begin, col_end), + Location::LineRange(ln_begin, ln_end) => { let codes = if self.input() == &Input::REPL { vec![self.input().reread()] } else { self.input().reread_lines(ln_begin, ln_end) }; let mut res = CYAN.to_string(); - let final_step = ln_end - ln_begin; for (i, lineno) in (ln_begin..=ln_end).enumerate() { let mut pointer = " ".repeat(lineno.to_string().len() + 2); // +2 means `| ` - if i == 0 && i == final_step { - pointer += &" ".repeat(col_begin); - pointer += &"^".repeat(cmp::max(1, col_end - col_begin)); - } else if i == 0 { - pointer += &" ".repeat(col_begin); - pointer += &"^".repeat(cmp::max(1, codes[i].len() - col_begin)); - } else if i == final_step { - pointer += &"^".repeat(col_end); - } else { - pointer += &"^".repeat(cmp::max(1, codes[i].len())); - } + pointer += &"^".repeat(cmp::max(1, codes[i].len())); res += &format!( "{lineno}{VBAR_UNICODE} {code}\n{pointer}\n", code = codes[i] @@ -476,9 +537,6 @@ pub trait ErrorDisplay { } res + RESET } - Location::LineRange(_begin, _end) => { - todo!() - } Location::Line(lineno) => { let code = if self.input() == &Input::REPL { self.input().reread() diff --git a/compiler/erg_common/macros.rs b/compiler/erg_common/macros.rs index da3b5ba2..a6b715b4 100644 --- a/compiler/erg_common/macros.rs +++ b/compiler/erg_common/macros.rs @@ -87,6 +87,9 @@ macro_rules! enum_unwrap { ($ex: expr, $Enum: path :( $Cons: path :(_) ) $(,)*) => {{ if let $Enum($Cons(res)) = $ex { res } else { $crate::switch_unreachable!() } }}; + ($ex: expr, $Enum: path :( $Cons: path :( $Cons2: path :(_) ) ) $(,)*) => {{ + if let $Enum($Cons($Cons2(res))) = $ex { res } else { $crate::switch_unreachable!() } + }}; // X::A{a, b} ($ex: expr, $Enum: path {$($fields: ident $(,)*)*}) => {{ if let $Enum{$($fields,)*} = $ex { ($($fields,)*) } else { $crate::switch_unreachable!() } diff --git a/compiler/erg_common/opcode.rs b/compiler/erg_common/opcode.rs index 53fdcbfc..61d66882 100644 --- a/compiler/erg_common/opcode.rs +++ b/compiler/erg_common/opcode.rs @@ -63,6 +63,7 @@ pub enum Opcode { PRINT_EXPR = 70, LOAD_BUILD_CLASS = 71, LOAD_ASSERTION_ERROR = 74, + LIST_TO_TUPLE = 82, RETURN_VALUE = 83, /* ↓ These opcodes take an arg */ STORE_NAME = 90, @@ -101,8 +102,10 @@ pub enum Opcode { LOAD_DEREF = 136, STORE_DEREF = 137, CALL_FUNCTION_KW = 141, + CALL_FUNCTION_EX = 142, LOAD_METHOD = 160, CALL_METHOD = 161, + LIST_EXTEND = 162, // Erg-specific opcodes (must have a unary `ERG_`) // Define in descending order from 219, 255 ERG_POP_NTH = 196, @@ -205,6 +208,7 @@ impl From for Opcode { 70 => PRINT_EXPR, 71 => LOAD_BUILD_CLASS, 74 => LOAD_ASSERTION_ERROR, + 82 => LIST_TO_TUPLE, 83 => RETURN_VALUE, /* ↓ These opcodes take an arg */ 90 => STORE_NAME, @@ -243,8 +247,10 @@ impl From for Opcode { 136 => LOAD_DEREF, 137 => STORE_DEREF, 141 => CALL_FUNCTION_KW, + 142 => CALL_FUNCTION_EX, 160 => LOAD_METHOD, 161 => CALL_METHOD, + 162 => LIST_EXTEND, // Erg-specific opcodes 196 => ERG_POP_NTH, 197 => ERG_PEEK_NTH, diff --git a/compiler/erg_common/traits.rs b/compiler/erg_common/traits.rs index 7474e868..e65b2990 100644 --- a/compiler/erg_common/traits.rs +++ b/compiler/erg_common/traits.rs @@ -119,6 +119,13 @@ pub trait Stream: Sized { fn take_all(&mut self) -> Vec { self.ref_mut_payload().drain(..).collect() } + + fn extend(&mut self, iter: I) + where + I: IntoIterator, + { + self.ref_mut_payload().extend(iter); + } } #[macro_export] @@ -400,7 +407,10 @@ pub trait Locational { fn ln_begin(&self) -> Option { match self.loc() { - Location::RangePair { ln_begin, .. } + Location::RangePair { + ln_first: (ln_begin, _), + .. + } | Location::Range { ln_begin, .. } | Location::LineRange(ln_begin, _) => Some(ln_begin), Location::Line(lineno) => Some(lineno), @@ -410,7 +420,10 @@ pub trait Locational { fn ln_end(&self) -> Option { match self.loc() { - Location::RangePair { ln_end, .. } + Location::RangePair { + ln_second: (_, ln_end), + .. + } | Location::Range { ln_end, .. } | Location::LineRange(_, ln_end) => Some(ln_end), Location::Line(lineno) => Some(lineno), diff --git a/compiler/erg_common/vis.rs b/compiler/erg_common/vis.rs index 4a43778c..ad1c8079 100644 --- a/compiler/erg_common/vis.rs +++ b/compiler/erg_common/vis.rs @@ -22,8 +22,8 @@ impl Visibility { /// same structure as `Identifier`, but only for Record fields. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Field { - vis: Visibility, - symbol: Str, + pub vis: Visibility, + pub symbol: Str, } impl fmt::Display for Field { diff --git a/compiler/erg_compiler/Cargo.toml b/compiler/erg_compiler/Cargo.toml index ad8067cc..3f5f6a34 100644 --- a/compiler/erg_compiler/Cargo.toml +++ b/compiler/erg_compiler/Cargo.toml @@ -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 "] 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" diff --git a/compiler/erg_compiler/codegen.rs b/compiler/erg_compiler/codegen.rs index 9a33de76..5cdd30bc 100644 --- a/compiler/erg_compiler/codegen.rs +++ b/compiler/erg_compiler/codegen.rs @@ -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, - 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 { + fn local_search(&self, name: &str, _acc_kind: AccessKind) -> Option { 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) = ¶ms.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: + -> @@ -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> { + 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) { + 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(¶m_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, params: Vec) -> 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 { "", 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; diff --git a/compiler/erg_compiler/compile.rs b/compiler/erg_compiler/compile.rs index d3cca832..c70bba33 100644 --- a/compiler/erg_compiler/compile.rs +++ b/compiler/erg_compiler/compile.rs @@ -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 { - 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() { diff --git a/compiler/erg_compiler/context/compare.rs b/compiler/erg_compiler/context/compare.rs index 9cd8bc3a..e0470e14 100644 --- a/compiler/erg_compiler/context/compare.rs +++ b/compiler/erg_compiler/context/compare.rs @@ -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を実装しない diff --git a/compiler/erg_compiler/eval.rs b/compiler/erg_compiler/context/eval.rs similarity index 57% rename from compiler/erg_compiler/eval.rs rename to compiler/erg_compiler/context/eval.rs index 04113d61..7ee818bc 100644 --- a/compiler/erg_compiler/eval.rs +++ b/compiler/erg_compiler/context/eval.rs @@ -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 { +fn try_get_op_kind_from_token(kind: TokenKind) -> EvalResult { 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 { 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 { - 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 { + 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 { - 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 { + match obj.try_get_attr(&Field::from(ident)) { + Some(val) => { + return Ok(val); } - _ => None, + _ => {} } - } - - fn eval_const_unary(&self, unary: &UnaryOp) -> Option { - 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> { - todo!() - } - - fn eval_const_call(&self, call: &Call, ctx: &Context) -> Option { - 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 { + 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 { + 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 { + 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 { + 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 { - if def.is_const() { todo!() } - None } - fn eval_const_array(&self, arr: &Array, ctx: &Context) -> Option { + fn eval_const_def(&mut self, def: &Def) -> EvalResult { + 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 { 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 { + fn eval_const_record(&self, record: &Record) -> EvalResult { + 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 { let mut attrs = vec![]; + // HACK: should avoid cloning + let mut record_ctx = Context::instant(Str::ever(""), 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 { + pub(crate) fn eval_const_expr( + &self, + expr: &Expr, + __name__: Option<&Str>, + ) -> EvalResult { 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 { - 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 { + 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 { + pub(crate) fn eval_const_block( + &mut self, + block: &Block, + __name__: Option<&Str>, + ) -> EvalResult { + 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 { match op { Add => lhs .try_add(rhs) @@ -346,10 +437,10 @@ impl Evaluator { ) -> EvalResult { 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 { + fn eval_unary(&self, op: OpKind, val: ValueObj) -> EvalResult { match op { Pos => todo!(), Neg => todo!(), @@ -382,9 +473,7 @@ impl Evaluator { fn eval_unary_tp(&self, op: OpKind, val: &TyParam) -> EvalResult { 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 { + pub(crate) fn eval_tp(&self, p: &TyParam) -> EvalResult { 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 { + pub(crate) fn eval_t_params(&self, substituted: Type, level: usize) -> EvalResult { 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 { + pub(crate) fn _eval_bound(&self, bound: TyBound, level: usize) -> EvalResult { 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 { + pub(crate) fn eval_pred(&self, p: Predicate) -> EvalResult { 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 { - let p = self.eval_tp(p, ctx)?; + pub(crate) fn get_tp_t(&self, p: &TyParam) -> EvalResult { + 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 { - let p = self.eval_tp(p, ctx)?; + pub(crate) fn _get_tp_class(&self, p: &TyParam) -> EvalResult { + 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 diff --git a/compiler/erg_compiler/context/hint.rs b/compiler/erg_compiler/context/hint.rs index 4a121cff..38999882 100644 --- a/compiler/erg_compiler/context/hint.rs +++ b/compiler/erg_compiler/context/hint.rs @@ -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 { diff --git a/compiler/erg_compiler/context/initialize/const_func.rs b/compiler/erg_compiler/context/initialize/const_func.rs new file mode 100644 index 00000000..9c658b76 --- /dev/null +++ b/compiler/erg_compiler/context/initialize/const_func.rs @@ -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) -> 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(""))); + 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) -> 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(""))); + 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) -> 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!(), + } +} diff --git a/compiler/erg_compiler/context/initialize/math.rs b/compiler/erg_compiler/context/initialize/math.rs deleted file mode 100644 index bf40bcf0..00000000 --- a/compiler/erg_compiler/context/initialize/math.rs +++ /dev/null @@ -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 - } -} diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index a456516c..b4294cc0 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -1,27 +1,23 @@ //! defines type information for builtin objects (in `Context`) //! //! 組み込みオブジェクトの型情報を(Contextに)定義 -pub mod importlib; -pub mod io; -pub mod math; -pub mod random; -pub mod socket; -pub mod sys; -pub mod time; +pub mod const_func; +pub mod py_mods; use erg_common::set; use erg_common::vis::Visibility; use erg_common::Str; -use erg_type::constructors::*; use erg_type::typaram::TyParam; use erg_type::value::ValueObj; use erg_type::Type; +use erg_type::{constructors::*, BuiltinConstSubr, ConstSubr}; use ParamSpec as PS; use Type::*; use erg_parser::ast::VarName; +use crate::context::initialize::const_func::{class_func, inherit_func, inheritable_func}; use crate::context::instantiate::{ConstTemplate, TyVarContext}; use crate::context::{Context, ContextKind, DefaultInfo, ParamSpec, TraitInstance}; use crate::varinfo::{Mutability, VarInfo, VarKind}; @@ -31,31 +27,40 @@ use VarKind::*; use Visibility::*; impl Context { - fn register_decl(&mut self, name: &'static str, t: Type, vis: Visibility) { + fn register_builtin_decl(&mut self, name: &'static str, t: Type, vis: Visibility) { let name = VarName::from_static(name); if self.decls.get(&name).is_some() { panic!("already registered: {name}"); } else { self.decls - .insert(name, VarInfo::new(t, Immutable, vis, Builtin)); + .insert(name, VarInfo::new(t, Immutable, vis, Builtin, None)); } } - fn register_impl(&mut self, name: &'static str, t: Type, muty: Mutability, vis: Visibility) { + fn register_builtin_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, Builtin)); + .insert(name, VarInfo::new(t, muty, vis, Builtin, None)); } } - fn register_const(&mut self, name: &'static str, obj: ValueObj) { - if self.consts.get(name).is_some() { + fn register_builtin_const(&mut self, name: &str, obj: ValueObj) { + if self.rec_get_const_obj(name).is_some() { panic!("already registered: {name}"); } else { - self.consts.insert(VarName::from_static(name), obj); + // TODO: not all value objects are comparable + let vi = VarInfo::new(enum_t(set! {obj.clone()}), Const, Private, Builtin, None); + self.consts.insert(VarName::from_str(Str::rc(name)), obj); + self.locals.insert(VarName::from_str(Str::rc(name)), vi); } } @@ -67,28 +72,28 @@ impl Context { } } - fn register_type(&mut self, t: Type, ctx: Self, muty: Mutability) { + fn register_builtin_type(&mut self, t: Type, ctx: Self, muty: Mutability) { if t.typarams_len().is_none() { self.register_mono_type(t, ctx, muty); } else { - if t.is_class() { - self.register_poly_class(t, ctx, muty); - } else if t.is_trait() { - self.register_poly_trait(t, ctx, muty); - } else { - todo!() - } + self.register_poly_type(t, ctx, muty); } } fn register_mono_type(&mut self, t: Type, ctx: Self, muty: Mutability) { + // FIXME: recursive search if self.mono_types.contains_key(&t.name()) { panic!("{} has already been registered", t.name()); + } else if self.rec_get_const_obj(&t.name()).is_some() { + panic!("{} has already been registered as const", t.name()); } else { let name = VarName::from_str(t.name()); - self.locals - .insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin)); - self.consts.insert(name.clone(), ValueObj::t(t.clone())); + self.locals.insert( + name.clone(), + VarInfo::new(Type, muty, Private, Builtin, None), + ); + self.consts + .insert(name.clone(), ValueObj::builtin_t(t.clone())); 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())); @@ -103,16 +108,21 @@ impl Context { } } - fn register_poly_class(&mut self, t: Type, ctx: Self, muty: Mutability) { + // FIXME: MethodDefsと再代入は違う + fn register_poly_type(&mut self, t: Type, ctx: Self, muty: Mutability) { let mut tv_ctx = TyVarContext::new(self.level, ctx.type_params_bounds(), self); let t = Self::instantiate_t(t, &mut tv_ctx); - if let Some((_, root_ctx)) = self.poly_classes.get_mut(&t.name()) { - root_ctx.specializations.push((t, ctx)); + // FIXME: panic + if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.name()) { + root_ctx.methods_list.push((t, ctx)); } else { let name = VarName::from_str(t.name()); - self.locals - .insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin)); - self.consts.insert(name.clone(), ValueObj::t(t.clone())); + self.locals.insert( + name.clone(), + VarInfo::new(Type, muty, Private, Builtin, None), + ); + self.consts + .insert(name.clone(), ValueObj::builtin_t(t.clone())); 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())); @@ -123,41 +133,19 @@ impl Context { ); } } - self.poly_classes.insert(name, (t, ctx)); + self.poly_types.insert(name, (t, ctx)); } } - fn register_poly_trait(&mut self, t: Type, ctx: Self, muty: Mutability) { - if self.poly_traits.contains_key(&t.name()) { - panic!("{} has already been registered", t.name()); - } else { - let mut tv_ctx = TyVarContext::new(self.level, ctx.type_params_bounds(), self); - let t = Self::instantiate_t(t, &mut tv_ctx); - let name = VarName::from_str(t.name()); - self.locals - .insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin)); - self.consts.insert(name.clone(), ValueObj::t(t.clone())); - 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.poly_traits.insert(name, (t, ctx)); - } - } - - fn register_patch(&mut self, name: &'static str, ctx: Self, muty: Mutability) { + fn register_builtin_patch(&mut self, name: &'static str, ctx: Self, muty: Mutability) { if self.patches.contains_key(name) { panic!("{} has already been registered", name); } else { let name = VarName::from_static(name); - self.locals - .insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin)); + self.locals.insert( + name.clone(), + VarInfo::new(Type, muty, Private, Builtin, None), + ); for method_name in ctx.locals.keys() { if let Some(patches) = self.method_impl_patches.get_mut(method_name) { patches.push(name.clone()); @@ -176,37 +164,39 @@ impl Context { // 型境界はすべて各サブルーチンで定義する // push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する fn init_builtin_traits(&mut self) { + let unpack = Self::mono_trait("Unpack", vec![], Self::TOP_LEVEL); + let inheritable_type = Self::mono_trait("InheritableType", vec![], Self::TOP_LEVEL); let named = Self::mono_trait("Named", vec![], Self::TOP_LEVEL); let mut mutable = Self::mono_trait("Mutable", vec![], Self::TOP_LEVEL); let proj = mono_proj(mono_q("Self"), "ImmutType"); let f_t = func(vec![param_t("old", proj.clone())], None, vec![], proj); - let t = pr1_met(mono_q("Self"), None, f_t, NoneType); - let t = quant(t, set! { subtypeof(mono_q("Self"), trait_("Immutizable")) }); - mutable.register_decl("update!", t, Public); + let t = pr1_met(ref_mut(mono_q("Self"), None), f_t, NoneType); + let t = quant(t, set! { subtypeof(mono_q("Self"), mono("Immutizable")) }); + mutable.register_builtin_decl("update!", t, Public); let mut immutizable = - Self::mono_trait("Immutizable", vec![trait_("Mutable")], Self::TOP_LEVEL); - immutizable.register_decl("ImmutType", Type, Public); + Self::mono_trait("Immutizable", vec![mono("Mutable")], Self::TOP_LEVEL); + immutizable.register_builtin_decl("ImmutType", Type, Public); let mut mutizable = Self::mono_trait("Mutizable", vec![], Self::TOP_LEVEL); - mutizable.register_decl("MutType!", Type, Public); + mutizable.register_builtin_decl("MutType!", Type, Public); let mut in_ = Self::poly_trait( "In", vec![PS::t("T", NonDefault)], - vec![poly_trait("Input", vec![ty_tp(mono_q("T"))])], + vec![poly("Input", vec![ty_tp(mono_q("T"))])], Self::TOP_LEVEL, ); let op_t = fn1_met(mono_q("T"), mono_q("I"), Bool); let op_t = quant( op_t, - set! { static_instance("T", Type), subtypeof(mono_q("I"), poly_trait("In", vec![ty_tp(mono_q("T"))])) }, + set! { static_instance("T", Type), subtypeof(mono_q("I"), poly("In", vec![ty_tp(mono_q("T"))])) }, ); - in_.register_decl("__in__", op_t, Public); + in_.register_builtin_decl("__in__", op_t, Public); // Erg does not have a trait equivalent to `PartialEq` in Rust // This means, Erg's `Float` cannot be compared with other `Float` // use `l - r < EPSILON` to check if two floats are almost equal let mut eq = Self::poly_trait( "Eq", vec![PS::t("R", WithDefault)], - vec![poly_trait("Output", vec![ty_tp(mono_q("R"))])], + vec![poly("Output", vec![ty_tp(mono_q("R"))])], Self::TOP_LEVEL, ); // __eq__: |Self <: Eq()| Self.(Self) -> Bool @@ -214,60 +204,60 @@ impl Context { let op_t = quant( op_t, set! { - subtypeof(mono_q("Self"), poly_trait("Eq", vec![ty_tp(mono_q("R"))])), + subtypeof(mono_q("Self"), poly("Eq", vec![ty_tp(mono_q("R"))])), static_instance("R", Type) }, ); - eq.register_decl("__eq__", op_t.clone(), Public); + eq.register_builtin_decl("__eq__", op_t.clone(), Public); let mut partial_ord = Self::poly_trait( "PartialOrd", vec![PS::t("R", WithDefault)], - vec![poly_trait("PartialEq", vec![ty_tp(mono_q("R"))])], + vec![poly("PartialEq", vec![ty_tp(mono_q("R"))])], Self::TOP_LEVEL, ); let op_t = fn1_met(mono_q("Self"), mono_q("R"), Bool); let op_t = quant( op_t, set! { - subtypeof(mono_q("Self"), poly_trait("PartialOrd", vec![ty_tp(mono_q("R"))])), + subtypeof(mono_q("Self"), poly("PartialOrd", vec![ty_tp(mono_q("R"))])), static_instance("R", Type) }, ); - partial_ord.register_decl("__lt__", op_t.clone(), Public); + partial_ord.register_builtin_decl("__lt__", op_t.clone(), Public); let ord = Self::mono_trait( "Ord", - vec![poly_trait("Eq", vec![]), poly_trait("PartialOrd", vec![])], + vec![poly("Eq", vec![]), poly("PartialOrd", vec![])], Self::TOP_LEVEL, ); let num = Self::mono_trait( "Num", vec![ - poly_trait("Add", vec![]), - poly_trait("Sub", vec![]), - poly_trait("Mul", vec![]), + poly("Add", vec![]), + poly("Sub", vec![]), + poly("Mul", vec![]), ], Self::TOP_LEVEL, ); let mut seq = Self::poly_trait( "Seq", vec![PS::t("T", NonDefault)], - vec![poly_trait("Output", vec![ty_tp(mono_q("T"))])], + vec![poly("Output", vec![ty_tp(mono_q("T"))])], Self::TOP_LEVEL, ); let self_t = mono_q("Self"); let t = fn0_met(self_t.clone(), Nat); let t = quant( t, - set! {subtypeof(self_t.clone(), poly_trait("Seq", vec![TyParam::erased(Type)]))}, + set! {subtypeof(self_t.clone(), poly("Seq", vec![TyParam::erased(Type)]))}, ); - seq.register_decl("__len__", t, Public); + seq.register_builtin_decl("__len__", t, Public); let t = fn1_met(self_t.clone(), Nat, mono_q("T")); let t = quant( t, - set! {subtypeof(self_t, poly_trait("Seq", vec![ty_tp(mono_q("T"))])), static_instance("T", Type)}, + set! {subtypeof(self_t, poly("Seq", vec![ty_tp(mono_q("T"))])), static_instance("T", Type)}, ); // Seq.get: |Self <: Seq(T)| Self.(Nat) -> T - seq.register_decl("get", t, Public); + seq.register_builtin_decl("get", t, Public); let params = vec![PS::t("T", NonDefault)]; let input = Self::poly_trait("Input", params.clone(), vec![], Self::TOP_LEVEL); let output = Self::poly_trait("Output", params.clone(), vec![], Self::TOP_LEVEL); @@ -278,74 +268,72 @@ impl Context { let mut add = Self::poly_trait( "Add", params.clone(), - vec![poly_trait("Output", vec![ty_tp(mono_q("R"))])], // Rについて共変(__add__の型とは関係ない) + vec![poly("Output", vec![ty_tp(mono_q("R"))])], // Rについて共変(__add__の型とは関係ない) Self::TOP_LEVEL, ); - let self_bound = subtypeof(mono_q("Self"), poly_trait("Add", ty_params.clone())); + let self_bound = subtypeof(mono_q("Self"), poly("Add", ty_params.clone())); let op_t = fn1_met(mono_q("Self"), r.clone(), mono_proj(mono_q("Self"), "AddO")); let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); - add.register_decl("__add__", op_t, Public); - add.register_decl("AddO", Type, Public); + add.register_builtin_decl("__add__", op_t, Public); + add.register_builtin_decl("AddO", Type, Public); let mut sub = Self::poly_trait( "Sub", params.clone(), - vec![poly_trait("Output", vec![ty_tp(mono_q("R"))])], + vec![poly("Output", vec![ty_tp(mono_q("R"))])], Self::TOP_LEVEL, ); let op_t = fn1_met(mono_q("Self"), r.clone(), mono_proj(mono_q("Self"), "SubO")); - let self_bound = subtypeof(mono_q("Self"), poly_trait("Sub", ty_params.clone())); + let self_bound = subtypeof(mono_q("Self"), poly("Sub", ty_params.clone())); let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); - sub.register_decl("__sub__", op_t, Public); - sub.register_decl("SubO", Type, Public); + sub.register_builtin_decl("__sub__", op_t, Public); + sub.register_builtin_decl("SubO", Type, Public); let mut mul = Self::poly_trait( "Mul", params.clone(), - vec![poly_trait("Output", vec![ty_tp(mono_q("R"))])], + vec![poly("Output", vec![ty_tp(mono_q("R"))])], Self::TOP_LEVEL, ); let op_t = fn1_met(mono_q("Self"), r.clone(), mono_proj(mono_q("Self"), "MulO")); - let self_bound = subtypeof(mono_q("Self"), poly_trait("Mul", ty_params.clone())); + let self_bound = subtypeof(mono_q("Self"), poly("Mul", ty_params.clone())); let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); - mul.register_decl("__mul__", op_t, Public); - mul.register_decl("MulO", Type, Public); + mul.register_builtin_decl("__mul__", op_t, Public); + mul.register_builtin_decl("MulO", Type, Public); let mut div = Self::poly_trait( "Div", params.clone(), - vec![poly_trait("Output", vec![ty_tp(mono_q("R"))])], + vec![poly("Output", vec![ty_tp(mono_q("R"))])], Self::TOP_LEVEL, ); let op_t = fn1_met(mono_q("Self"), r, mono_proj(mono_q("Self"), "DivO")); - let self_bound = subtypeof(mono_q("Self"), poly_trait("Div", ty_params.clone())); + let self_bound = subtypeof(mono_q("Self"), poly("Div", ty_params.clone())); let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); - div.register_decl("__div__", op_t, Public); - div.register_decl("DivO", Type, Public); - self.register_type(trait_("Named"), named, Const); - self.register_type(trait_("Mutable"), mutable, Const); - self.register_type(trait_("Immutizable"), immutizable, Const); - self.register_type(trait_("Mutizable"), mutizable, Const); - self.register_type(poly_trait("In", vec![ty_tp(mono_q("T"))]), in_, Const); - self.register_type(poly_trait("Eq", vec![ty_tp(mono_q("R"))]), eq, Const); - self.register_type( - poly_trait("PartialOrd", vec![ty_tp(mono_q("R"))]), + div.register_builtin_decl("__div__", op_t, Public); + div.register_builtin_decl("DivO", Type, Public); + self.register_builtin_type(mono("Unpack"), unpack, Const); + self.register_builtin_type(mono("InheritableType"), inheritable_type, Const); + self.register_builtin_type(mono("Named"), named, Const); + self.register_builtin_type(mono("Mutable"), mutable, Const); + self.register_builtin_type(mono("Immutizable"), immutizable, Const); + self.register_builtin_type(mono("Mutizable"), mutizable, Const); + self.register_builtin_type(poly("In", vec![ty_tp(mono_q("T"))]), in_, Const); + self.register_builtin_type(poly("Eq", vec![ty_tp(mono_q("R"))]), eq, Const); + self.register_builtin_type( + poly("PartialOrd", vec![ty_tp(mono_q("R"))]), partial_ord, Const, ); - self.register_type(trait_("Ord"), ord, Const); - self.register_type(trait_("Num"), num, Const); - self.register_type(poly_trait("Seq", vec![ty_tp(mono_q("T"))]), seq, Const); - self.register_type(poly_trait("Input", vec![ty_tp(mono_q("T"))]), input, Const); - self.register_type( - poly_trait("Output", vec![ty_tp(mono_q("T"))]), - output, - Const, - ); - self.register_type(poly_trait("Add", ty_params.clone()), add, Const); - self.register_type(poly_trait("Sub", ty_params.clone()), sub, Const); - self.register_type(poly_trait("Mul", ty_params.clone()), mul, Const); - self.register_type(poly_trait("Div", ty_params), div, Const); + self.register_builtin_type(mono("Ord"), ord, Const); + self.register_builtin_type(mono("Num"), num, Const); + self.register_builtin_type(poly("Seq", vec![ty_tp(mono_q("T"))]), seq, Const); + self.register_builtin_type(poly("Input", vec![ty_tp(mono_q("T"))]), input, Const); + self.register_builtin_type(poly("Output", vec![ty_tp(mono_q("T"))]), output, Const); + self.register_builtin_type(poly("Add", ty_params.clone()), add, Const); + self.register_builtin_type(poly("Sub", ty_params.clone()), sub, Const); + self.register_builtin_type(poly("Mul", ty_params.clone()), mul, Const); + self.register_builtin_type(poly("Div", ty_params), div, Const); self.register_const_param_defaults( "Eq", - vec![ConstTemplate::Obj(ValueObj::t(mono_q("Self")))], + vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))], ); self.register_const_param_defaults( "PartialOrd", @@ -353,92 +341,89 @@ impl Context { ); self.register_const_param_defaults( "Add", - vec![ConstTemplate::Obj(ValueObj::t(mono_q("Self")))], + vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))], ); self.register_const_param_defaults( "Sub", - vec![ConstTemplate::Obj(ValueObj::t(mono_q("Self")))], + vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))], ); self.register_const_param_defaults( "Mul", - vec![ConstTemplate::Obj(ValueObj::t(mono_q("Self")))], + vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))], ); self.register_const_param_defaults( "Div", - vec![ConstTemplate::Obj(ValueObj::t(mono_q("Self")))], + vec![ConstTemplate::Obj(ValueObj::builtin_t(mono_q("Self")))], ); } fn init_builtin_classes(&mut self) { let mut obj = Self::mono_class("Obj", vec![], vec![], Self::TOP_LEVEL); let t = fn0_met(mono_q("Self"), mono_q("Self")); - let t = quant(t, set! {subtypeof(mono_q("Self"), class("Obj"))}); - obj.register_impl("clone", t, Const, Public); - obj.register_impl("__module__", Str, Const, Public); - obj.register_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public); - obj.register_impl("__repr__", fn0_met(Obj, Str), Immutable, Public); - obj.register_impl("__str__", fn0_met(Obj, Str), Immutable, Public); - obj.register_impl("__dict__", fn0_met(Obj, dict(Str, Obj)), Immutable, Public); - obj.register_impl("__bytes__", fn0_met(Obj, class("Bytes")), Immutable, Public); - obj.register_const("MutType!", ValueObj::t(class("Obj!"))); - // let mut record = Self::mono_trait("Record", vec![Obj], Self::TOP_LEVEL); - // let mut class = Self::mono_class("Class", vec![Type, Obj], Self::TOP_LEVEL); + let t = quant(t, set! {subtypeof(mono_q("Self"), mono("Obj"))}); + obj.register_builtin_impl("clone", t, Const, Public); + obj.register_builtin_impl("__module__", Str, Const, Public); + obj.register_builtin_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public); + obj.register_builtin_impl("__repr__", fn0_met(Obj, Str), Immutable, Public); + obj.register_builtin_impl("__str__", fn0_met(Obj, Str), Immutable, Public); + obj.register_builtin_impl("__dict__", fn0_met(Obj, dict(Str, Obj)), Immutable, Public); + obj.register_builtin_impl("__bytes__", fn0_met(Obj, mono("Bytes")), Immutable, Public); + obj.register_builtin_const("MutType!", ValueObj::builtin_t(mono("Obj!"))); let mut int = Self::mono_class( "Int", vec![Ratio, Obj], vec![ - trait_("Ord"), - poly_trait("Eq", vec![ty_tp(Int)]), - poly_trait("Add", vec![ty_tp(Int)]), - poly_trait("Sub", vec![ty_tp(Int)]), - poly_trait("Mul", vec![ty_tp(Int)]), - poly_trait("Div", vec![ty_tp(Int)]), - trait_("Num"), - // trait_("Rational"), - // trait_("Integral"), - trait_("Mutizable"), + mono("Ord"), + poly("Eq", vec![ty_tp(Int)]), + poly("Add", vec![ty_tp(Int)]), + poly("Sub", vec![ty_tp(Int)]), + poly("Mul", vec![ty_tp(Int)]), + poly("Div", vec![ty_tp(Int)]), + mono("Num"), + // class("Rational"), + // class("Integral"), + mono("Mutizable"), ], Self::TOP_LEVEL, ); - int.register_impl("abs", fn0_met(Int, Nat), Immutable, Public); + int.register_builtin_impl("abs", fn0_met(Int, Nat), Immutable, Public); // __div__ is not included in Int (cast to Float) let op_t = fn1_met(Int, Int, Int); - int.register_impl("__add__", op_t.clone(), Const, Public); - int.register_impl("__sub__", op_t.clone(), Const, Public); - int.register_impl("__mul__", op_t, Const, Public); - int.register_const("AddO", ValueObj::t(Int)); - int.register_const("SubO", ValueObj::t(Int)); - int.register_const("MulO", ValueObj::t(Int)); - int.register_const("DivO", ValueObj::t(Ratio)); - int.register_const("MutType!", ValueObj::t(class("Int!"))); - int.register_impl("Real", Int, Const, Public); - int.register_impl("Imag", Int, Const, Public); + int.register_builtin_impl("__add__", op_t.clone(), Const, Public); + int.register_builtin_impl("__sub__", op_t.clone(), Const, Public); + int.register_builtin_impl("__mul__", op_t, Const, Public); + int.register_builtin_const("AddO", ValueObj::builtin_t(Int)); + int.register_builtin_const("SubO", ValueObj::builtin_t(Int)); + int.register_builtin_const("MulO", ValueObj::builtin_t(Int)); + int.register_builtin_const("DivO", ValueObj::builtin_t(Ratio)); + int.register_builtin_const("MutType!", ValueObj::builtin_t(mono("Int!"))); + int.register_builtin_impl("Real", Int, Const, Public); + int.register_builtin_impl("Imag", Int, Const, Public); let mut nat = Self::mono_class( "Nat", vec![Int, Ratio, Obj], vec![ - trait_("Ord"), - poly_trait("Eq", vec![ty_tp(Nat)]), - poly_trait("Add", vec![ty_tp(Nat)]), - poly_trait("Sub", vec![ty_tp(Nat)]), - poly_trait("Mul", vec![ty_tp(Nat)]), - poly_trait("Div", vec![ty_tp(Nat)]), - trait_("Num"), - // trait_("Rational"), - // trait_("Integral"), - trait_("Mutizable"), + mono("Ord"), + poly("Eq", vec![ty_tp(Nat)]), + poly("Add", vec![ty_tp(Nat)]), + poly("Sub", vec![ty_tp(Nat)]), + poly("Mul", vec![ty_tp(Nat)]), + poly("Div", vec![ty_tp(Nat)]), + mono("Num"), + // class("Rational"), + // class("Integral"), + mono("Mutizable"), ], Self::TOP_LEVEL, ); // __sub__, __div__ is not included in Nat (cast to Int) let op_t = fn1_met(Nat, Nat, Nat); - nat.register_impl("__add__", op_t.clone(), Const, Public); - nat.register_impl("__mul__", op_t, Const, Public); - nat.register_impl( + nat.register_builtin_impl("__add__", op_t.clone(), Const, Public); + nat.register_builtin_impl("__mul__", op_t, Const, Public); + nat.register_builtin_impl( "times!", pr_met( Nat, - None, vec![param_t("p", nd_proc(vec![], None, NoneType))], None, vec![], @@ -447,103 +432,103 @@ impl Context { Immutable, Public, ); - nat.register_const("AddO", ValueObj::t(Nat)); - nat.register_const("SubO", ValueObj::t(Int)); - nat.register_const("MulO", ValueObj::t(Nat)); - nat.register_const("DivO", ValueObj::t(Ratio)); - nat.register_const("MutType!", ValueObj::t(class("Nat!"))); - nat.register_impl("Real", Nat, Const, Public); - nat.register_impl("Imag", Nat, Const, Public); + nat.register_builtin_const("AddO", ValueObj::builtin_t(Nat)); + nat.register_builtin_const("SubO", ValueObj::builtin_t(Int)); + nat.register_builtin_const("MulO", ValueObj::builtin_t(Nat)); + nat.register_builtin_const("DivO", ValueObj::builtin_t(Ratio)); + nat.register_builtin_const("MutType!", ValueObj::builtin_t(mono("Nat!"))); + nat.register_builtin_impl("Real", Nat, Const, Public); + nat.register_builtin_impl("Imag", Nat, Const, Public); let mut float = Self::mono_class( "Float", vec![Obj], vec![ - trait_("Num"), - // trait_("Eq"), // Float doesn't have an Eq implementation - trait_("Ord"), - poly_trait("Add", vec![ty_tp(Float)]), - poly_trait("Sub", vec![ty_tp(Float)]), - poly_trait("Mul", vec![ty_tp(Float)]), - poly_trait("Div", vec![ty_tp(Float)]), - trait_("Mutizable"), + mono("Num"), + // class("Eq"), // Float doesn't have an Eq implementation + mono("Ord"), + poly("Add", vec![ty_tp(Float)]), + poly("Sub", vec![ty_tp(Float)]), + poly("Mul", vec![ty_tp(Float)]), + poly("Div", vec![ty_tp(Float)]), + mono("Mutizable"), ], Self::TOP_LEVEL, ); let op_t = fn1_met(Float, Float, Float); - float.register_impl("__add__", op_t.clone(), Const, Public); - float.register_impl("__sub__", op_t.clone(), Const, Public); - float.register_impl("__mul__", op_t.clone(), Const, Public); - float.register_impl("__div__", op_t, Const, Public); - float.register_const("AddO", ValueObj::t(Float)); - float.register_const("SubO", ValueObj::t(Float)); - float.register_const("MulO", ValueObj::t(Float)); - float.register_const("DivO", ValueObj::t(Float)); - float.register_const("MutType!", ValueObj::t(class("Float!"))); - float.register_impl("Real", Float, Const, Public); - float.register_impl("Imag", Float, Const, Public); + float.register_builtin_impl("__add__", op_t.clone(), Const, Public); + float.register_builtin_impl("__sub__", op_t.clone(), Const, Public); + float.register_builtin_impl("__mul__", op_t.clone(), Const, Public); + float.register_builtin_impl("__div__", op_t, Const, Public); + float.register_builtin_const("AddO", ValueObj::builtin_t(Float)); + float.register_builtin_const("SubO", ValueObj::builtin_t(Float)); + float.register_builtin_const("MulO", ValueObj::builtin_t(Float)); + float.register_builtin_const("DivO", ValueObj::builtin_t(Float)); + float.register_builtin_const("MutType!", ValueObj::builtin_t(mono("Float!"))); + float.register_builtin_impl("Real", Float, Const, Public); + float.register_builtin_impl("Imag", Float, Const, Public); let mut ratio = Self::mono_class( "Ratio", vec![Obj], vec![ - trait_("Num"), - poly_trait("Eq", vec![ty_tp(Ratio)]), - trait_("Ord"), - poly_trait("Add", vec![ty_tp(Ratio)]), - poly_trait("Sub", vec![ty_tp(Ratio)]), - poly_trait("Mul", vec![ty_tp(Ratio)]), - poly_trait("Div", vec![ty_tp(Ratio)]), - trait_("Mutizable"), + mono("Num"), + poly("Eq", vec![ty_tp(Ratio)]), + mono("Ord"), + poly("Add", vec![ty_tp(Ratio)]), + poly("Sub", vec![ty_tp(Ratio)]), + poly("Mul", vec![ty_tp(Ratio)]), + poly("Div", vec![ty_tp(Ratio)]), + mono("Mutizable"), ], Self::TOP_LEVEL, ); let op_t = fn1_met(Ratio, Ratio, Ratio); - ratio.register_impl("__add__", op_t.clone(), Const, Public); - ratio.register_impl("__sub__", op_t.clone(), Const, Public); - ratio.register_impl("__mul__", op_t.clone(), Const, Public); - ratio.register_impl("__div__", op_t, Const, Public); - ratio.register_const("AddO", ValueObj::t(Ratio)); - ratio.register_const("SubO", ValueObj::t(Ratio)); - ratio.register_const("MulO", ValueObj::t(Ratio)); - ratio.register_const("DivO", ValueObj::t(Ratio)); - ratio.register_const("MutType!", ValueObj::t(class("Ratio!"))); - ratio.register_impl("Real", Ratio, Const, Public); - ratio.register_impl("Imag", Ratio, Const, Public); + ratio.register_builtin_impl("__add__", op_t.clone(), Const, Public); + ratio.register_builtin_impl("__sub__", op_t.clone(), Const, Public); + ratio.register_builtin_impl("__mul__", op_t.clone(), Const, Public); + ratio.register_builtin_impl("__div__", op_t, Const, Public); + ratio.register_builtin_const("AddO", ValueObj::builtin_t(Ratio)); + ratio.register_builtin_const("SubO", ValueObj::builtin_t(Ratio)); + ratio.register_builtin_const("MulO", ValueObj::builtin_t(Ratio)); + ratio.register_builtin_const("DivO", ValueObj::builtin_t(Ratio)); + ratio.register_builtin_const("MutType!", ValueObj::builtin_t(mono("Ratio!"))); + ratio.register_builtin_impl("Real", Ratio, Const, Public); + ratio.register_builtin_impl("Imag", Ratio, Const, Public); let mut bool_ = Self::mono_class( "Bool", vec![Nat, Int, Ratio, Obj], vec![ - trait_("Num"), - // trait_("Rational"), - // trait_("Integral"), - poly_trait("Eq", vec![ty_tp(Bool)]), - poly_trait("Add", vec![ty_tp(Bool)]), - trait_("Ord"), + mono("Num"), + // class("Rational"), + // class("Integral"), + poly("Eq", vec![ty_tp(Bool)]), + poly("Add", vec![ty_tp(Bool)]), + mono("Ord"), // mono("SelfAdd"), // mono("SelfSub"), // mono("SelfMul"), // mono("SelfDiv"), - trait_("Mutizable"), + mono("Mutizable"), ], Self::TOP_LEVEL, ); - bool_.register_impl("__and__", fn1_met(Bool, Bool, Bool), Const, Public); - bool_.register_impl("__or__", fn1_met(Bool, Bool, Bool), Const, Public); - bool_.register_const("MutType!", ValueObj::t(class("Bool!"))); + bool_.register_builtin_impl("__and__", fn1_met(Bool, Bool, Bool), Const, Public); + bool_.register_builtin_impl("__or__", fn1_met(Bool, Bool, Bool), Const, Public); + bool_.register_builtin_const("MutType!", ValueObj::builtin_t(mono("Bool!"))); let mut str_ = Self::mono_class( "Str", vec![Obj], vec![ - poly_trait("Eq", vec![ty_tp(Str)]), - trait_("Ord"), - trait_("Mutizable"), - poly_trait("Seq", vec![ty_tp(Str)]), - poly_trait("Add", vec![ty_tp(Str)]), - poly_trait("Mul", vec![ty_tp(Nat)]), + poly("Eq", vec![ty_tp(Str)]), + mono("Ord"), + mono("Mutizable"), + poly("Seq", vec![ty_tp(Str)]), + poly("Add", vec![ty_tp(Str)]), + poly("Mul", vec![ty_tp(Nat)]), ], Self::TOP_LEVEL, ); - str_.register_impl("__add__", fn1_met(Str, Str, Str), Const, Public); - str_.register_impl( + str_.register_builtin_impl("__add__", fn1_met(Str, Str, Str), Const, Public); + str_.register_builtin_impl( "replace", fn_met( Str, @@ -555,36 +540,46 @@ impl Context { Immutable, Public, ); - str_.register_impl( + str_.register_builtin_impl( "encode", fn_met( Str, vec![], None, vec![param_t("encoding", Str), param_t("errors", Str)], - class("Bytes"), + mono("Bytes"), ), Immutable, Public, ); - str_.register_const("AddO", ValueObj::t(Str)); - str_.register_const("MulO", ValueObj::t(Str)); - str_.register_const("MutType!", ValueObj::t(class("Str!"))); + str_.register_builtin_const("AddO", ValueObj::builtin_t(Str)); + str_.register_builtin_const("MulO", ValueObj::builtin_t(Str)); + str_.register_builtin_const("MutType!", ValueObj::builtin_t(mono("Str!"))); let mut type_ = Self::mono_class( "Type", vec![Obj], vec![ - poly_trait("Eq", vec![ty_tp(Type)]), - poly_trait("In", vec![ty_tp(Obj)]), // x in Type - trait_("Named"), + poly("Eq", vec![ty_tp(Type)]), + poly("In", vec![ty_tp(Obj)]), // x in Type + mono("Named"), + ], + Self::TOP_LEVEL, + ); + type_.register_builtin_impl("mro", array(Type, TyParam::erased(Nat)), Immutable, Public); + let class_type = Self::mono_class( + "ClassType", + vec![Type, Obj], + vec![ + poly("Eq", vec![ty_tp(Class)]), + poly("In", vec![ty_tp(Obj)]), // x in Class + mono("Named"), ], Self::TOP_LEVEL, ); - type_.register_impl("mro", array(Type, TyParam::erased(Nat)), Immutable, Public); let module = Self::mono_class( "Module", vec![Obj], - vec![poly_trait("Eq", vec![ty_tp(Module)]), trait_("Named")], + vec![poly("Eq", vec![ty_tp(Module)]), mono("Named")], Self::TOP_LEVEL, ); let mut array_ = Self::poly_class( @@ -592,16 +587,16 @@ impl Context { vec![PS::t_nd("T"), PS::named_nd("N", Nat)], vec![Obj], vec![ - poly_trait( + poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")], ))], ), - trait_("Mutizable"), - poly_trait("Seq", vec![ty_tp(mono_q("T"))]), - poly_trait("Output", vec![ty_tp(mono_q("T"))]), + mono("Mutizable"), + poly("Seq", vec![ty_tp(mono_q("T"))]), + poly("Output", vec![ty_tp(mono_q("T"))]), ], Self::TOP_LEVEL, ); @@ -619,7 +614,7 @@ impl Context { t, set! {static_instance("N", Nat), static_instance("M", Nat)}, ); - array_.register_impl("concat", t, Immutable, Public); + array_.register_builtin_impl("concat", t, Immutable, Public); let n = mono_q_tp("N"); let array_inner = mono_q("T"); let array_t = array(array_inner.clone(), n.clone()); @@ -636,45 +631,45 @@ impl Context { ); let t = quant( t, - set! {static_instance("N", Nat), static_instance("T", trait_("Mutable"))}, + set! {static_instance("N", Nat), static_instance("T", mono("Mutable"))}, ); - array_.register_impl("map!", t, Immutable, Public); - let mut_type = ValueObj::t(poly_class( + array_.register_builtin_impl("map!", t, Immutable, Public); + let mut_type = ValueObj::builtin_t(poly( "Array!", vec![TyParam::t(mono_q("T")), TyParam::mono_q("N").mutate()], )); // [T; N].MutType! = [T; !N] (neither [T!; N] nor [T; N]!) - array_.register_const("MutType!", mut_type); + array_.register_builtin_const("MutType!", mut_type); let mut int_mut = Self::mono_class( "Int!", - vec![Int, class("Ratio!"), Obj], - vec![trait_("Mutable")], + vec![Int, mono("Ratio!"), Obj], + vec![mono("Mutable")], Self::TOP_LEVEL, ); // TODO: make Tuple6, Tuple7, ... etc. let tuple_ = Self::mono_class( "Tuple", vec![Obj], - vec![poly_trait("Eq", vec![ty_tp(class("Tuple"))])], + vec![poly("Eq", vec![ty_tp(mono("Tuple"))])], Self::TOP_LEVEL, ); let tuple1 = Self::poly_class( "Tuple1", vec![PS::t_nd("A")], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class("Tuple1", vec![ty_tp(mono_q("A"))]))], + vec![ty_tp(poly("Tuple1", vec![ty_tp(mono_q("A"))]))], )], Self::TOP_LEVEL, ); let tuple2 = Self::poly_class( "Tuple2", vec![PS::t_nd("A"), PS::t_nd("B")], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Tuple2", vec![ty_tp(mono_q("A")), ty_tp(mono_q("B"))], ))], @@ -684,10 +679,10 @@ impl Context { let tuple3 = Self::poly_class( "Tuple3", vec![PS::t_nd("A"), PS::t_nd("B"), PS::t_nd("C")], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Tuple3", vec![ty_tp(mono_q("A")), ty_tp(mono_q("B")), ty_tp(mono_q("C"))], ))], @@ -697,10 +692,10 @@ impl Context { let tuple4 = Self::poly_class( "Tuple4", vec![PS::t_nd("A"), PS::t_nd("B"), PS::t_nd("C"), PS::t_nd("D")], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Tuple4", vec![ ty_tp(mono_q("A")), @@ -721,10 +716,10 @@ impl Context { PS::t_nd("D"), PS::t_nd("E"), ], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Tuple5", vec![ ty_tp(mono_q("A")), @@ -747,10 +742,10 @@ impl Context { PS::t_nd("E"), PS::t_nd("F"), ], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Tuple6", vec![ ty_tp(mono_q("A")), @@ -775,10 +770,10 @@ impl Context { PS::t_nd("F"), PS::t_nd("G"), ], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Tuple7", vec![ ty_tp(mono_q("A")), @@ -805,10 +800,10 @@ impl Context { PS::t_nd("G"), PS::t_nd("H"), ], - vec![class("Tuple"), Obj], - vec![poly_trait( + vec![mono("Tuple"), Obj], + vec![poly( "Eq", - vec![ty_tp(poly_class( + vec![ty_tp(poly( "Tuple8", vec![ ty_tp(mono_q("A")), @@ -824,88 +819,120 @@ impl Context { )], Self::TOP_LEVEL, ); - int_mut.register_const("ImmutType", ValueObj::t(Int)); + int_mut.register_builtin_const("ImmutType", ValueObj::builtin_t(Int)); let f_t = param_t("f", func(vec![param_t("old", Int)], None, vec![], Int)); - let t = pr_met(class("Int!"), None, vec![f_t], None, vec![], NoneType); - int_mut.register_impl("update!", t, Immutable, Public); + let t = pr_met( + ref_mut(mono("Int!"), None), + vec![f_t], + None, + vec![], + NoneType, + ); + int_mut.register_builtin_impl("update!", t, Immutable, Public); let mut nat_mut = Self::mono_class( "Nat!", - vec![Nat, class("Int!"), class("Ratio!"), Obj], - vec![trait_("Mutable")], + vec![Nat, mono("Int!"), mono("Ratio!"), Obj], + vec![mono("Mutable")], Self::TOP_LEVEL, ); - nat_mut.register_const("ImmutType", ValueObj::t(Nat)); + nat_mut.register_builtin_const("ImmutType", ValueObj::builtin_t(Nat)); let f_t = param_t("f", func(vec![param_t("old", Nat)], None, vec![], Nat)); - let t = pr_met(class("Nat!"), None, vec![f_t], None, vec![], NoneType); - nat_mut.register_impl("update!", t, Immutable, Public); + let t = pr_met( + ref_mut(mono("Nat!"), None), + vec![f_t], + None, + vec![], + NoneType, + ); + nat_mut.register_builtin_impl("update!", t, Immutable, Public); let mut float_mut = Self::mono_class( "Float!", vec![Float, Obj], - vec![trait_("Mutable")], + vec![mono("Mutable")], Self::TOP_LEVEL, ); - float_mut.register_const("ImmutType", ValueObj::t(Float)); + float_mut.register_builtin_const("ImmutType", ValueObj::builtin_t(Float)); let f_t = param_t("f", func(vec![param_t("old", Float)], None, vec![], Float)); - let t = pr_met(class("Float!"), None, vec![f_t], None, vec![], NoneType); - float_mut.register_impl("update!", t, Immutable, Public); + let t = pr_met( + ref_mut(mono("Float!"), None), + vec![f_t], + None, + vec![], + NoneType, + ); + float_mut.register_builtin_impl("update!", t, Immutable, Public); let mut ratio_mut = Self::mono_class( "Ratio!", vec![Ratio, Obj], - vec![trait_("Mutable")], + vec![mono("Mutable")], Self::TOP_LEVEL, ); - ratio_mut.register_const("ImmutType", ValueObj::t(Ratio)); + ratio_mut.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio)); let f_t = param_t( "f", func( - vec![param_t("old", class("Ratio"))], + vec![param_t("old", mono("Ratio"))], None, vec![], - class("Ratio"), + mono("Ratio"), ), ); - let t = pr_met(class("Ratio!"), None, vec![f_t], None, vec![], NoneType); - ratio_mut.register_impl("update!", t, Immutable, Public); + let t = pr_met( + ref_mut(mono("Ratio!"), None), + vec![f_t], + None, + vec![], + NoneType, + ); + ratio_mut.register_builtin_impl("update!", t, Immutable, Public); let mut bool_mut = Self::mono_class( "Bool!", - vec![Bool, class("Nat!"), class("Int!"), class("Ratio!"), Obj], - vec![trait_("Mutable")], + vec![Bool, mono("Nat!"), mono("Int!"), mono("Ratio!"), Obj], + vec![mono("Mutable")], Self::TOP_LEVEL, ); - bool_mut.register_const("ImmutType", ValueObj::t(Bool)); + bool_mut.register_builtin_const("ImmutType", ValueObj::builtin_t(Bool)); let f_t = param_t("f", func(vec![param_t("old", Bool)], None, vec![], Bool)); - let t = pr_met(class("Bool!"), None, vec![f_t], None, vec![], NoneType); - bool_mut.register_impl("update!", t, Immutable, Public); + let t = pr_met( + ref_mut(mono("Bool!"), None), + vec![f_t], + None, + vec![], + NoneType, + ); + bool_mut.register_builtin_impl("update!", t, Immutable, Public); let mut str_mut = Self::mono_class( "Str!", vec![Str, Obj], - vec![trait_("Mutable")], + vec![mono("Mutable")], Self::TOP_LEVEL, ); - str_mut.register_const("ImmutType", ValueObj::t(Str)); + str_mut.register_builtin_const("ImmutType", ValueObj::builtin_t(Str)); let f_t = param_t("f", func(vec![param_t("old", Str)], None, vec![], Str)); - let t = pr_met(class("Str!"), None, vec![f_t], None, vec![], NoneType); - str_mut.register_impl("update!", t, Immutable, Public); - let array_mut_t = poly_class("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]); + let t = pr_met( + ref_mut(mono("Str!"), None), + vec![f_t], + None, + vec![], + NoneType, + ); + str_mut.register_builtin_impl("update!", t, Immutable, Public); + let array_mut_t = poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]); let mut array_mut = Self::poly_class( "Array!", - vec![PS::t_nd("T"), PS::named_nd("N", class("Nat!"))], - vec![ - poly_class("Range", vec![ty_tp(mono_q("T")), mono_q_tp("N")]), - Obj, - ], - vec![ - trait_("Mutizable"), - poly_trait("Seq", vec![ty_tp(mono_q("T"))]), - ], + vec![PS::t_nd("T"), PS::named_nd("N", mono("Nat!"))], + vec![poly("Range", vec![ty_tp(mono_q("T")), mono_q_tp("N")]), Obj], + vec![mono("Mutizable"), poly("Seq", vec![ty_tp(mono_q("T"))])], Self::TOP_LEVEL, ); let t = pr_met( - ref_mut(array_mut_t.clone()), - Some(ref_mut(poly_class( - "Array!", - vec![ty_tp(mono_q("T")), mono_q_tp("N") + value(1)], - ))), + ref_mut( + array_mut_t.clone(), + Some(poly( + "Array!", + vec![ty_tp(mono_q("T")), mono_q_tp("N") + value(1)], + )), + ), vec![param_t("elem", mono_q("T"))], None, vec![], @@ -913,9 +940,9 @@ impl Context { ); let t = quant( t, - set! {static_instance("T", Type), static_instance("N", class("Nat!"))}, + set! {static_instance("T", Type), static_instance("N", mono("Nat!"))}, ); - array_mut.register_impl("push!", t, Immutable, Public); + array_mut.register_builtin_impl("push!", t, Immutable, Public); let f_t = param_t( "f", func( @@ -925,61 +952,60 @@ impl Context { array_t.clone(), ), ); - let t = pr_met(array_mut_t.clone(), None, vec![f_t], None, vec![], NoneType); - array_mut.register_impl("update!", t, Immutable, Public); - let range_t = poly_class("Range", vec![TyParam::t(mono_q("T"))]); + let t = pr_met( + ref_mut(array_mut_t.clone(), None), + vec![f_t], + None, + vec![], + NoneType, + ); + array_mut.register_builtin_impl("update!", t, Immutable, Public); + let range_t = poly("Range", vec![TyParam::t(mono_q("T"))]); let range = Self::poly_class( "Range", vec![PS::t_nd("T")], vec![Obj], vec![ - poly_trait( - "Eq", - vec![ty_tp(poly_class("Range", vec![ty_tp(mono_q("T"))]))], - ), - trait_("Mutizable"), - poly_trait("Seq", vec![ty_tp(mono_q("T"))]), - poly_trait("Output", vec![ty_tp(mono_q("T"))]), + poly("Eq", vec![ty_tp(poly("Range", vec![ty_tp(mono_q("T"))]))]), + mono("Mutizable"), + poly("Seq", vec![ty_tp(mono_q("T"))]), + poly("Output", vec![ty_tp(mono_q("T"))]), ], Self::TOP_LEVEL, ); - let func = Self::mono_class( - "Function", - vec![Obj], - vec![trait_("Named")], - Self::TOP_LEVEL, - ); + let func = Self::mono_class("Function", vec![Obj], vec![mono("Named")], Self::TOP_LEVEL); let qfunc = Self::mono_class( "QuantifiedFunction", - vec![class("Function"), Obj], + vec![mono("Function"), Obj], vec![], Self::TOP_LEVEL, ); - self.register_type(Obj, obj, Const); + self.register_builtin_type(Obj, obj, Const); // self.register_type(mono("Record"), vec![], record, Const); // self.register_type(mono("Class"), vec![], class, Const); - self.register_type(Int, int, Const); - self.register_type(Nat, nat, Const); - self.register_type(Float, float, Const); - self.register_type(Ratio, ratio, Const); - self.register_type(Bool, bool_, Const); - self.register_type(Str, str_, Const); - self.register_type(Type, type_, Const); - self.register_type(Module, module, Const); - self.register_type(array_t, array_, Const); - self.register_type(tuple(vec![mono_q("A")]), tuple1, Const); - self.register_type(tuple(vec![mono_q("A"), mono_q("B")]), tuple2, Const); - self.register_type( + self.register_builtin_type(Int, int, Const); + self.register_builtin_type(Nat, nat, Const); + self.register_builtin_type(Float, float, Const); + self.register_builtin_type(Ratio, ratio, Const); + self.register_builtin_type(Bool, bool_, Const); + self.register_builtin_type(Str, str_, Const); + self.register_builtin_type(Type, type_, Const); + self.register_builtin_type(Class, class_type, Const); + self.register_builtin_type(Module, module, Const); + self.register_builtin_type(array_t, array_, Const); + self.register_builtin_type(tuple(vec![mono_q("A")]), tuple1, Const); + self.register_builtin_type(tuple(vec![mono_q("A"), mono_q("B")]), tuple2, Const); + self.register_builtin_type( tuple(vec![mono_q("A"), mono_q("B"), mono_q("C")]), tuple3, Const, ); - self.register_type( + self.register_builtin_type( tuple(vec![mono_q("A"), mono_q("B"), mono_q("C"), mono_q("D")]), tuple4, Const, ); - self.register_type( + self.register_builtin_type( tuple(vec![ mono_q("A"), mono_q("B"), @@ -990,7 +1016,7 @@ impl Context { tuple5, Const, ); - self.register_type( + self.register_builtin_type( tuple(vec![ mono_q("A"), mono_q("B"), @@ -1002,7 +1028,7 @@ impl Context { tuple6, Const, ); - self.register_type( + self.register_builtin_type( tuple(vec![ mono_q("A"), mono_q("B"), @@ -1015,7 +1041,7 @@ impl Context { tuple7, Const, ); - self.register_type( + self.register_builtin_type( tuple(vec![ mono_q("A"), mono_q("B"), @@ -1029,21 +1055,21 @@ impl Context { tuple8, Const, ); - self.register_type(class("Int!"), int_mut, Const); - self.register_type(class("Nat!"), nat_mut, Const); - self.register_type(class("Float!"), float_mut, Const); - self.register_type(class("Ratio!"), ratio_mut, Const); - self.register_type(class("Bool!"), bool_mut, Const); - self.register_type(class("Str!"), str_mut, Const); - self.register_type(array_mut_t, array_mut, Const); - self.register_type(range_t, range, Const); - self.register_type(class("Tuple"), tuple_, Const); - self.register_type(class("Function"), func, Const); - self.register_type(class("QuantifiedFunction"), qfunc, Const); + self.register_builtin_type(mono("Int!"), int_mut, Const); + self.register_builtin_type(mono("Nat!"), nat_mut, Const); + self.register_builtin_type(mono("Float!"), float_mut, Const); + self.register_builtin_type(mono("Ratio!"), ratio_mut, Const); + self.register_builtin_type(mono("Bool!"), bool_mut, Const); + self.register_builtin_type(mono("Str!"), str_mut, Const); + self.register_builtin_type(array_mut_t, array_mut, Const); + self.register_builtin_type(range_t, range, Const); + self.register_builtin_type(mono("Tuple"), tuple_, Const); + self.register_builtin_type(mono("Function"), func, Const); + self.register_builtin_type(mono("QuantifiedFunction"), qfunc, Const); } fn init_builtin_funcs(&mut self) { - let t_abs = nd_func(vec![param_t("n", trait_("Num"))], None, Nat); + let t_abs = nd_func(vec![param_t("n", mono("Num"))], None, Nat); let t_assert = func( vec![param_t("condition", Bool)], None, @@ -1082,28 +1108,55 @@ impl Context { vec![ param_t("sep", Str), param_t("end", Str), - param_t("file", class("Write")), + param_t("file", mono("Write")), param_t("flush", Bool), ], NoneType, ); let t_pyimport = nd_func(vec![param_t("path", Str)], None, Module); let t_quit = func(vec![], None, vec![param_t("code", Int)], NoneType); - self.register_impl("abs", t_abs, Const, Private); - self.register_impl("assert", t_assert, Const, Private); - self.register_impl("classof", t_classof, Const, Private); - self.register_impl("compile", t_compile, Const, Private); - self.register_impl("cond", t_cond, Const, Private); - self.register_impl("discard", t_discard, Const, Private); - self.register_impl("id", t_id, Const, Private); - self.register_impl("if", t_if, Const, Private); - self.register_impl("log", t_log, Const, Private); - self.register_impl("import", t_import, Const, Private); + self.register_builtin_impl("abs", t_abs, Const, Private); + self.register_builtin_impl("assert", t_assert, Const, Private); + self.register_builtin_impl("classof", t_classof, Const, Private); + self.register_builtin_impl("compile", t_compile, Const, Private); + self.register_builtin_impl("cond", t_cond, Const, Private); + self.register_builtin_impl("discard", t_discard, Const, Private); + self.register_builtin_impl("id", t_id, Const, Private); + self.register_builtin_impl("if", t_if, Const, Private); + self.register_builtin_impl("log", t_log, Const, Private); + self.register_builtin_impl("import", t_import, Const, Private); if cfg!(feature = "debug") { - self.register_impl("py", t_pyimport.clone(), Const, Private); + self.register_builtin_impl("py", t_pyimport.clone(), Const, Private); } - self.register_impl("pyimport", t_pyimport, Const, Private); - self.register_impl("quit", t_quit, Const, Private); + self.register_builtin_impl("pyimport", t_pyimport, Const, Private); + self.register_builtin_impl("quit", t_quit, Const, Private); + } + + fn init_builtin_const_funcs(&mut self) { + let class_t = func( + vec![param_t("Requirement", Type)], + None, + vec![param_t("Impl", Type)], + Class, + ); + let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t)); + self.register_builtin_const("Class", ValueObj::Subr(class)); + let inherit_t = func( + vec![param_t("Super", Class)], + None, + vec![param_t("Impl", Type), param_t("Additional", Type)], + Class, + ); + let inherit = ConstSubr::Builtin(BuiltinConstSubr::new("Inherit", inherit_func, inherit_t)); + self.register_builtin_const("Inherit", ValueObj::Subr(inherit)); + // decorators + let inheritable_t = func1(Class, Class); + let inheritable = ConstSubr::Builtin(BuiltinConstSubr::new( + "Inheritable", + inheritable_func, + inheritable_t, + )); + self.register_builtin_const("Inheritable", ValueObj::Subr(inheritable)); } fn init_builtin_procs(&mut self) { @@ -1113,7 +1166,7 @@ impl Context { vec![ param_t("sep", Str), param_t("end", Str), - param_t("file", class("Write")), + param_t("file", mono("Write")), param_t("flush", Bool), ], NoneType, @@ -1140,17 +1193,17 @@ impl Context { let t_for = quant(t_for, set! {static_instance("T", Type)}); let t_while = nd_proc( vec![ - param_t("cond", class("Bool!")), + param_t("cond", mono("Bool!")), param_t("p", nd_proc(vec![], None, NoneType)), ], None, NoneType, ); - self.register_impl("print!", t_print, Const, Private); - self.register_impl("input!", t_input, Const, Private); - self.register_impl("if!", t_if, Const, Private); - self.register_impl("for!", t_for, Const, Private); - self.register_impl("while!", t_while, Const, Private); + self.register_builtin_impl("print!", t_print, Const, Private); + self.register_builtin_impl("input!", t_input, Const, Private); + self.register_builtin_impl("if!", t_if, Const, Private); + self.register_builtin_impl("for!", t_for, Const, Private); + self.register_builtin_impl("while!", t_while, Const, Private); } fn init_builtin_operators(&mut self) { @@ -1167,84 +1220,84 @@ impl Context { op_t, set! { static_instance("R", Type), - subtypeof(l.clone(), poly_trait("Add", params.clone())) + subtypeof(l.clone(), poly("Add", params.clone())) }, ); - self.register_impl("__add__", op_t, Const, Private); + self.register_builtin_impl("__add__", op_t, Const, Private); let op_t = bin_op(l.clone(), r.clone(), mono_proj(mono_q("L"), "SubO")); let op_t = quant( op_t, set! { static_instance("R", Type), - subtypeof(l.clone(), poly_trait("Sub", params.clone())) + subtypeof(l.clone(), poly("Sub", params.clone())) }, ); - self.register_impl("__sub__", op_t, Const, Private); + self.register_builtin_impl("__sub__", op_t, Const, Private); let op_t = bin_op(l.clone(), r.clone(), mono_proj(mono_q("L"), "MulO")); let op_t = quant( op_t, set! { static_instance("R", Type), - subtypeof(l.clone(), poly_trait("Mul", params.clone())) + subtypeof(l.clone(), poly("Mul", params.clone())) }, ); - self.register_impl("__mul__", op_t, Const, Private); + self.register_builtin_impl("__mul__", op_t, Const, Private); let op_t = bin_op(l.clone(), r.clone(), mono_proj(mono_q("L"), "DivO")); let op_t = quant( op_t, set! { static_instance("R", Type), - subtypeof(l, poly_trait("Mul", params.clone())) + subtypeof(l, poly("Mul", params.clone())) }, ); - self.register_impl("__div__", op_t, Const, Private); + self.register_builtin_impl("__div__", op_t, Const, Private); let m = mono_q("M"); let op_t = bin_op(m.clone(), m.clone(), m.clone()); - let op_t = quant(op_t, set! {subtypeof(m, poly_trait("Mul", vec![]))}); + let op_t = quant(op_t, set! {subtypeof(m, poly("Mul", vec![]))}); // TODO: add bound: M == MulO - self.register_impl("__pow__", op_t, Const, Private); + self.register_builtin_impl("__pow__", op_t, Const, Private); let d = mono_q("D"); let op_t = bin_op(d.clone(), d.clone(), d.clone()); - let op_t = quant(op_t, set! {subtypeof(d, poly_trait("Div", vec![]))}); - self.register_impl("__mod__", op_t, Const, Private); + let op_t = quant(op_t, set! {subtypeof(d, poly("Div", vec![]))}); + self.register_builtin_impl("__mod__", op_t, Const, Private); let e = mono_q("E"); let op_t = bin_op(e.clone(), e.clone(), Bool); - let op_t = quant(op_t, set! {subtypeof(e, poly_trait("Eq", vec![]))}); - self.register_impl("__eq__", op_t.clone(), Const, Private); - self.register_impl("__ne__", op_t, Const, Private); + let op_t = quant(op_t, set! {subtypeof(e, poly("Eq", vec![]))}); + self.register_builtin_impl("__eq__", op_t.clone(), Const, Private); + self.register_builtin_impl("__ne__", op_t, Const, Private); let o = mono_q("O"); let op_t = bin_op(o.clone(), o.clone(), Bool); - let op_t = quant(op_t, set! {subtypeof(o, trait_("Ord"))}); - self.register_impl("__lt__", op_t.clone(), Const, Private); - self.register_impl("__le__", op_t.clone(), Const, Private); - self.register_impl("__gt__", op_t.clone(), Const, Private); - self.register_impl("__ge__", op_t, Const, Private); - self.register_impl("__and__", bin_op(Bool, Bool, Bool), Const, Private); - self.register_impl("__or__", bin_op(Bool, Bool, Bool), Const, Private); + let op_t = quant(op_t, set! {subtypeof(o, mono("Ord"))}); + self.register_builtin_impl("__lt__", op_t.clone(), Const, Private); + self.register_builtin_impl("__le__", op_t.clone(), Const, Private); + self.register_builtin_impl("__gt__", op_t.clone(), Const, Private); + self.register_builtin_impl("__ge__", op_t, Const, Private); + self.register_builtin_impl("__and__", bin_op(Bool, Bool, Bool), Const, Private); + self.register_builtin_impl("__or__", bin_op(Bool, Bool, Bool), Const, Private); let t = mono_q("T"); let op_t = bin_op(t.clone(), t.clone(), range(t.clone())); - let op_t = quant(op_t, set! {subtypeof(t.clone(), trait_("Ord"))}); - self.register_decl("__rng__", op_t.clone(), Private); - self.register_decl("__lorng__", op_t.clone(), Private); - self.register_decl("__rorng__", op_t.clone(), Private); - self.register_decl("__orng__", op_t, Private); + let op_t = quant(op_t, set! {subtypeof(t.clone(), mono("Ord"))}); + self.register_builtin_decl("__rng__", op_t.clone(), Private); + self.register_builtin_decl("__lorng__", op_t.clone(), Private); + self.register_builtin_decl("__rorng__", op_t.clone(), Private); + self.register_builtin_decl("__orng__", op_t, Private); // TODO: use existential type: |T: Type| (T, In(T)) -> Bool let op_t = bin_op(mono_q("T"), mono_q("I"), Bool); let op_t = quant( op_t, - set! { static_instance("T", Type), subtypeof(mono_q("I"), poly_trait("In", vec![ty_tp(mono_q("T"))])) }, + set! { static_instance("T", Type), subtypeof(mono_q("I"), poly("In", vec![ty_tp(mono_q("T"))])) }, ); - self.register_impl("__in__", op_t, Const, Private); + self.register_builtin_impl("__in__", op_t, Const, Private); /* unary */ // TODO: Boolの+/-は警告を出したい let op_t = func1(mono_q("T"), mono_proj(mono_q("T"), "MutType!")); - let op_t = quant(op_t, set! {subtypeof(mono_q("T"), trait_("Mutizable"))}); - self.register_impl("__mutate__", op_t, Const, Private); + let op_t = quant(op_t, set! {subtypeof(mono_q("T"), mono("Mutizable"))}); + self.register_builtin_impl("__mutate__", op_t, Const, Private); let n = mono_q("N"); let op_t = func1(n.clone(), n.clone()); - let op_t = quant(op_t, set! {subtypeof(n, trait_("Num"))}); - self.register_decl("__pos__", op_t.clone(), Private); - self.register_decl("__neg__", op_t, Private); + let op_t = quant(op_t, set! {subtypeof(n, mono("Num"))}); + self.register_builtin_decl("__pos__", op_t.clone(), Private); + self.register_builtin_decl("__neg__", op_t, Private); } fn init_builtin_patches(&mut self) { @@ -1264,8 +1317,8 @@ impl Context { params, vec![Type::from(&m..=&n)], vec![ - poly_trait("Add", vec![TyParam::from(&o..=&p)]), - poly_trait("Sub", vec![TyParam::from(&o..=&p)]), + poly("Add", vec![TyParam::from(&o..=&p)]), + poly("Sub", vec![TyParam::from(&o..=&p)]), ], Self::TOP_LEVEL, ); @@ -1274,19 +1327,19 @@ impl Context { Type::from(&o..=&p), Type::from(m.clone() + o.clone()..=n.clone() + p.clone()), ); - interval.register_impl("__add__", op_t, Const, Public); + interval.register_builtin_impl("__add__", op_t, Const, Public); let op_t = fn1_met( Type::from(&m..=&n), Type::from(&o..=&p), Type::from(m.clone() - p.clone()..=n.clone() - o.clone()), ); - interval.register_impl("__sub__", op_t, Const, Public); - interval.register_const( + interval.register_builtin_impl("__sub__", op_t, Const, Public); + interval.register_builtin_const( "AddO", - ValueObj::t(Type::from(m.clone() + o.clone()..=n.clone() + p.clone())), + ValueObj::builtin_t(Type::from(m.clone() + o.clone()..=n.clone() + p.clone())), ); - interval.register_const("SubO", ValueObj::t(Type::from(m - p..=n - o))); - self.register_patch("Interval", interval, Const); + interval.register_builtin_const("SubO", ValueObj::builtin_t(Type::from(m - p..=n - o))); + self.register_builtin_patch("Interval", interval, Const); // eq.register_impl("__ne__", op_t, Const, Public); // ord.register_impl("__le__", op_t.clone(), Const, Public); // ord.register_impl("__gt__", op_t.clone(), Const, Public); @@ -1297,6 +1350,7 @@ impl Context { // TODO: capacityを正確に把握する let mut ctx = Context::module("".into(), 40); ctx.init_builtin_funcs(); + ctx.init_builtin_const_funcs(); ctx.init_builtin_procs(); ctx.init_builtin_operators(); ctx.init_builtin_traits(); diff --git a/compiler/erg_compiler/context/initialize/importlib.rs b/compiler/erg_compiler/context/initialize/py_mods/importlib.rs similarity index 79% rename from compiler/erg_compiler/context/initialize/importlib.rs rename to compiler/erg_compiler/context/initialize/py_mods/importlib.rs index 66e7e4b8..d23f8804 100644 --- a/compiler/erg_compiler/context/initialize/importlib.rs +++ b/compiler/erg_compiler/context/initialize/py_mods/importlib.rs @@ -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 } } diff --git a/compiler/erg_compiler/context/initialize/io.rs b/compiler/erg_compiler/context/initialize/py_mods/io.rs similarity index 69% rename from compiler/erg_compiler/context/initialize/io.rs rename to compiler/erg_compiler/context/initialize/py_mods/io.rs index 00451fbe..5f6d053d 100644 --- a/compiler/erg_compiler/context/initialize/io.rs +++ b/compiler/erg_compiler/context/initialize/py_mods/io.rs @@ -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 } } diff --git a/compiler/erg_compiler/context/initialize/py_mods/math.rs b/compiler/erg_compiler/context/initialize/py_mods/math.rs new file mode 100644 index 00000000..0bd63129 --- /dev/null +++ b/compiler/erg_compiler/context/initialize/py_mods/math.rs @@ -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 + } +} diff --git a/compiler/erg_compiler/context/initialize/py_mods/mod.rs b/compiler/erg_compiler/context/initialize/py_mods/mod.rs new file mode 100644 index 00000000..3b5006b4 --- /dev/null +++ b/compiler/erg_compiler/context/initialize/py_mods/mod.rs @@ -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; diff --git a/compiler/erg_compiler/context/initialize/random.rs b/compiler/erg_compiler/context/initialize/py_mods/random.rs similarity index 70% rename from compiler/erg_compiler/context/initialize/random.rs rename to compiler/erg_compiler/context/initialize/py_mods/random.rs index 51773079..09f02e1a 100644 --- a/compiler/erg_compiler/context/initialize/random.rs +++ b/compiler/erg_compiler/context/initialize/py_mods/random.rs @@ -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 } } diff --git a/compiler/erg_compiler/context/initialize/socket.rs b/compiler/erg_compiler/context/initialize/py_mods/socket.rs similarity index 80% rename from compiler/erg_compiler/context/initialize/socket.rs rename to compiler/erg_compiler/context/initialize/py_mods/socket.rs index 42ec4c32..af2e0f1c 100644 --- a/compiler/erg_compiler/context/initialize/socket.rs +++ b/compiler/erg_compiler/context/initialize/py_mods/socket.rs @@ -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 } } diff --git a/compiler/erg_compiler/context/initialize/py_mods/sys.rs b/compiler/erg_compiler/context/initialize/py_mods/sys.rs new file mode 100644 index 00000000..ae36ea30 --- /dev/null +++ b/compiler/erg_compiler/context/initialize/py_mods/sys.rs @@ -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 + } +} diff --git a/compiler/erg_compiler/context/initialize/time.rs b/compiler/erg_compiler/context/initialize/py_mods/time.rs similarity index 67% rename from compiler/erg_compiler/context/initialize/time.rs rename to compiler/erg_compiler/context/initialize/py_mods/time.rs index 4609eb0d..7b91ef9b 100644 --- a/compiler/erg_compiler/context/initialize/time.rs +++ b/compiler/erg_compiler/context/initialize/py_mods/time.rs @@ -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 } } diff --git a/compiler/erg_compiler/context/initialize/sys.rs b/compiler/erg_compiler/context/initialize/sys.rs deleted file mode 100644 index 1ad02502..00000000 --- a/compiler/erg_compiler/context/initialize/sys.rs +++ /dev/null @@ -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 - } -} diff --git a/compiler/erg_compiler/context/inquire.rs b/compiler/erg_compiler/context/inquire.rs index a1d74570..8ef20994 100644 --- a/compiler/erg_compiler/context/inquire.rs +++ b/compiler/erg_compiler/context/inquire.rs @@ -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 { - 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 { + 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 { let self_t = obj.t(); - match self_t { - Type => todo!(), - Type::Record(rec) => { - // REVIEW: `rec.get(name.inspect())` returns None (Borrow 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 { + 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 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, + method_name: &Option, namespace: &Str, ) -> TyCheckResult { 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[..] != "" + && &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, + method_name: &Option, 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, + method_name: &Option, pos_args: &[hir::PosArg], kw_args: &[hir::KwArg], namespace: &Str, ) -> TyCheckResult { 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 { 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 { - 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> { + 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 { + ) -> Option> { // 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 { - 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> { + 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>) + .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> { 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 { + 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!() + } + } } diff --git a/compiler/erg_compiler/context/instantiate.rs b/compiler/erg_compiler/context/instantiate.rs index b856be4c..8263ab7d 100644 --- a/compiler/erg_compiler/context/instantiate.rs +++ b/compiler/erg_compiler/context/instantiate.rs @@ -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 { 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 { - 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")), + )?; } _ => {} }, diff --git a/compiler/erg_compiler/context/mod.rs b/compiler/erg_compiler/context/mod.rs index 7913bc94..34f1fdd8 100644 --- a/compiler/erg_compiler/context/mod.rs +++ b/compiler/erg_compiler/context/mod.rs @@ -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 { 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, // if self is a patch, means patch classes pub(crate) super_traits: Vec, // 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, VarInfo)>, pub(crate) locals: Dict, pub(crate) consts: Dict, - pub(crate) eval: Evaluator, // {"Nat": ctx, "Int": ctx, ...} pub(crate) mono_types: Dict, // Implementation Contexts for Polymorphic Types // Vec 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, - // Traits cannot be specialized - pub(crate) poly_traits: Dict, + pub(crate) poly_types: Dict, // 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, @@ -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>(name: S, level: usize) -> Self { + Self::with_capacity( + name.into(), + ContextKind::MethodDefs, + vec![], + None, + vec![], + vec![], + 2, + level, + ) + } + #[inline] pub fn poly_patch>( 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 { 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( diff --git a/compiler/erg_compiler/context/register.rs b/compiler/erg_compiler/context/register.rs index 285e62dc..affbb9ef 100644 --- a/compiler/erg_compiler/context/register.rs +++ b/compiler/erg_compiler/context/register.rs @@ -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, @@ -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(¶m_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, diff --git a/compiler/erg_compiler/context/test.rs b/compiler/erg_compiler/context/test.rs index a2116faa..430cfb7d 100644 --- a/compiler/erg_compiler/context/test.rs +++ b/compiler/erg_compiler/context/test.rs @@ -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()); diff --git a/compiler/erg_compiler/context/tyvar.rs b/compiler/erg_compiler/context/tyvar.rs index e717eedd..7b660f83 100644 --- a/compiler/erg_compiler/context/tyvar.rs +++ b/compiler/erg_compiler/context/tyvar.rs @@ -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::>(); - 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::>(); - 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!(), diff --git a/compiler/erg_compiler/effectcheck.rs b/compiler/erg_compiler/effectcheck.rs index dfc7aea3..0514817b 100644 --- a/compiler/erg_compiler/effectcheck.rs +++ b/compiler/erg_compiler/effectcheck.rs @@ -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, } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 94c452ed..a05c60da 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -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::::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>( + 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)] diff --git a/compiler/erg_compiler/hir.rs b/compiler/erg_compiler/hir.rs index c2253441..e50c8804 100644 --- a/compiler/erg_compiler/hir.rs +++ b/compiler/erg_compiler/hir.rs @@ -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, + pub var_args: Option>, pub kw_args: Vec, 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> for Args { fn from(exprs: Vec) -> 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, + var_args: Option, kw_args: Vec, 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, - 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 { + 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, 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, - 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, + pub name: VarName, + pub __name__: Option, + 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, 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, name: VarName, __name__: Option, 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, 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, - 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 { + 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> for RecordAttrs { fn from(attrs: Vec) -> Self { Self(attrs) @@ -695,10 +761,6 @@ impl From> 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, - pub method_name: Option, + pub method_name: Option, 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, args: Args, sig_t: Type) -> Self { + pub fn new(obj: Expr, method_name: Option, 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, + /// 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 { + pub fn show_acc(&self) -> Option { 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, } } } diff --git a/compiler/erg_compiler/lib.rs b/compiler/erg_compiler/lib.rs index b0c1974b..199b4448 100644 --- a/compiler/erg_compiler/lib.rs +++ b/compiler/erg_compiler/lib.rs @@ -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; diff --git a/compiler/erg_compiler/link.rs b/compiler/erg_compiler/link.rs new file mode 100644 index 00000000..77f9a80c --- /dev/null +++ b/compiler/erg_compiler/link.rs @@ -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, + 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 { + 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) + } + } +} diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index 09206008..ea98908a 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -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 { + fn lower_record(&mut self, record: ast::Record) -> LowerResult { + 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 { 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("", 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 { 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 { + // `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 { 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 { + 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 { 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 { + "" + }; + 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 { 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 { + 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 { @@ -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) => { diff --git a/compiler/erg_compiler/ownercheck.rs b/compiler/erg_compiler/ownercheck.rs index 1885631a..3523b88c 100644 --- a/compiler/erg_compiler/ownercheck.rs +++ b/compiler/erg_compiler/ownercheck.rs @@ -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) => { diff --git a/compiler/erg_compiler/tests/test.rs b/compiler/erg_compiler/tests/test.rs index 68ec1f99..a137e2eb 100644 --- a/compiler/erg_compiler/tests/test.rs +++ b/compiler/erg_compiler/tests/test.rs @@ -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(()) } diff --git a/compiler/erg_compiler/varinfo.rs b/compiler/erg_compiler/varinfo.rs index f44305c3..5bb4fb11 100644 --- a/compiler/erg_compiler/varinfo.rs +++ b/compiler/erg_compiler/varinfo.rs @@ -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>, } 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>, + ) -> Self { + Self { + t, + muty, + vis, + kind, + comptime_decos, + } } pub fn same_id_as(&self, id: DefId) -> bool { diff --git a/compiler/erg_parser/Cargo.toml b/compiler/erg_parser/Cargo.toml index 9769b4d5..93954535 100644 --- a/compiler/erg_parser/Cargo.toml +++ b/compiler/erg_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_parser" -version = "0.3.2" +version = "0.4.0-beta.1" description = "The Erg parser" authors = ["mtshiba "] license = "MIT OR Apache-2.0" @@ -16,7 +16,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ] [dependencies] -erg_common = { version = "0.3.2", path = "../erg_common" } +erg_common = { version = "0.4.0-beta.1", path = "../erg_common" } [lib] path = "lib.rs" diff --git a/compiler/erg_parser/ast.rs b/compiler/erg_parser/ast.rs index 31cab944..5e309b3f 100644 --- a/compiler/erg_parser/ast.rs +++ b/compiler/erg_parser/ast.rs @@ -6,15 +6,13 @@ use erg_common::error::Location; use erg_common::set::Set as HashSet; use erg_common::traits::{Locational, NestedDisplay, Stream}; use erg_common::vis::{Field, Visibility}; -// use erg_common::ty::SubrKind; -// use erg_common::value::{Field, ValueObj, Visibility}; -use erg_common::Str; use erg_common::{ fmt_option, fmt_vec, impl_display_for_enum, impl_display_for_single_struct, impl_display_from_nested, impl_displayable_stream_for_wrapper, impl_locational, impl_locational_for_enum, impl_nested_display_for_chunk_enum, impl_nested_display_for_enum, impl_stream, impl_stream_for_wrapper, }; +use erg_common::{fmt_vec_split_with, Str}; use crate::token::{Token, TokenKind}; @@ -228,107 +226,26 @@ impl Args { } } -/// represents a local (private) variable -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Local { - pub symbol: Token, -} - -impl NestedDisplay for Local { - fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result { - write!(f, "{}", self.symbol.content) - } -} - -impl_display_from_nested!(Local); -impl_locational!(Local, symbol); - -impl Local { - pub const fn new(symbol: Token) -> Self { - Self { symbol } - } - - pub fn static_dummy(name: &'static str) -> Self { - Self::new(Token::static_symbol(name)) - } - - pub fn dummy(name: &str) -> Self { - Self::new(Token::symbol(name)) - } - - pub fn dummy_with_line(name: &str, line: usize) -> Self { - Self::new(Token::new(TokenKind::Symbol, Str::rc(name), line, 0)) - } - - // &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで - pub const fn inspect(&self) -> &Str { - &self.symbol.content - } - - pub fn is_const(&self) -> bool { - self.symbol.inspect().chars().next().unwrap().is_uppercase() - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Public { - pub dot: Token, - pub symbol: Token, -} - -impl NestedDisplay for Public { - fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result { - write!(f, ".{}", self.symbol.content) - } -} - -impl_display_from_nested!(Public); -impl_locational!(Public, dot, symbol); - -impl Public { - pub const fn new(dot: Token, symbol: Token) -> Self { - Self { dot, symbol } - } - - pub fn dummy(name: &'static str) -> Self { - Self::new( - Token::from_str(TokenKind::Dot, "."), - Token::from_str(TokenKind::Symbol, name), - ) - } - - // &strにするとクローンしたいときにアロケーションコストがかかるので&Strのままで - pub const fn inspect(&self) -> &Str { - &self.symbol.content - } - - pub fn is_const(&self) -> bool { - self.symbol.inspect().chars().next().unwrap().is_uppercase() - } -} - #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Attribute { pub obj: Box, - pub vis: Token, - pub name: Local, + pub ident: Identifier, } impl NestedDisplay for Attribute { fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result { - write!(f, "({}){}{}", self.obj, self.vis.inspect(), self.name) + write!(f, "({}){}", self.obj, self.ident) } } impl_display_from_nested!(Attribute); -impl_locational!(Attribute, obj, name); +impl_locational!(Attribute, obj, ident); impl Attribute { - pub fn new(obj: Expr, vis: Token, name: Local) -> Self { + pub fn new(obj: Expr, ident: Identifier) -> Self { Self { obj: Box::new(obj), - vis, - name, + ident, } } } @@ -384,28 +301,27 @@ impl Subscript { #[derive(Clone, Debug, PartialEq, Eq, Hash)] 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_locational_for_enum!(Accessor; Ident Attr, TupleAttr, Subscr); impl Accessor { pub const fn local(symbol: Token) -> Self { - Self::Local(Local::new(symbol)) + Self::Ident(Identifier::new(None, VarName::new(symbol))) } pub const fn public(dot: Token, symbol: Token) -> Self { - Self::Public(Public::new(dot, symbol)) + Self::Ident(Identifier::new(Some(dot), VarName::new(symbol))) } - pub fn attr(obj: Expr, vis: Token, name: Local) -> Self { - Self::Attr(Attribute::new(obj, vis, name)) + pub fn attr(obj: Expr, ident: Identifier) -> Self { + Self::Attr(Attribute::new(obj, ident)) } pub fn tuple_attr(obj: Expr, index: Literal) -> Self { @@ -418,19 +334,17 @@ impl Accessor { pub const fn name(&self) -> Option<&Str> { match self { - Self::Local(local) => Some(local.inspect()), - Self::Public(local) => Some(local.inspect()), + Self::Ident(ident) => Some(ident.inspect()), _ => None, } } pub fn is_const(&self) -> bool { match self { - Self::Local(local) => local.is_const(), - Self::Public(public) => public.is_const(), + Self::Ident(ident) => ident.is_const(), Self::Subscr(subscr) => subscr.obj.is_const_acc(), Self::TupleAttr(attr) => attr.obj.is_const_acc(), - Self::Attr(attr) => attr.obj.is_const_acc() && attr.name.is_const(), + Self::Attr(attr) => attr.obj.is_const_acc() && attr.ident.is_const(), } } } @@ -496,7 +410,7 @@ pub struct ArrayComprehension { pub l_sqbr: Token, pub r_sqbr: Token, pub elem: Box, - pub generators: Vec<(Local, Expr)>, + pub generators: Vec<(Identifier, Expr)>, pub guards: Vec, } @@ -524,7 +438,7 @@ impl ArrayComprehension { l_sqbr: Token, r_sqbr: Token, elem: Expr, - generators: Vec<(Local, Expr)>, + generators: Vec<(Identifier, Expr)>, guards: Vec, ) -> Self { Self { @@ -675,10 +589,18 @@ impl From> for RecordAttrs { } impl RecordAttrs { + pub const fn new(attrs: Vec) -> Self { + Self(attrs) + } + pub fn iter(&self) -> impl Iterator { self.0.iter() } + pub fn iter_mut(&mut self) -> impl Iterator { + self.0.iter_mut() + } + pub fn into_iter(self) -> impl IntoIterator { self.0.into_iter() } @@ -714,12 +636,45 @@ impl NormalRecord { /// e.g. {x; y; z} (syntax sugar of {x = x; y = y; z = z}) #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct SimpleRecord { +pub struct ShortenedRecord { pub l_brace: Token, pub r_brace: Token, - idents: Vec, + pub idents: Vec, } +impl NestedDisplay for ShortenedRecord { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { + write!(f, "{{")?; + for ident in self.idents.iter() { + write!(f, "{}; ", ident)?; + } + write!(f, "}}") + } +} + +impl_display_from_nested!(ShortenedRecord); +impl_locational!(ShortenedRecord, l_brace, r_brace); + +impl ShortenedRecord { + pub const fn new(l_brace: Token, r_brace: Token, idents: Vec) -> Self { + Self { + l_brace, + r_brace, + idents, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Record { + Normal(NormalRecord), + Shortened(ShortenedRecord), +} + +impl_nested_display_for_enum!(Record; Normal, Shortened); +impl_display_for_enum!(Record; Normal, Shortened); +impl_locational_for_enum!(Record; Normal, Shortened); + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct NormalSet { l_brace: Token, @@ -821,7 +776,7 @@ impl UnaryOp { #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Call { pub obj: Box, - pub method_name: Option, + pub method_name: Option, pub args: Args, } @@ -829,7 +784,7 @@ impl NestedDisplay for Call { fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, level: usize) -> std::fmt::Result { write!(f, "({})", self.obj)?; if let Some(method_name) = self.method_name.as_ref() { - write!(f, ".{}", method_name.content)?; + write!(f, "{}", method_name)?; } writeln!(f, ":")?; self.args.fmt_nest(f, level + 1) @@ -849,7 +804,7 @@ impl Locational for Call { } impl Call { - pub fn new(obj: Expr, method_name: Option, args: Args) -> Self { + pub fn new(obj: Expr, method_name: Option, args: Args) -> Self { Self { obj: Box::new(obj), method_name, @@ -858,6 +813,38 @@ impl Call { } } +/// e.g. `Data::{x = 1; y = 2}` +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct DataPack { + pub class: Box, + pub connector: Token, + pub args: Record, +} + +impl NestedDisplay for DataPack { + fn fmt_nest(&self, f: &mut std::fmt::Formatter<'_>, _level: usize) -> std::fmt::Result { + write!(f, "{}::{}", self.class, self.args) + } +} + +impl_display_from_nested!(DataPack); + +impl Locational for DataPack { + fn loc(&self) -> Location { + Location::concat(self.class.as_ref(), &self.args) + } +} + +impl DataPack { + pub fn new(class: Expr, connector: Token, args: Record) -> Self { + Self { + class: Box::new(class), + connector, + args, + } + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Block(Vec); @@ -1412,33 +1399,13 @@ impl ParamTySpec { } } -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub enum SubrKindSpec { - Func, - Proc, - FuncMethod(Box), - ProcMethod { - before: Box, - after: Option>, - }, -} - -impl SubrKindSpec { - pub const fn arrow(&self) -> Str { - match self { - Self::Func | Self::FuncMethod(_) => Str::ever("->"), - Self::Proc | Self::ProcMethod { .. } => Str::ever("=>"), - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct SubrTypeSpec { - pub kind: SubrKindSpec, pub lparen: Option, pub non_defaults: Vec, pub var_args: Option>, pub defaults: Vec, + pub arrow: Token, pub return_t: Box, } @@ -1450,7 +1417,7 @@ impl fmt::Display for SubrTypeSpec { fmt_vec(&self.non_defaults), fmt_option!(pre "...", &self.var_args), fmt_vec(&self.defaults), - self.kind.arrow(), + self.arrow.content, self.return_t ) } @@ -1469,19 +1436,19 @@ impl Locational for SubrTypeSpec { impl SubrTypeSpec { pub fn new( - kind: SubrKindSpec, lparen: Option, non_defaults: Vec, var_args: Option, defaults: Vec, + arrow: Token, return_t: TypeSpec, ) -> Self { Self { - kind, lparen, non_defaults, var_args: var_args.map(Box::new), defaults, + arrow, return_t: Box::new(return_t), } } @@ -1580,40 +1547,6 @@ impl TypeSpec { pub const fn interval(op: Token, lhs: ConstExpr, rhs: ConstExpr) -> Self { Self::Interval { op, lhs, rhs } } - - pub fn func( - lparen: Option, - non_defaults: Vec, - var_args: Option, - defaults: Vec, - return_t: TypeSpec, - ) -> Self { - Self::Subr(SubrTypeSpec::new( - SubrKindSpec::Func, - lparen, - non_defaults, - var_args, - defaults, - return_t, - )) - } - - pub fn proc( - lparen: Option, - non_defaults: Vec, - var_args: Option, - defaults: Vec, - return_t: TypeSpec, - ) -> Self { - Self::Subr(SubrTypeSpec::new( - SubrKindSpec::Proc, - lparen, - non_defaults, - var_args, - defaults, - return_t, - )) - } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -1657,7 +1590,7 @@ impl Locational for TypeBoundSpecs { /// デコレータは関数を返す関数オブジェクトならば何でも指定できる /// e.g. @(x -> x) #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Decorator(Expr); +pub struct Decorator(pub Expr); impl Decorator { pub const fn new(expr: Expr) -> Self { @@ -1760,15 +1693,17 @@ pub struct Identifier { pub name: VarName, } -impl fmt::Display for Identifier { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +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), + None => write!(f, "::{}", self.name), } } } +impl_display_from_nested!(Identifier); + impl Locational for Identifier { fn loc(&self) -> Location { if let Some(dot) = &self.dot { @@ -1805,13 +1740,17 @@ impl Identifier { Self::new(None, VarName::from_str_and_line(name, line)) } + pub fn public_with_line(dot: Token, name: Str, line: usize) -> Self { + Self::new(Some(dot), VarName::from_str_and_line(name, line)) + } + pub fn is_const(&self) -> bool { self.name.is_const() } pub const fn vis(&self) -> Visibility { match &self.dot { - Some(_dot) => Visibility::Public, + Some(_) => Visibility::Public, None => Visibility::Private, } } @@ -1907,32 +1846,96 @@ impl VarTuplePattern { } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct VarRecordAttr { + pub lhs: Identifier, + pub rhs: VarSignature, +} + +impl NestedDisplay for VarRecordAttr { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { + write!(f, "{} = {}", self.lhs, self.rhs) + } +} + +impl_display_from_nested!(VarRecordAttr); +impl_locational!(VarRecordAttr, lhs, rhs); + +impl VarRecordAttr { + pub const fn new(lhs: Identifier, rhs: VarSignature) -> Self { + Self { lhs, rhs } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct VarRecordAttrs { + pub(crate) elems: Vec, +} + +impl NestedDisplay for VarRecordAttrs { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { + write!(f, "{}", fmt_vec_split_with(&self.elems, "; ")) + } +} + +impl_display_from_nested!(VarRecordAttrs); +impl_stream!(VarRecordAttrs, VarRecordAttr, elems); + +impl VarRecordAttrs { + pub const fn new(elems: Vec) -> Self { + Self { elems } + } + + pub const fn empty() -> Self { + Self::new(vec![]) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct VarRecordPattern { l_brace: Token, - // TODO: レコード専用の構造体を作る - pub(crate) elems: Vars, + pub(crate) attrs: VarRecordAttrs, r_brace: Token, } impl fmt::Display for VarRecordPattern { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{{{}}}", self.elems) + write!(f, "{{{}}}", self.attrs) } } impl_locational!(VarRecordPattern, l_brace, r_brace); impl VarRecordPattern { - pub const fn new(l_brace: Token, elems: Vars, r_brace: Token) -> Self { + pub const fn new(l_brace: Token, attrs: VarRecordAttrs, r_brace: Token) -> Self { Self { l_brace, - elems, + attrs, r_brace, } } } +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct VarDataPackPattern { + pub class: TypeSpec, + pub args: VarRecordPattern, +} + +impl fmt::Display for VarDataPackPattern { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}::{}", self.class, self.args) + } +} + +impl_locational!(VarDataPackPattern, class, args); + +impl VarDataPackPattern { + pub const fn new(class: TypeSpec, args: VarRecordPattern) -> Self { + Self { class, args } + } +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub enum VarPattern { Discard(Token), @@ -1943,6 +1946,8 @@ pub enum VarPattern { Tuple(VarTuplePattern), // e.g. `{name; age}`, `{_; [car, cdr]}` Record(VarRecordPattern), + // e.g. `Data::{x, y}` + DataPack(VarDataPackPattern), } impl NestedDisplay for VarPattern { @@ -1953,12 +1958,13 @@ impl NestedDisplay for VarPattern { Self::Array(a) => write!(f, "{}", a), Self::Tuple(t) => write!(f, "{}", t), Self::Record(r) => write!(f, "{}", r), + Self::DataPack(d) => write!(f, "{}", d), } } } impl_display_from_nested!(VarPattern); -impl_locational_for_enum!(VarPattern; Discard, Ident, Array, Tuple, Record); +impl_locational_for_enum!(VarPattern; Discard, Ident, Array, Tuple, Record, DataPack); impl VarPattern { pub const fn inspect(&self) -> Option<&Str> { @@ -1968,18 +1974,6 @@ impl VarPattern { } } - pub fn inspects(&self) -> Vec<&Str> { - match self { - Self::Ident(ident) => vec![ident.inspect()], - Self::Array(VarArrayPattern { elems, .. }) - | Self::Tuple(VarTuplePattern { elems, .. }) - | Self::Record(VarRecordPattern { elems, .. }) => { - elems.iter().flat_map(|s| s.pat.inspects()).collect() - } - _ => vec![], - } - } - // _!(...) = ... is invalid pub fn is_procedural(&self) -> bool { match self { @@ -2052,6 +2046,13 @@ impl VarSignature { pub const fn vis(&self) -> Visibility { self.pat.vis() } + + pub fn ident(&self) -> Option<&Identifier> { + match &self.pat { + VarPattern::Ident(ident) => Some(ident), + _ => None, + } + } } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -2156,26 +2157,38 @@ impl ParamRecordPattern { pub enum ParamPattern { Discard(Token), VarName(VarName), - // TODO: ConstField(), - // e.g. `a` of `[*a, b] = [1, 2, 3]` (a == [1, 2], b == 3) - // `b` of `[a, *b] = [1, 2, 3]` (a == 1, b == [2, 3]) - VarArgsName(VarName), + // TODO: ConstAttr(), Lit(Literal), Array(ParamArrayPattern), Tuple(ParamTuplePattern), Record(ParamRecordPattern), + // DataPack(ParamDataPackPattern), Ref(VarName), RefMut(VarName), - VarArgs(VarName), } -impl_display_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs); -impl_locational_for_enum!(ParamPattern; Discard, VarName, VarArgsName, Lit, Array, Tuple, Record, Ref, RefMut, VarArgs); +impl NestedDisplay for ParamPattern { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result { + match self { + Self::Discard(tok) => write!(f, "{}", tok), + Self::VarName(var_name) => write!(f, "{}", var_name), + Self::Lit(lit) => write!(f, "{}", lit), + Self::Array(array) => write!(f, "{}", array), + Self::Tuple(tuple) => write!(f, "{}", tuple), + Self::Record(record) => write!(f, "{}", record), + Self::Ref(var_name) => write!(f, "ref {}", var_name), + Self::RefMut(var_name) => write!(f, "ref! {}", var_name), + } + } +} + +impl_display_from_nested!(ParamPattern); +impl_locational_for_enum!(ParamPattern; Discard, VarName, Lit, Array, Tuple, Record, Ref, RefMut); impl ParamPattern { pub const fn inspect(&self) -> Option<&Str> { match self { - Self::VarName(n) | Self::VarArgsName(n) => Some(n.inspect()), + Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => Some(n.inspect()), _ => None, } } @@ -2187,7 +2200,7 @@ impl ParamPattern { pub fn is_procedural(&self) -> bool { match self { Self::Discard(_) => true, - Self::VarName(n) | Self::VarArgsName(n) => n.is_procedural(), + Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_procedural(), _ => false, } } @@ -2195,7 +2208,7 @@ impl ParamPattern { pub fn is_const(&self) -> bool { match self { Self::Discard(_) => true, - Self::VarName(n) | Self::VarArgsName(n) => n.is_const(), + Self::VarName(n) | Self::Ref(n) | Self::RefMut(n) => n.is_const(), _ => false, } } @@ -2289,7 +2302,11 @@ impl Locational for Params { } else if !self.non_defaults.is_empty() { Location::concat(&self.non_defaults[0], self.non_defaults.last().unwrap()) } else if let Some(var_args) = &self.var_args { - Location::concat(var_args.as_ref(), self.defaults.last().unwrap()) + if !self.defaults.is_empty() { + Location::concat(var_args.as_ref(), self.defaults.last().unwrap()) + } else { + var_args.loc() + } } else if !self.defaults.is_empty() { Location::concat(&self.defaults[0], self.defaults.last().unwrap()) } else { @@ -2540,6 +2557,19 @@ impl Signature { } } + pub fn ident_mut(&mut self) -> Option<&mut Identifier> { + match self { + Self::Var(var) => { + if let VarPattern::Ident(ident) = &mut var.pat { + Some(ident) + } else { + None + } + } + Self::Subr(subr) => Some(&mut subr.ident), + } + } + pub fn t_spec(&self) -> Option<&TypeSpec> { match self { Self::Var(v) => v.t_spec.as_ref(), @@ -2610,7 +2640,8 @@ pub struct Def { impl NestedDisplay for Def { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { - writeln!(f, "{} {}", self.sig, self.body.op.content)?; + self.sig.fmt_nest(f, level)?; + writeln!(f, " {}", self.body.op.content)?; self.body.block.fmt_nest(f, level + 1) } } @@ -2640,28 +2671,58 @@ impl Def { /// f(a) = ... /// ``` #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct MethodDefs { +pub struct Methods { pub class: TypeSpec, pub vis: Token, // `.` or `::` pub defs: RecordAttrs, // TODO: allow declaration } -impl NestedDisplay for MethodDefs { +impl NestedDisplay for Methods { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { - writeln!(f, "{}{}", self.class, self.vis)?; + writeln!(f, "{}{}", self.class, self.vis.content)?; self.defs.fmt_nest(f, level + 1) } } -impl_display_from_nested!(MethodDefs); -impl_locational!(MethodDefs, class, defs); +impl_display_from_nested!(Methods); +impl_locational!(Methods, class, defs); -impl MethodDefs { +impl Methods { pub const fn new(class: TypeSpec, vis: Token, defs: RecordAttrs) -> Self { Self { class, vis, defs } } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ClassDef { + pub def: Def, + pub methods_list: Vec, +} + +impl NestedDisplay for ClassDef { + fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { + write!(f, "(class)")?; + self.def.fmt_nest(f, level)?; + for methods in self.methods_list.iter() { + write!(f, "(methods)")?; + methods.fmt_nest(f, level + 1)?; + } + Ok(()) + } +} + +impl_display_from_nested!(ClassDef); +impl_locational!(ClassDef, def); + +impl ClassDef { + pub const fn new(def: Def, methods: Vec) -> Self { + Self { + def, + methods_list: methods, + } + } +} + /// Expression(式) #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Expr { @@ -2671,19 +2732,21 @@ pub enum Expr { Tuple(Tuple), Dict(Dict), Set(Set), - Record(NormalRecord), + Record(Record), BinOp(BinOp), UnaryOp(UnaryOp), Call(Call), + DataPack(DataPack), Lambda(Lambda), TypeAsc(TypeAscription), Def(Def), - MethodDefs(MethodDefs), + Methods(Methods), + ClassDef(ClassDef), } -impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, TypeAsc, Def, MethodDefs); +impl_nested_display_for_chunk_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef); impl_display_from_nested!(Expr); -impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, Lambda, TypeAsc, Def, MethodDefs); +impl_locational_for_enum!(Expr; Lit, Accessor, Array, Tuple, Dict, Set, Record, BinOp, UnaryOp, Call, DataPack, Lambda, TypeAsc, Def, Methods, ClassDef); impl Expr { pub fn is_match_call(&self) -> bool { @@ -2720,7 +2783,7 @@ impl Expr { } #[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct Module(Vec); +pub struct Module(Block); impl fmt::Display for Module { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -2734,7 +2797,34 @@ impl Locational for Module { } } -impl_stream_for_wrapper!(Module, Expr); +impl Stream for Module { + fn payload(self) -> Vec { + self.0.payload() + } + fn ref_payload(&self) -> &Vec { + self.0.ref_payload() + } + fn ref_mut_payload(&mut self) -> &mut Vec { + self.0.ref_mut_payload() + } +} + +impl Module { + pub const fn empty() -> Self { + Self(Block::empty()) + } + pub const fn new(payload: Vec) -> Self { + Self(Block::new(payload)) + } + #[inline] + pub fn with_capacity(capacity: usize) -> Self { + Self(Block::with_capacity(capacity)) + } + + pub fn block(&self) -> &Block { + &self.0 + } +} #[derive(Debug)] pub struct AST { diff --git a/compiler/erg_parser/desugar.rs b/compiler/erg_parser/desugar.rs index 6a2748c6..4cfe3128 100644 --- a/compiler/erg_parser/desugar.rs +++ b/compiler/erg_parser/desugar.rs @@ -11,17 +11,19 @@ use erg_common::Str; use erg_common::{enum_unwrap, get_hash, set}; use crate::ast::{ - Accessor, Args, Block, Call, Def, DefBody, DefId, Expr, Identifier, Lambda, LambdaSignature, - Literal, Local, Module, ParamPattern, ParamSignature, Params, PosArg, Signature, SubrSignature, - TypeBoundSpecs, TypeSpec, VarName, VarPattern, VarSignature, + Accessor, Args, Array, BinOp, Block, Call, DataPack, Def, DefBody, DefId, Expr, Identifier, + KwArg, Lambda, LambdaSignature, Literal, Methods, Module, NormalArray, NormalRecord, + NormalTuple, ParamPattern, ParamSignature, Params, PosArg, Record, RecordAttrs, + ShortenedRecord, Signature, SubrSignature, Tuple, TypeAscription, TypeBoundSpecs, TypeSpec, + UnaryOp, VarName, VarPattern, VarRecordAttr, VarSignature, }; use crate::token::{Token, TokenKind}; #[derive(Debug, Clone, PartialEq, Eq)] -enum BufIndex<'s> { +enum BufIndex<'i> { Array(usize), Tuple(usize), - Record(&'s str), + Record(&'i Identifier), } #[derive(Debug)] @@ -46,7 +48,10 @@ impl Desugarer { pub fn desugar(&mut self, module: Module) -> Module { let module = self.desugar_multiple_pattern_def(module); - self.desugar_pattern(module) + let module = self.desugar_pattern(module); + let module = self.desugar_shortened_record(module); + // let module = self.desugar_self(module); + module } fn desugar_ubar_lambda(&self, _module: Module) -> Module { @@ -74,7 +79,7 @@ impl Desugarer { } else { self.gen_match_call(previous, def) }; - let param_name = enum_unwrap!(&call.args.pos_args().iter().next().unwrap().expr, Expr::Accessor:(Accessor::Local:(_))).inspect(); + let param_name = enum_unwrap!(&call.args.pos_args().iter().next().unwrap().expr, Expr::Accessor:(Accessor::Ident:(_))).inspect(); // FIXME: multiple params let param = VarName::new(Token::new( TokenKind::Symbol, @@ -160,6 +165,19 @@ impl Desugarer { todo!() } + fn gen_buf_name_and_sig( + &mut self, + line: usize, + t_spec: Option, + ) -> (String, Signature) { + let buf_name = self.fresh_var_name(); + let buf_sig = Signature::Var(VarSignature::new( + VarPattern::Ident(Identifier::private_with_line(Str::rc(&buf_name), line)), + t_spec, + )); + (buf_name, buf_sig) + } + /// `[i, j] = [1, 2]` -> `i = 1; j = 2` /// `[i, j] = l` -> `i = l[0]; j = l[1]` /// `[i, [j, k]] = l` -> `i = l[0]; j = l[1][0]; k = l[1][1]` @@ -174,14 +192,8 @@ impl Desugarer { body, }) => match &v.pat { VarPattern::Tuple(tup) => { - let buf_name = self.fresh_var_name(); - let buf_sig = Signature::Var(VarSignature::new( - VarPattern::Ident(Identifier::private_with_line( - Str::rc(&buf_name), - v.ln_begin().unwrap(), - )), - v.t_spec, - )); + let (buf_name, buf_sig) = + self.gen_buf_name_and_sig(v.ln_begin().unwrap(), v.t_spec); let buf_def = Def::new(buf_sig, body); new.push(Expr::Def(buf_def)); for (n, elem) in tup.elems.iter().enumerate() { @@ -194,14 +206,8 @@ impl Desugarer { } } VarPattern::Array(arr) => { - let buf_name = self.fresh_var_name(); - let buf_sig = Signature::Var(VarSignature::new( - VarPattern::Ident(Identifier::private_with_line( - Str::rc(&buf_name), - v.ln_begin().unwrap(), - )), - v.t_spec, - )); + let (buf_name, buf_sig) = + self.gen_buf_name_and_sig(v.ln_begin().unwrap(), v.t_spec); let buf_def = Def::new(buf_sig, body); new.push(Expr::Def(buf_def)); for (n, elem) in arr.elems.iter().enumerate() { @@ -213,7 +219,36 @@ impl Desugarer { ); } } - VarPattern::Record(_rec) => todo!(), + VarPattern::Record(rec) => { + let (buf_name, buf_sig) = + self.gen_buf_name_and_sig(v.ln_begin().unwrap(), v.t_spec); + let buf_def = Def::new(buf_sig, body); + new.push(Expr::Def(buf_def)); + for VarRecordAttr { lhs, rhs } in rec.attrs.iter() { + self.desugar_nested_var_pattern( + &mut new, + rhs, + &buf_name, + BufIndex::Record(lhs), + ); + } + } + VarPattern::DataPack(pack) => { + let (buf_name, buf_sig) = self.gen_buf_name_and_sig( + v.ln_begin().unwrap(), + Some(pack.class.clone()), // TODO: これだとvの型指定の意味がなくなる + ); + let buf_def = Def::new(buf_sig, body); + new.push(Expr::Def(buf_def)); + for VarRecordAttr { lhs, rhs } in pack.args.attrs.iter() { + self.desugar_nested_var_pattern( + &mut new, + rhs, + &buf_name, + BufIndex::Record(lhs), + ); + } + } VarPattern::Ident(_i) => { let def = Def::new(Signature::Var(v), body); new.push(Expr::Def(def)); @@ -243,14 +278,7 @@ impl Desugarer { BufIndex::Array(n) => { Accessor::subscr(obj, Expr::Lit(Literal::nat(n, sig.ln_begin().unwrap()))) } - BufIndex::Record(attr) => { - // TODO: visibility - Accessor::attr( - obj, - Token::from_str(TokenKind::Dot, "."), - Local::dummy_with_line(attr, sig.ln_begin().unwrap()), - ) - } + BufIndex::Record(attr) => Accessor::attr(obj, attr.clone()), }; let id = DefId(get_hash(&(&acc, buf_name))); let block = Block::new(vec![Expr::Accessor(acc)]); @@ -258,14 +286,7 @@ impl Desugarer { let body = DefBody::new(op, block, id); match &sig.pat { VarPattern::Tuple(tup) => { - let buf_name = self.fresh_var_name(); - let buf_sig = Signature::Var(VarSignature::new( - VarPattern::Ident(Identifier::private_with_line( - Str::rc(&buf_name), - sig.ln_begin().unwrap(), - )), - None, - )); + let (buf_name, buf_sig) = self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), None); let buf_def = Def::new(buf_sig, body); new_module.push(Expr::Def(buf_def)); for (n, elem) in tup.elems.iter().enumerate() { @@ -278,14 +299,7 @@ impl Desugarer { } } VarPattern::Array(arr) => { - let buf_name = self.fresh_var_name(); - let buf_sig = Signature::Var(VarSignature::new( - VarPattern::Ident(Identifier::private_with_line( - Str::rc(&buf_name), - sig.ln_begin().unwrap(), - )), - None, - )); + let (buf_name, buf_sig) = self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), None); let buf_def = Def::new(buf_sig, body); new_module.push(Expr::Def(buf_def)); for (n, elem) in arr.elems.iter().enumerate() { @@ -297,7 +311,33 @@ impl Desugarer { ); } } - VarPattern::Record(_rec) => todo!(), + VarPattern::Record(rec) => { + let (buf_name, buf_sig) = self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), None); + let buf_def = Def::new(buf_sig, body); + new_module.push(Expr::Def(buf_def)); + for VarRecordAttr { lhs, rhs } in rec.attrs.iter() { + self.desugar_nested_var_pattern( + new_module, + rhs, + &buf_name, + BufIndex::Record(lhs), + ); + } + } + VarPattern::DataPack(pack) => { + let (buf_name, buf_sig) = + self.gen_buf_name_and_sig(sig.ln_begin().unwrap(), Some(pack.class.clone())); + let buf_def = Def::new(buf_sig, body); + new_module.push(Expr::Def(buf_def)); + for VarRecordAttr { lhs, rhs } in pack.args.attrs.iter() { + self.desugar_nested_var_pattern( + new_module, + rhs, + &buf_name, + BufIndex::Record(lhs), + ); + } + } VarPattern::Ident(_ident) => { let def = Def::new(Signature::Var(sig.clone()), body); new_module.push(Expr::Def(def)); @@ -306,21 +346,162 @@ impl Desugarer { } } - /// `F(I | I > 0)` -> `F(I: {I: Int | I > 0})` - fn desugar_refinement_pattern(&self, _mod: Module) -> Module { - todo!() + /// `{x; y}` -> `{x = x; y = y}` + fn desugar_shortened_record(&self, mut module: Module) -> Module { + let mut new = Module::with_capacity(module.len()); + while let Some(chunk) = module.lpop() { + new.push(self.rec_desugar_shortened_record(chunk)); + } + new } - /// ```python - /// @deco - /// f x = ... - /// ``` - /// ↓ - /// ```python - /// _f x = ... - /// f = deco _f - /// ``` - fn desugar_decorators(&self, _mod: Module) -> Module { + fn rec_desugar_shortened_record(&self, expr: Expr) -> Expr { + match expr { + Expr::Record(Record::Shortened(rec)) => { + let rec = self.desugar_shortened_record_inner(rec); + Expr::Record(Record::Normal(rec)) + } + Expr::DataPack(pack) => { + if let Record::Shortened(rec) = pack.args { + let class = self.rec_desugar_shortened_record(*pack.class); + let rec = self.desugar_shortened_record_inner(rec); + let args = Record::Normal(rec); + Expr::DataPack(DataPack::new(class, pack.connector, args)) + } else { + Expr::DataPack(pack) + } + } + Expr::Array(array) => match array { + Array::Normal(arr) => { + let (elems, _, _) = arr.elems.deconstruct(); + let elems = elems + .into_iter() + .map(|elem| PosArg::new(self.rec_desugar_shortened_record(elem.expr))) + .collect(); + let elems = Args::new(elems, vec![], None); + let arr = NormalArray::new(arr.l_sqbr, arr.r_sqbr, elems); + Expr::Array(Array::Normal(arr)) + } + _ => todo!(), + }, + Expr::Tuple(tuple) => match tuple { + Tuple::Normal(tup) => { + let (elems, _, paren) = tup.elems.deconstruct(); + let elems = elems + .into_iter() + .map(|elem| PosArg::new(self.rec_desugar_shortened_record(elem.expr))) + .collect(); + let new_tup = Args::new(elems, vec![], paren); + let tup = NormalTuple::new(new_tup); + Expr::Tuple(Tuple::Normal(tup)) + } + }, + Expr::Set(set) => { + todo!("{set}") + } + Expr::Dict(dict) => { + todo!("{dict}") + } + Expr::BinOp(binop) => { + let mut args = binop.args.into_iter(); + let lhs = self.rec_desugar_shortened_record(*args.next().unwrap()); + let rhs = self.rec_desugar_shortened_record(*args.next().unwrap()); + Expr::BinOp(BinOp::new(binop.op, lhs, rhs)) + } + Expr::UnaryOp(unaryop) => { + let mut args = unaryop.args.into_iter(); + let expr = self.rec_desugar_shortened_record(*args.next().unwrap()); + Expr::UnaryOp(UnaryOp::new(unaryop.op, expr)) + } + Expr::Call(call) => { + let obj = self.rec_desugar_shortened_record(*call.obj); + let (pos_args, kw_args, paren) = call.args.deconstruct(); + let pos_args = pos_args + .into_iter() + .map(|arg| PosArg::new(self.rec_desugar_shortened_record(arg.expr))) + .collect(); + let kw_args = kw_args + .into_iter() + .map(|arg| { + let expr = self.rec_desugar_shortened_record(arg.expr); + KwArg::new(arg.keyword, arg.t_spec, expr) // TODO: t_spec + }) + .collect(); + let args = Args::new(pos_args, kw_args, paren); + Expr::Call(Call::new(obj, call.method_name, args)) + } + Expr::Def(def) => { + let mut chunks = vec![]; + for chunk in def.body.block.into_iter() { + chunks.push(self.rec_desugar_shortened_record(chunk)); + } + let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id); + Expr::Def(Def::new(def.sig, body)) + } + Expr::Lambda(lambda) => { + let mut chunks = vec![]; + for chunk in lambda.body.into_iter() { + chunks.push(self.rec_desugar_shortened_record(chunk)); + } + let body = Block::new(chunks); + Expr::Lambda(Lambda::new(lambda.sig, lambda.op, body, lambda.id)) + } + Expr::TypeAsc(tasc) => { + let expr = self.rec_desugar_shortened_record(*tasc.expr); + Expr::TypeAsc(TypeAscription::new(expr, tasc.t_spec)) + } + Expr::Methods(method_defs) => { + let mut new_defs = vec![]; + for def in method_defs.defs.into_iter() { + let mut chunks = vec![]; + for chunk in def.body.block.into_iter() { + chunks.push(self.rec_desugar_shortened_record(chunk)); + } + let body = DefBody::new(def.body.op, Block::new(chunks), def.body.id); + new_defs.push(Def::new(def.sig, body)); + } + let new_defs = RecordAttrs::from(new_defs); + Expr::Methods(Methods::new(method_defs.class, method_defs.vis, new_defs)) + } + // TODO: Accessorにも一応レコードを入れられる + other => other, + } + } + + fn desugar_shortened_record_inner(&self, rec: ShortenedRecord) -> NormalRecord { + let mut attrs = vec![]; + for attr in rec.idents.into_iter() { + let var = VarSignature::new(VarPattern::Ident(attr.clone()), None); + let sig = Signature::Var(var); + let body = DefBody::new( + Token::from_str(TokenKind::Equal, "="), + Block::new(vec![Expr::local( + attr.inspect(), + attr.ln_begin().unwrap(), + attr.col_begin().unwrap(), + )]), + DefId(get_hash(&(&sig, attr.inspect()))), + ); + let def = Def::new(sig, body); + attrs.push(def); + } + let attrs = RecordAttrs::new(attrs); + NormalRecord::new(rec.l_brace, rec.r_brace, attrs) + } + + fn desugar_self(&self, mut module: Module) -> Module { + let mut new = Module::with_capacity(module.len()); + while let Some(chunk) = module.lpop() { + new.push(self.rec_desugar_self(chunk)); + } + new + } + + fn rec_desugar_self(&self, _expr: Expr) -> Expr { + todo!() + } + /// `F(I | I > 0)` -> `F(I: {I: Int | I > 0})` + fn desugar_refinement_pattern(&self, _mod: Module) -> Module { todo!() } } diff --git a/compiler/erg_parser/lex.rs b/compiler/erg_parser/lex.rs index 74fb08af..0b106448 100644 --- a/compiler/erg_parser/lex.rs +++ b/compiler/erg_parser/lex.rs @@ -412,7 +412,9 @@ impl Lexer /*<'a>*/ { while let Some(ch) = self.peek_cur_ch() { match ch { // `.` may be a dot operator, don't consume - '.' => return self.lex_num_dot(num), + '.' => { + return self.lex_num_dot(num); + } n if n.is_ascii_digit() || n == '_' => { num.push(self.consume().unwrap()); } @@ -525,6 +527,8 @@ impl Lexer /*<'a>*/ { "isnot" => IsNotOp, "dot" => DotOp, "cross" => CrossOp, + "ref" => RefOp, + "ref!" => RefMutOp, // これらはリテラルというより定数だが便宜的にリテラルということにしておく "True" | "False" => BoolLit, "None" => NoneLit, diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index e659bb02..e38848f3 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -56,7 +56,7 @@ pub enum ArrayInner { WithLength(PosArg, Expr), Comprehension { elem: PosArg, - generators: Vec<(Local, Expr)>, + generators: Vec<(Identifier, Expr)>, guards: Vec, }, } @@ -64,7 +64,7 @@ pub enum ArrayInner { pub enum BraceContainer { Set(Set), Dict(Dict), - Record(NormalRecord), + Record(Record), } /// Perform recursive descent parsing. @@ -145,12 +145,6 @@ impl Parser { } } - fn throw_syntax_err(&mut self, l: &L, caused_by: &str) -> ParseError { - log!(err "error caused by: {caused_by}"); - self.next_expr(); - ParseError::simple_syntax_error(0, l.loc()) - } - fn skip_and_throw_syntax_err(&mut self, caused_by: &str) -> ParseError { let loc = self.peek().unwrap().loc(); log!(err "error caused by: {caused_by}"); @@ -275,7 +269,10 @@ impl Parser { Some(t) if t.is(EOF) => { break; } - Some(t) if t.is(Indent) || t.is(Dedent) => { + Some(t) if t.is(Indent) => { + switch_unreachable!() + } + Some(t) if t.is(Dedent) => { switch_unreachable!() } Some(_) => match self.try_reduce_chunk(true) { @@ -284,7 +281,7 @@ impl Parser { } Err(_) => {} }, - _ => switch_unreachable!(), + None => switch_unreachable!(), } } self.level -= 1; @@ -306,29 +303,22 @@ impl Parser { Some(t) if t.category_is(TC::Separator) => { self.skip(); } - Some(t) => { - if t.is(Indent) { - self.skip(); - while self.cur_is(Newline) { - self.skip(); - } - } else if self.cur_is(Dedent) { - self.skip(); - break; - } else if t.is(EOF) { - break; - } - match self.try_reduce_chunk(true) { - Ok(expr) => { - block.push(expr); - if self.cur_is(Dedent) { - self.skip(); - break; - } - } - Err(_) => {} - } + Some(t) if t.is(Indent) => { + self.skip(); } + Some(t) if t.is(Dedent) => { + self.skip(); + break; + } + Some(t) if t.is(EOF) => { + break; + } + Some(_) => match self.try_reduce_chunk(true) { + Ok(expr) => { + block.push(expr); + } + Err(_) => {} + }, _ => switch_unreachable!(), } } @@ -418,8 +408,8 @@ impl Parser { let token = self.lpop(); match token.kind { Symbol => { - let attr = Local::new(token); - acc = Accessor::attr(Expr::Accessor(acc), vis, attr); + let ident = Identifier::new(Some(vis), VarName::new(token)); + acc = Accessor::attr(Expr::Accessor(acc), ident); } NatLit => { let attr = Literal::from(token); @@ -444,9 +434,16 @@ impl Parser { let token = self.lpop(); match token.kind { Symbol => { - let attr = Local::new(token); - acc = Accessor::attr(Expr::Accessor(acc), vis, attr); + let ident = Identifier::new(None, VarName::new(token)); + acc = Accessor::attr(Expr::Accessor(acc), ident); } + // DataPack + LBrace => { + self.restore(token); + self.restore(vis); + break; + } + // MethodDefs Newline => { self.restore(token); self.restore(vis); @@ -495,8 +492,8 @@ impl Parser { fn validate_const_expr(&mut self, expr: Expr) -> ParseResult { match expr { Expr::Lit(l) => Ok(ConstExpr::Lit(l)), - Expr::Accessor(Accessor::Local(local)) => { - let local = ConstLocal::new(local.symbol); + Expr::Accessor(Accessor::Ident(local)) => { + let local = ConstLocal::new(local.name.into_token()); Ok(ConstExpr::Accessor(ConstAccessor::Local(local))) } // TODO: App, Array, Record, BinOp, UnaryOp, @@ -606,7 +603,11 @@ impl Parser { { Some(self.try_reduce_args()) } - Some(t) if (t.is(Dot) || t.is(DblColon)) && !self.nth_is(1, Newline) => { + Some(t) + if (t.is(Dot) || t.is(DblColon)) + && !self.nth_is(1, Newline) + && !self.nth_is(1, LBrace) => + { Some(self.try_reduce_args()) } _ => None, @@ -743,8 +744,8 @@ impl Parser { // TODO: type specification debug_power_assert!(self.cur_is(Walrus)); self.skip(); - let kw = if let Accessor::Local(n) = acc { - n.symbol + let kw = if let Accessor::Ident(n) = acc { + n.name.into_token() } else { self.next_expr(); self.level -= 1; @@ -788,8 +789,8 @@ impl Parser { let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?; debug_power_assert!(self.cur_is(Walrus)); self.skip(); - let keyword = if let Accessor::Local(n) = acc { - n.symbol + let keyword = if let Accessor::Ident(n) = acc { + n.name.into_token() } else { self.next_expr(); self.level -= 1; @@ -827,13 +828,16 @@ impl Parser { } } - fn try_reduce_method_defs(&mut self, class: Expr, vis: Token) -> ParseResult { + fn try_reduce_method_defs(&mut self, class: Expr, vis: Token) -> ParseResult { debug_call_info!(self); if self.cur_is(Indent) { self.skip(); } else { todo!() } + while self.cur_is(Newline) { + self.skip(); + } let first = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?; let first = option_enum_unwrap!(first, Expr::Def).unwrap_or_else(|| todo!()); let mut defs = vec![first]; @@ -841,13 +845,22 @@ impl Parser { match self.peek() { Some(t) if t.category_is(TC::Separator) => { self.skip(); - if self.cur_is(Dedent) { - self.skip(); - break; - } + } + Some(t) if t.is(Dedent) => { + self.skip(); + break; + } + Some(_) => { let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?; - let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!()); - defs.push(def); + match def { + Expr::Def(def) => { + defs.push(def); + } + other => { + self.errs + .push(ParseError::simple_syntax_error(0, other.loc())); + } + } } _ => todo!(), } @@ -857,7 +870,7 @@ impl Parser { .convert_rhs_to_type_spec(class) .map_err(|_| self.stack_dec())?; self.level -= 1; - Ok(MethodDefs::new(class, vis, defs)) + Ok(Methods::new(class, vis, defs)) } fn try_reduce_do_block(&mut self) -> ParseResult { @@ -967,10 +980,12 @@ impl Parser { .transpose() .map_err(|_| self.stack_dec())? { - let call = Call::new(obj, Some(symbol), args); + let ident = Identifier::new(None, VarName::new(symbol)); + let call = Call::new(obj, Some(ident), args); stack.push(ExprOrOp::Expr(Expr::Call(call))); } else { - let acc = Accessor::attr(obj, vis, Local::new(symbol)); + let ident = Identifier::new(None, VarName::new(symbol)); + let acc = Accessor::attr(obj, ident); stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); } } @@ -979,7 +994,25 @@ impl Parser { let defs = self .try_reduce_method_defs(maybe_class, vis) .map_err(|_| self.stack_dec())?; - return Ok(Expr::MethodDefs(defs)); + let expr = Expr::Methods(defs); + assert_eq!(stack.len(), 0); + self.level -= 1; + return Ok(expr); + } + l_brace if l_brace.is(LBrace) => { + let maybe_class = enum_unwrap!(stack.pop(), Some:(ExprOrOp::Expr:(_))); + self.restore(l_brace); + let container = self + .try_reduce_brace_container() + .map_err(|_| self.stack_dec())?; + match container { + BraceContainer::Record(args) => { + let pack = DataPack::new(maybe_class, vis, args); + stack.push(ExprOrOp::Expr(Expr::DataPack(pack))); + } + BraceContainer::Dict(dict) => todo!("{dict}"), + BraceContainer::Set(set) => todo!("{set}"), + } } other => { self.restore(other); @@ -1007,10 +1040,12 @@ impl Parser { .transpose() .map_err(|_| self.stack_dec())? { - let call = Call::new(obj, Some(symbol), args); + let ident = Identifier::new(Some(vis), VarName::new(symbol)); + let call = Call::new(obj, Some(ident), args); stack.push(ExprOrOp::Expr(Expr::Call(call))); } else { - let acc = Accessor::attr(obj, vis, Local::new(symbol)); + let ident = Identifier::new(Some(vis), VarName::new(symbol)); + let acc = Accessor::attr(obj, ident); stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); } } @@ -1019,7 +1054,7 @@ impl Parser { let defs = self .try_reduce_method_defs(maybe_class, vis) .map_err(|_| self.stack_dec())?; - return Ok(Expr::MethodDefs(defs)); + return Ok(Expr::Methods(defs)); } other => { self.restore(other); @@ -1037,6 +1072,11 @@ impl Parser { .map_err(|_| self.stack_dec())?; stack.push(ExprOrOp::Expr(Expr::Tuple(tup))); } + Some(t) if t.category_is(TC::Reserved) => { + self.level -= 1; + let err = self.skip_and_throw_syntax_err(caused_by!()); + self.errs.push(err); + } _ => { if stack.len() <= 1 { break; @@ -1156,10 +1196,12 @@ impl Parser { .transpose() .map_err(|_| self.stack_dec())? { - let call = Call::new(obj, Some(symbol), args); + let ident = Identifier::new(Some(vis), VarName::new(symbol)); + let call = Call::new(obj, Some(ident), args); stack.push(ExprOrOp::Expr(Expr::Call(call))); } else { - let acc = Accessor::attr(obj, vis, Local::new(symbol)); + let ident = Identifier::new(Some(vis), VarName::new(symbol)); + let acc = Accessor::attr(obj, ident); stack.push(ExprOrOp::Expr(Expr::Accessor(acc))); } } @@ -1179,6 +1221,12 @@ impl Parser { .map_err(|_| self.stack_dec())?; stack.push(ExprOrOp::Expr(Expr::Tuple(tup))); } + Some(t) if t.category_is(TC::Reserved) => { + self.level -= 1; + let err = self.skip_and_throw_syntax_err(caused_by!()); + self.errs.push(err); + return Err(()); + } _ => { if stack.len() <= 1 { break; @@ -1340,8 +1388,8 @@ impl Parser { if let Some(res) = self.opt_reduce_args() { let args = res.map_err(|_| self.stack_dec())?; let (obj, method_name) = match acc { - Accessor::Attr(attr) => (*attr.obj, Some(attr.name.symbol)), - Accessor::Local(local) => (Expr::Accessor(Accessor::Local(local)), None), + Accessor::Attr(attr) => (*attr.obj, Some(attr.ident)), + Accessor::Ident(ident) => (Expr::Accessor(Accessor::Ident(ident)), None), _ => todo!(), }; let call = Call::new(obj, method_name, args); @@ -1403,6 +1451,7 @@ impl Parser { /// Set, Dict, Record fn try_reduce_brace_container(&mut self) -> ParseResult { debug_call_info!(self); + assert!(self.cur_is(LBrace)); let l_brace = self.lpop(); if self.cur_is(Newline) { self.skip(); @@ -1416,12 +1465,20 @@ impl Parser { match first { Expr::Def(def) => { let record = self - .try_reduce_record(l_brace, def) + .try_reduce_normal_record(l_brace, def) .map_err(|_| self.stack_dec())?; self.level -= 1; - Ok(BraceContainer::Record(record)) + Ok(BraceContainer::Record(Record::Normal(record))) + } + // Dict + Expr::TypeAsc(_) => todo!(), + Expr::Accessor(acc) if self.cur_is(Semi) => { + let record = self + .try_reduce_shortened_record(l_brace, acc) + .map_err(|_| self.stack_dec())?; + self.level -= 1; + Ok(BraceContainer::Record(Record::Shortened(record))) } - Expr::TypeAsc(_) => todo!(), // invalid syntax other => { let set = self .try_reduce_set(l_brace, other) @@ -1432,27 +1489,28 @@ impl Parser { } } - fn try_reduce_record(&mut self, l_brace: Token, first: Def) -> ParseResult { + fn try_reduce_normal_record( + &mut self, + l_brace: Token, + first: Def, + ) -> ParseResult { debug_call_info!(self); let mut attrs = vec![first]; loop { match self.peek() { Some(t) if t.category_is(TC::Separator) => { self.skip(); - if self.cur_is(Dedent) { - self.skip(); - if self.cur_is(RBrace) { - let r_brace = self.lpop(); - self.level -= 1; - let attrs = RecordAttrs::from(attrs); - return Ok(NormalRecord::new(l_brace, r_brace, attrs)); - } else { - todo!() - } + } + Some(t) if t.is(Dedent) => { + self.skip(); + if self.cur_is(RBrace) { + let r_brace = self.lpop(); + self.level -= 1; + let attrs = RecordAttrs::from(attrs); + return Ok(NormalRecord::new(l_brace, r_brace, attrs)); + } else { + todo!() } - let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?; - let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!()); - attrs.push(def); } Some(term) if term.is(RBrace) => { let r_brace = self.lpop(); @@ -1460,6 +1518,55 @@ impl Parser { let attrs = RecordAttrs::from(attrs); return Ok(NormalRecord::new(l_brace, r_brace, attrs)); } + Some(_) => { + let def = self.try_reduce_chunk(false).map_err(|_| self.stack_dec())?; + let def = option_enum_unwrap!(def, Expr::Def).unwrap_or_else(|| todo!()); + attrs.push(def); + } + _ => todo!(), + } + } + } + + fn try_reduce_shortened_record( + &mut self, + l_brace: Token, + first: Accessor, + ) -> ParseResult { + debug_call_info!(self); + let first = match first { + Accessor::Ident(ident) => ident, + other => todo!("{other}"), // syntax error + }; + let mut idents = vec![first]; + loop { + match self.peek() { + Some(t) if t.category_is(TC::Separator) => { + self.skip(); + } + Some(t) if t.is(Dedent) => { + self.skip(); + if self.cur_is(RBrace) { + let r_brace = self.lpop(); + self.level -= 1; + return Ok(ShortenedRecord::new(l_brace, r_brace, idents)); + } else { + todo!() + } + } + Some(term) if term.is(RBrace) => { + let r_brace = self.lpop(); + self.level -= 1; + return Ok(ShortenedRecord::new(l_brace, r_brace, idents)); + } + Some(_) => { + let acc = self.try_reduce_acc().map_err(|_| self.stack_dec())?; + let acc = match acc { + Accessor::Ident(ident) => ident, + other => todo!("{other}"), // syntax error + }; + idents.push(acc); + } _ => todo!(), } } @@ -1556,6 +1663,14 @@ impl Parser { self.level -= 1; Ok(Signature::Var(var)) } + Expr::DataPack(pack) => { + let data_pack = self + .convert_data_pack_to_data_pack_pat(pack) + .map_err(|_| self.stack_dec())?; + let var = VarSignature::new(VarPattern::DataPack(data_pack), None); + self.level -= 1; + Ok(Signature::Var(var)) + } Expr::Tuple(tuple) => { let tuple_pat = self .convert_tuple_to_tuple_pat(tuple) @@ -1573,7 +1688,7 @@ impl Parser { } other => { self.level -= 1; - let err = self.throw_syntax_err(&other, caused_by!()); + let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); self.errs.push(err); Err(()) } @@ -1583,22 +1698,14 @@ impl Parser { fn convert_accessor_to_var_sig(&mut self, _accessor: Accessor) -> ParseResult { debug_call_info!(self); match _accessor { - Accessor::Local(local) => { - let pat = VarPattern::Ident(Identifier::new(None, VarName::new(local.symbol))); - self.level -= 1; - Ok(VarSignature::new(pat, None)) - } - Accessor::Public(public) => { - let pat = VarPattern::Ident(Identifier::new( - Some(public.dot), - VarName::new(public.symbol), - )); + Accessor::Ident(ident) => { + let pat = VarPattern::Ident(ident); self.level -= 1; Ok(VarSignature::new(pat, None)) } other => { self.level -= 1; - let err = self.throw_syntax_err(&other, caused_by!()); + let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); self.errs.push(err); Err(()) } @@ -1610,12 +1717,54 @@ impl Parser { todo!() } - fn convert_record_to_record_pat( - &mut self, - _record: NormalRecord, - ) -> ParseResult { + fn convert_record_to_record_pat(&mut self, record: Record) -> ParseResult { debug_call_info!(self); - todo!() + match record { + Record::Normal(rec) => { + let mut pats = vec![]; + for mut attr in rec.attrs.into_iter() { + let lhs = + option_enum_unwrap!(attr.sig, Signature::Var).unwrap_or_else(|| todo!()); + let lhs = + option_enum_unwrap!(lhs.pat, VarPattern::Ident).unwrap_or_else(|| todo!()); + assert_eq!(attr.body.block.len(), 1); + let rhs = option_enum_unwrap!(attr.body.block.remove(0), Expr::Accessor) + .unwrap_or_else(|| todo!()); + let rhs = self + .convert_accessor_to_var_sig(rhs) + .map_err(|_| self.stack_dec())?; + pats.push(VarRecordAttr::new(lhs, rhs)); + } + let attrs = VarRecordAttrs::new(pats); + self.level -= 1; + Ok(VarRecordPattern::new(rec.l_brace, attrs, rec.r_brace)) + } + Record::Shortened(rec) => { + let mut pats = vec![]; + for ident in rec.idents.into_iter() { + let rhs = VarSignature::new(VarPattern::Ident(ident.clone()), None); + pats.push(VarRecordAttr::new(ident.clone(), rhs)); + } + let attrs = VarRecordAttrs::new(pats); + self.level -= 1; + Ok(VarRecordPattern::new(rec.l_brace, attrs, rec.r_brace)) + } + } + } + + fn convert_data_pack_to_data_pack_pat( + &mut self, + pack: DataPack, + ) -> ParseResult { + debug_call_info!(self); + let class = self + .convert_rhs_to_type_spec(*pack.class) + .map_err(|_| self.stack_dec())?; + let args = self + .convert_record_to_record_pat(pack.args) + .map_err(|_| self.stack_dec())?; + self.level -= 1; + Ok(VarDataPackPattern::new(class, args)) } fn convert_tuple_to_tuple_pat(&mut self, tuple: Tuple) -> ParseResult { @@ -1675,7 +1824,7 @@ impl Parser { .map_err(|_| self.stack_dec())?, other => { self.level -= 1; - let err = self.throw_syntax_err(&other, caused_by!()); + let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); self.errs.push(err); return Err(()); } @@ -1691,13 +1840,10 @@ impl Parser { fn convert_accessor_to_ident(&mut self, _accessor: Accessor) -> ParseResult { debug_call_info!(self); let ident = match _accessor { - Accessor::Local(local) => Identifier::new(None, VarName::new(local.symbol)), - Accessor::Public(public) => { - Identifier::new(Some(public.dot), VarName::new(public.symbol)) - } + Accessor::Ident(ident) => ident, other => { self.level -= 1; - let err = self.throw_syntax_err(&other, caused_by!()); + let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); self.errs.push(err); return Err(()); } @@ -1747,15 +1893,15 @@ impl Parser { ) -> ParseResult { debug_call_info!(self); match expr { - Expr::Accessor(Accessor::Local(local)) => { - if &local.inspect()[..] == "self" && !allow_self { + Expr::Accessor(Accessor::Ident(ident)) => { + if &ident.inspect()[..] == "self" && !allow_self { self.level -= 1; - let err = self.throw_syntax_err(&local, caused_by!()); + let err = ParseError::simple_syntax_error(line!() as usize, ident.loc()); self.errs.push(err); return Err(()); } - let name = VarName::new(local.symbol); - let pat = ParamPattern::VarName(name); + // FIXME deny: public + let pat = ParamPattern::VarName(ident.name); let param = ParamSignature::new(pat, None, None); self.level -= 1; Ok(param) @@ -1800,45 +1946,36 @@ impl Parser { self.level -= 1; Ok(param) } - Expr::Call(mut call) => match *call.obj { - Expr::Accessor(Accessor::Local(local)) => match &local.inspect()[..] { - "ref" => { - assert_eq!(call.args.len(), 1); - let var = call.args.remove_pos(0).expr; - let var = option_enum_unwrap!(var, Expr::Accessor:(Accessor::Local:(_))) - .unwrap_or_else(|| todo!()); - let pat = ParamPattern::Ref(VarName::new(var.symbol)); - let param = ParamSignature::new(pat, None, None); - self.level -= 1; - Ok(param) - } - "ref!" => { - assert_eq!(call.args.len(), 1); - let var = call.args.remove_pos(0).expr; - let var = option_enum_unwrap!(var, Expr::Accessor:(Accessor::Local:(_))) - .unwrap_or_else(|| todo!()); - let pat = ParamPattern::RefMut(VarName::new(var.symbol)); - let param = ParamSignature::new(pat, None, None); - self.level -= 1; - Ok(param) - } - _other => { - self.level -= 1; - let err = self.throw_syntax_err(&local, caused_by!()); - self.errs.push(err); - Err(()) - } - }, - other => { + Expr::UnaryOp(unary) => match unary.op.kind { + TokenKind::RefOp => { + let var = unary.args.into_iter().next().unwrap(); + let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_))) + .unwrap_or_else(|| todo!()); + let pat = ParamPattern::Ref(var.name); + let param = ParamSignature::new(pat, None, None); self.level -= 1; - let err = self.throw_syntax_err(&other, caused_by!()); + Ok(param) + } + TokenKind::RefMutOp => { + let var = unary.args.into_iter().next().unwrap(); + let var = option_enum_unwrap!(*var, Expr::Accessor:(Accessor::Ident:(_))) + .unwrap_or_else(|| todo!()); + let pat = ParamPattern::RefMut(var.name); + let param = ParamSignature::new(pat, None, None); + self.level -= 1; + Ok(param) + } + // TODO: Spread + _other => { + self.level -= 1; + let err = ParseError::simple_syntax_error(line!() as usize, unary.loc()); self.errs.push(err); Err(()) } }, other => { self.level -= 1; - let err = self.throw_syntax_err(&other, caused_by!()); + let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); self.errs.push(err); Err(()) } @@ -1864,7 +2001,7 @@ impl Parser { fn convert_record_to_param_record_pat( &mut self, - _record: NormalRecord, + _record: Record, ) -> ParseResult { debug_call_info!(self); todo!() @@ -1937,7 +2074,7 @@ impl Parser { } other => { self.level -= 1; - let err = self.throw_syntax_err(&other, caused_by!()); + let err = ParseError::simple_syntax_error(line!() as usize, other.loc()); self.errs.push(err); Err(()) } @@ -1981,10 +2118,7 @@ impl Parser { todo!() } - fn convert_record_to_param_pat( - &mut self, - _record: NormalRecord, - ) -> ParseResult { + fn convert_record_to_param_pat(&mut self, _record: Record) -> ParseResult { debug_call_info!(self); todo!() } @@ -2038,10 +2172,9 @@ impl Parser { ) -> ParseResult { debug_call_info!(self); let t_spec = match accessor { - Accessor::Local(local) => PreDeclTypeSpec::Simple(SimpleTypeSpec::new( - VarName::new(local.symbol), - ConstArgs::empty(), - )), + Accessor::Ident(ident) => { + PreDeclTypeSpec::Simple(SimpleTypeSpec::new(ident.name, ConstArgs::empty())) + } other => todo!("{other}"), }; self.level -= 1; diff --git a/compiler/erg_parser/token.rs b/compiler/erg_parser/token.rs index 4dabc27b..b59efee1 100644 --- a/compiler/erg_parser/token.rs +++ b/compiler/erg_parser/token.rs @@ -103,6 +103,10 @@ pub enum TokenKind { DotOp, /// `cross` (vector product) CrossOp, + /// `ref` (special unary) + RefOp, + /// `ref!` (special unary) + RefMutOp, /// = Equal, /// := @@ -183,10 +187,8 @@ pub enum TokenCategory { LambdaOp, /// \n ; Separator, - /// ^ (reserved) - Caret, - /// & - Amper, + /// ^ & + Reserved, /// @ AtSign, /// | @@ -210,7 +212,7 @@ impl TokenKind { Symbol => TokenCategory::Symbol, NatLit | IntLit | RatioLit | StrLit | BoolLit | NoneLit | EllipsisLit | NoImplLit | InfLit => TokenCategory::Literal, - PrePlus | PreMinus | PreBitNot | Mutate => TokenCategory::UnaryOp, + PrePlus | PreMinus | PreBitNot | Mutate | RefOp | RefMutOp => TokenCategory::UnaryOp, Try => TokenCategory::PostfixOp, Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus => { TokenCategory::SpecialBinOp @@ -220,8 +222,7 @@ impl TokenKind { Semi | Newline => TokenCategory::Separator, LParen | LBrace | LSqBr | Indent => TokenCategory::LEnclosure, RParen | RBrace | RSqBr | Dedent => TokenCategory::REnclosure, - Caret => TokenCategory::Caret, - Amper => TokenCategory::Amper, + Caret | Amper => TokenCategory::Reserved, AtSign => TokenCategory::AtSign, VBar => TokenCategory::VBar, UBar => TokenCategory::UBar, @@ -234,16 +235,16 @@ impl TokenKind { pub const fn precedence(&self) -> Option { let prec = match self { - Dot | DblColon => 200, // . - Pow => 190, // ** - PrePlus | PreMinus | PreBitNot => 180, // (unary) + - * ~ - Star | Slash | FloorDiv | Mod | CrossOp | DotOp => 170, // * / // % cross dot - Plus | Minus => 160, // + - - Shl | Shr => 150, // << >> - BitAnd => 140, // && - BitXor => 130, // ^^ - BitOr => 120, // || - Closed | LeftOpen | RightOpen | Open => 100, // range operators + Dot | DblColon => 200, // . + Pow => 190, // ** + PrePlus | PreMinus | PreBitNot | RefOp | RefMutOp => 180, // (unary) + - * ~ ref ref! + Star | Slash | FloorDiv | Mod | CrossOp | DotOp => 170, // * / // % cross dot + Plus | Minus => 160, // + - + Shl | Shr => 150, // << >> + BitAnd => 140, // && + BitXor => 130, // ^^ + BitOr => 120, // || + Closed | LeftOpen | RightOpen | Open => 100, // range operators Less | Gre | LessEq | GreEq | DblEq | NotEq | InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot AndOp => 80, // and OrOp => 70, // or @@ -372,6 +373,16 @@ impl Token { Self::from_str(TokenKind::Symbol, cont) } + #[inline] + pub fn symbol_with_line(cont: &str, line: usize) -> Self { + Token { + kind: TokenKind::Symbol, + content: Str::rc(cont), + lineno: line, + col_begin: 0, + } + } + pub const fn static_symbol(s: &'static str) -> Self { Token { kind: TokenKind::Symbol, diff --git a/compiler/erg_type/Cargo.toml b/compiler/erg_type/Cargo.toml index e209f605..3f9432f9 100644 --- a/compiler/erg_type/Cargo.toml +++ b/compiler/erg_type/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_type" -version = "0.3.2" +version = "0.4.0-beta.1" description = "APIs for Erg types" authors = ["Shunsuke Shibayama "] license = "MIT OR Apache-2.0" @@ -18,7 +18,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ] [dependencies] -erg_common = { version = "0.3.2", path = "../erg_common" } +erg_common = { version = "0.4.0-beta.1", path = "../erg_common" } [lib] path = "lib.rs" diff --git a/compiler/erg_type/constructors.rs b/compiler/erg_type/constructors.rs index 756df604..4761c2fa 100644 --- a/compiler/erg_type/constructors.rs +++ b/compiler/erg_type/constructors.rs @@ -21,25 +21,25 @@ pub fn named_free_var(name: Str, level: usize, constraint: Constraint) -> Type { } pub fn array(elem_t: Type, len: TyParam) -> Type { - poly_class("Array", vec![TyParam::t(elem_t), len]) + poly("Array", vec![TyParam::t(elem_t), len]) } pub fn array_mut(elem_t: Type, len: TyParam) -> Type { - poly_class("Array!", vec![TyParam::t(elem_t), len]) + poly("Array!", vec![TyParam::t(elem_t), len]) } pub fn dict(k_t: Type, v_t: Type) -> Type { - poly_class("Dict", vec![TyParam::t(k_t), TyParam::t(v_t)]) + poly("Dict", vec![TyParam::t(k_t), TyParam::t(v_t)]) } pub fn tuple(args: Vec) -> Type { let name = format!("Tuple{}", args.len()); - poly_class(name, args.into_iter().map(TyParam::t).collect()) + poly(name, args.into_iter().map(TyParam::t).collect()) } #[inline] pub fn range(t: Type) -> Type { - poly_class("Range", vec![TyParam::t(t)]) + poly("Range", vec![TyParam::t(t)]) } pub fn enum_t(s: Set) -> Type { @@ -91,23 +91,26 @@ pub fn int_interval, Q: Into>(op: IntervalOp, l: P, r: } pub fn iter(t: Type) -> Type { - poly_class("Iter", vec![TyParam::t(t)]) + poly("Iter", vec![TyParam::t(t)]) } pub fn ref_(t: Type) -> Type { Type::Ref(Box::new(t)) } -pub fn ref_mut(t: Type) -> Type { - Type::RefMut(Box::new(t)) +pub fn ref_mut(before: Type, after: Option) -> Type { + Type::RefMut { + before: Box::new(before), + after: after.map(Box::new), + } } pub fn option(t: Type) -> Type { - poly_class("Option", vec![TyParam::t(t)]) + poly("Option", vec![TyParam::t(t)]) } pub fn option_mut(t: Type) -> Type { - poly_class("Option!", vec![TyParam::t(t)]) + poly("Option!", vec![TyParam::t(t)]) } pub fn subr_t( @@ -207,13 +210,14 @@ pub fn proc2(l: Type, r: Type, return_t: Type) -> Type { pub fn fn_met( self_t: Type, - non_default_params: Vec, + mut non_default_params: Vec, var_params: Option, default_params: Vec, return_t: Type, ) -> Type { + non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t)); Type::Subr(SubrType::new( - SubrKind::FuncMethod(Box::new(self_t)), + SubrKind::Func, non_default_params, var_params, default_params, @@ -236,15 +240,15 @@ pub fn fn1_met(self_t: Type, input_t: Type, return_t: Type) -> Type { } pub fn pr_met( - self_before: Type, - self_after: Option, - non_default_params: Vec, + self_t: Type, + mut non_default_params: Vec, var_params: Option, default_params: Vec, return_t: Type, ) -> Type { + non_default_params.insert(0, ParamTy::kw(Str::ever("self"), self_t)); Type::Subr(SubrType::new( - SubrKind::pr_met(self_before, self_after), + SubrKind::Proc, non_default_params, var_params, default_params, @@ -252,14 +256,13 @@ pub fn pr_met( )) } -pub fn pr0_met(self_before: Type, self_after: Option, return_t: Type) -> Type { - pr_met(self_before, self_after, vec![], None, vec![], return_t) +pub fn pr0_met(self_t: Type, return_t: Type) -> Type { + pr_met(self_t, vec![], None, vec![], return_t) } -pub fn pr1_met(self_before: Type, self_after: Option, input_t: Type, return_t: Type) -> Type { +pub fn pr1_met(self_t: Type, input_t: Type, return_t: Type) -> Type { pr_met( - self_before, - self_after, + self_t, vec![ParamTy::anonymous(input_t)], None, vec![], @@ -286,13 +289,8 @@ pub fn callable(param_ts: Vec, return_t: Type) -> Type { } #[inline] -pub fn class>(name: S) -> Type { - Type::MonoClass(name.into()) -} - -#[inline] -pub fn trait_>(name: S) -> Type { - Type::MonoTrait(name.into()) +pub fn mono>(name: S) -> Type { + Type::Mono(name.into()) } #[inline] @@ -301,16 +299,8 @@ pub fn mono_q>(name: S) -> Type { } #[inline] -pub fn poly_class>(name: S, params: Vec) -> Type { - Type::PolyClass { - name: name.into(), - params, - } -} - -#[inline] -pub fn poly_trait>(name: S, params: Vec) -> Type { - Type::PolyTrait { +pub fn poly>(name: S, params: Vec) -> Type { + Type::Poly { name: name.into(), params, } diff --git a/compiler/erg_type/free.rs b/compiler/erg_type/free.rs index 267f376f..04f3a0a2 100644 --- a/compiler/erg_type/free.rs +++ b/compiler/erg_type/free.rs @@ -107,23 +107,38 @@ impl LimitedDisplay for Constraint { sup, cyclicity, } => match (sub == &Type::Never, sup == &Type::Obj) { - (true, true) => write!(f, ": Type (:> Never, <: Obj)"), + (true, true) => { + write!(f, ": Type")?; + if cfg!(feature = "debug") { + write!(f, "(:> Never, <: Obj)")?; + } + Ok(()) + } (true, false) => { write!(f, "<: ")?; sup.limited_fmt(f, limit - 1)?; - write!(f, "(cyclicity: {cyclicity:?})") + if cfg!(feature = "debug") { + write!(f, "(cyclicity: {cyclicity:?})")?; + } + Ok(()) } (false, true) => { write!(f, ":> ")?; sub.limited_fmt(f, limit - 1)?; - write!(f, "(cyclicity: {cyclicity:?})") + if cfg!(feature = "debug") { + write!(f, "(cyclicity: {cyclicity:?})")?; + } + Ok(()) } (false, false) => { write!(f, ":> ")?; sub.limited_fmt(f, limit - 1)?; write!(f, ", <: ")?; sup.limited_fmt(f, limit - 1)?; - write!(f, "(cyclicity: {cyclicity:?})") + if cfg!(feature = "debug") { + write!(f, "(cyclicity: {cyclicity:?})")?; + } + Ok(()) } }, Self::TypeOf(t) => { @@ -136,7 +151,7 @@ impl LimitedDisplay for Constraint { } impl Constraint { - pub const fn sandwiched(sub: Type, sup: Type, cyclicity: Cyclicity) -> Self { + pub const fn new_sandwiched(sub: Type, sup: Type, cyclicity: Cyclicity) -> Self { Self::Sandwiched { sub, sup, @@ -144,20 +159,20 @@ impl Constraint { } } - pub fn type_of(t: Type) -> Self { + pub fn new_type_of(t: Type) -> Self { if t == Type::Type { - Self::sandwiched(Type::Never, Type::Obj, Not) + Self::new_sandwiched(Type::Never, Type::Obj, Not) } else { Self::TypeOf(t) } } - pub const fn subtype_of(sup: Type, cyclicity: Cyclicity) -> Self { - Self::sandwiched(Type::Never, sup, cyclicity) + pub const fn new_subtype_of(sup: Type, cyclicity: Cyclicity) -> Self { + Self::new_sandwiched(Type::Never, sup, cyclicity) } - pub const fn supertype_of(sub: Type, cyclicity: Cyclicity) -> Self { - Self::sandwiched(sub, Type::Obj, cyclicity) + pub const fn new_supertype_of(sub: Type, cyclicity: Cyclicity) -> Self { + Self::new_sandwiched(sub, Type::Obj, cyclicity) } pub const fn is_uninited(&self) -> bool { @@ -171,6 +186,17 @@ impl Constraint { } } + pub fn lift(&self) { + match self { + Self::Sandwiched { sub, sup, .. } => { + sub.lift(); + sup.lift(); + } + Self::TypeOf(t) => t.lift(), + Self::Uninited => {} + } + } + pub fn get_type(&self) -> Option<&Type> { match self { Self::TypeOf(ty) => Some(ty), @@ -183,28 +209,28 @@ impl Constraint { } } - pub fn get_sub_type(&self) -> Option<&Type> { + pub fn get_sub(&self) -> Option<&Type> { match self { Self::Sandwiched { sub, .. } => Some(sub), _ => None, } } - pub fn get_super_type(&self) -> Option<&Type> { + pub fn get_super(&self) -> Option<&Type> { match self { Self::Sandwiched { sup, .. } => Some(sup), _ => None, } } - pub fn get_sub_sup_type(&self) -> Option<(&Type, &Type)> { + pub fn get_sub_sup(&self) -> Option<(&Type, &Type)> { match self { Self::Sandwiched { sub, sup, .. } => Some((sub, sup)), _ => None, } } - pub fn get_super_type_mut(&mut self) -> Option<&mut Type> { + pub fn get_super_mut(&mut self) -> Option<&mut Type> { match self { Self::Sandwiched { sup, .. } => Some(sup), _ => None, @@ -250,7 +276,11 @@ impl LimitedDisplay for FreeKind { return write!(f, "..."); } match self { - Self::Linked(t) | Self::UndoableLinked { t, .. } => t.limited_fmt(f, limit), + Self::Linked(t) | Self::UndoableLinked { t, .. } => { + write!(f, "(")?; + t.limited_fmt(f, limit)?; + write!(f, ")") + } Self::NamedUnbound { name, lev, @@ -258,7 +288,11 @@ impl LimitedDisplay for FreeKind { } => { write!(f, "?{name}(")?; constraint.limited_fmt(f, limit - 1)?; - write!(f, ")[{lev}]") + write!(f, ")")?; + if cfg!(feature = "debug") { + write!(f, "[{lev}]")?; + } + Ok(()) } Self::Unbound { id, @@ -267,7 +301,11 @@ impl LimitedDisplay for FreeKind { } => { write!(f, "?{id}(")?; constraint.limited_fmt(f, limit - 1)?; - write!(f, ")[{lev}]") + write!(f, ")")?; + if cfg!(feature = "debug") { + write!(f, "[{lev}]")?; + } + Ok(()) } } } @@ -417,13 +455,17 @@ impl Free { pub fn lift(&self) { match &mut *self.borrow_mut() { - FreeKind::Unbound { lev, .. } | FreeKind::NamedUnbound { lev, .. } => { + FreeKind::Unbound { + lev, constraint, .. + } + | FreeKind::NamedUnbound { + lev, constraint, .. + } => { *lev += 1; + constraint.lift(); } FreeKind::Linked(t) | FreeKind::UndoableLinked { t, .. } => { - if let Some(lev) = t.level() { - t.update_level(lev + 1); - } + t.lift(); } } } @@ -495,23 +537,22 @@ impl Free { }) } - pub fn type_of(&self) -> Option { + pub fn get_type(&self) -> Option { self.borrow() .constraint() .and_then(|c| c.get_type().cloned()) } - pub fn crack_subtype(&self) -> Option { + pub fn get_sup(&self) -> Option { self.borrow() .constraint() - .and_then(|c| c.get_super_type().cloned()) + .and_then(|c| c.get_super().cloned()) } - pub fn crack_bound_types(&self) -> Option<(Type, Type)> { - self.borrow().constraint().and_then(|c| { - c.get_sub_sup_type() - .map(|(sub, sup)| (sub.clone(), sup.clone())) - }) + pub fn get_bound_types(&self) -> Option<(Type, Type)> { + self.borrow() + .constraint() + .and_then(|c| c.get_sub_sup().map(|(sub, sup)| (sub.clone(), sup.clone()))) } pub fn is_unbound(&self) -> bool { @@ -542,7 +583,7 @@ impl Free { matches!( &*self.borrow(), FreeKind::Unbound { constraint, .. } - | FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_type().is_some() + | FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub().is_some() ) } @@ -550,7 +591,7 @@ impl Free { matches!( &*self.borrow(), FreeKind::Unbound { constraint, .. } - | FreeKind::NamedUnbound { constraint, .. } if constraint.get_super_type().is_some() + | FreeKind::NamedUnbound { constraint, .. } if constraint.get_super().is_some() ) } @@ -558,12 +599,15 @@ impl Free { matches!( &*self.borrow(), FreeKind::Unbound { constraint, .. } - | FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_sup_type().is_some() + | FreeKind::NamedUnbound { constraint, .. } if constraint.get_sub_sup().is_some() ) } pub fn is_linked(&self) -> bool { - matches!(&*self.borrow(), FreeKind::Linked(_)) + matches!( + &*self.borrow(), + FreeKind::Linked(_) | FreeKind::UndoableLinked { .. } + ) } pub fn unbound_name(&self) -> Option { diff --git a/compiler/erg_type/lib.rs b/compiler/erg_type/lib.rs index a803395a..127fc5a4 100644 --- a/compiler/erg_type/lib.rs +++ b/compiler/erg_type/lib.rs @@ -18,7 +18,7 @@ use erg_common::vis::Field; use erg_common::{enum_unwrap, fmt_option, fmt_set_split_with, set, Str}; use crate::codeobj::CodeObj; -use crate::constructors::{and, class, int_interval, mono_q}; +use crate::constructors::{int_interval, mono, mono_q}; use crate::free::{ fresh_varname, Constraint, Cyclicity, Free, FreeKind, FreeTyVar, HasLevel, Level, }; @@ -129,12 +129,50 @@ macro_rules! impl_t_for_enum { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct UserConstSubr { - code: CodeObj, + code: CodeObj, // may be this should be HIR or AST block +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ValueArgs { + pub pos_args: Vec, + pub kw_args: Dict, +} + +impl ValueArgs { + pub const fn new(pos_args: Vec, kw_args: Dict) -> Self { + ValueArgs { pos_args, kw_args } + } + + pub fn remove_left_or_key(&mut self, key: &str) -> Option { + if !self.pos_args.is_empty() { + Some(self.pos_args.remove(0)) + } else { + self.kw_args.remove(key) + } + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct BuiltinConstSubr { - subr: fn(Vec) -> ValueObj, + name: &'static str, + subr: fn(ValueArgs, Option) -> ValueObj, + t: Type, +} + +impl fmt::Display for BuiltinConstSubr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "", self.name) + } +} + +impl BuiltinConstSubr { + pub const fn new( + name: &'static str, + subr: fn(ValueArgs, Option) -> ValueObj, + t: Type, + ) -> Self { + Self { name, subr, t } + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -143,11 +181,29 @@ pub enum ConstSubr { Builtin(BuiltinConstSubr), } +impl fmt::Display for ConstSubr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ConstSubr::User(subr) => { + write!(f, "", subr.code.name) + } + ConstSubr::Builtin(subr) => write!(f, "{subr}"), + } + } +} + impl ConstSubr { - pub fn call(&self, args: Vec) -> ValueObj { + pub fn call(&self, args: ValueArgs, __name__: Option) -> ValueObj { match self { ConstSubr::User(_user) => todo!(), - ConstSubr::Builtin(builtin) => (builtin.subr)(args), + ConstSubr::Builtin(builtin) => (builtin.subr)(args, __name__), + } + } + + pub fn class(&self) -> Type { + match self { + ConstSubr::User(_user) => todo!(), + ConstSubr::Builtin(builtin) => builtin.t.clone(), } } } @@ -185,7 +241,13 @@ impl LimitedDisplay for TyBound { } match self { Self::Sandwiched { sub, mid, sup } => match (sub == &Type::Never, sup == &Type::Obj) { - (true, true) => write!(f, "{mid}: Type (:> Never, <: Obj)"), + (true, true) => { + write!(f, "{mid}: Type")?; + if cfg!(feature = "debug") { + write!(f, "(:> Never, <: Obj)")?; + } + Ok(()) + } (true, false) => { write!(f, "{mid} <: ")?; sup.limited_fmt(f, limit - 1) @@ -688,7 +750,7 @@ impl LimitedDisplay for SubrType { if limit == 0 { return write!(f, "..."); } - write!(f, "{}(", self.kind.prefix())?; + write!(f, "(")?; for (i, param) in self.non_default_params.iter().enumerate() { if i != 0 { write!(f, ", ")?; @@ -730,11 +792,9 @@ impl SubrType { } pub fn contains_tvar(&self, name: &str) -> bool { - self.kind.contains_tvar(name) - || self - .non_default_params - .iter() - .any(|pt| pt.typ().contains_tvar(name)) + self.non_default_params + .iter() + .any(|pt| pt.typ().contains_tvar(name)) || self .var_params .as_ref() @@ -748,8 +808,7 @@ impl SubrType { } pub fn has_qvar(&self) -> bool { - self.kind.has_qvar() - || self.non_default_params.iter().any(|pt| pt.typ().has_qvar()) + self.non_default_params.iter().any(|pt| pt.typ().has_qvar()) || self .var_params .as_ref() @@ -761,11 +820,6 @@ impl SubrType { pub fn typarams(&self) -> Vec { [ - self.kind - .self_t() - .map(|t| TyParam::t(t.clone())) - .into_iter() - .collect(), self.non_default_params .iter() .map(|pt| TyParam::t(pt.typ().clone())) @@ -782,6 +836,13 @@ impl SubrType { ] .concat() } + + pub fn self_t(&self) -> Option<&Type> { + self.non_default_params + .iter() + .find(|p| p.name() == Some(&Str::ever("self")) || p.name() == Some(&Str::ever("Self"))) + .map(|p| p.typ()) + } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -877,157 +938,17 @@ impl QuantifiedType { } } -type SelfType = Type; - -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum SubrKind { Func, Proc, - FuncMethod(Box), - ProcMethod { - before: Box, - after: Option>, - }, -} - -impl HasLevel for SubrKind { - fn level(&self) -> Option { - todo!() - } - - fn update_level(&self, level: usize) { - match self { - Self::FuncMethod(t) => t.update_level(level), - Self::ProcMethod { before, after } => { - before.update_level(level); - if let Some(t) = after.as_ref() { - t.update_level(level); - } - } - _ => {} - } - } - - fn lift(&self) { - match self { - Self::FuncMethod(t) => t.lift(), - Self::ProcMethod { before, after } => { - before.lift(); - if let Some(t) = after.as_ref() { - t.lift(); - } - } - _ => {} - } - } } impl SubrKind { - pub fn fn_met(t: SelfType) -> Self { - SubrKind::FuncMethod(Box::new(t)) - } - - pub fn pr_met(before: SelfType, after: Option) -> Self { - Self::ProcMethod { - before: Box::new(before), - after: after.map(Box::new), - } - } - pub const fn arrow(&self) -> Str { match self { - Self::Func | Self::FuncMethod(_) => Str::ever("->"), - Self::Proc | Self::ProcMethod { .. } => Str::ever("=>"), - } - } - - pub const fn inner_len(&self) -> usize { - match self { - Self::Func | Self::Proc => 0, - Self::FuncMethod(_) | Self::ProcMethod { .. } => 1, - } - } - - pub fn prefix(&self) -> String { - match self { - Self::Func | Self::Proc => "".to_string(), - Self::FuncMethod(t) => format!("{t}."), - Self::ProcMethod { before, after } => { - if let Some(after) = after { - format!("({before} ~> {after}).") - } else { - format!("{before}.") - } - } - } - } - - pub fn has_qvar(&self) -> bool { - match self { - Self::Func | Self::Proc => false, - Self::FuncMethod(t) => t.has_qvar(), - Self::ProcMethod { before, after } => { - before.has_qvar() || after.as_ref().map(|t| t.has_qvar()).unwrap_or(false) - } - } - } - - pub fn contains_tvar(&self, name: &str) -> bool { - match self { - Self::Func | Self::Proc => false, - Self::FuncMethod(t) => t.contains_tvar(name), - Self::ProcMethod { before, after } => { - before.contains_tvar(name) - || after - .as_ref() - .map(|t| t.contains_tvar(name)) - .unwrap_or(false) - } - } - } - - pub fn is_cachable(&self) -> bool { - match self { - Self::Func | Self::Proc => true, - Self::FuncMethod(t) => t.is_cachable(), - Self::ProcMethod { before, after } => { - before.is_cachable() && after.as_ref().map(|t| t.is_cachable()).unwrap_or(true) - } - } - } - - pub fn has_unbound_var(&self) -> bool { - match self { - Self::Func | Self::Proc => false, - Self::FuncMethod(t) => t.has_unbound_var(), - Self::ProcMethod { before, after } => { - before.has_unbound_var() - || after.as_ref().map(|t| t.has_unbound_var()).unwrap_or(false) - } - } - } - - pub fn same_kind_as(&self, other: &Self) -> bool { - matches!( - (self, other), - (Self::Func, Self::Func) - | (Self::Proc, Self::Proc) - | (Self::FuncMethod(_), Self::FuncMethod(_)) - | (Self::ProcMethod { .. }, Self::ProcMethod { .. }) - ) - } - - pub fn self_t(&self) -> Option<&SelfType> { - match self { - Self::FuncMethod(t) | Self::ProcMethod { before: t, .. } => Some(t), - _ => None, - } - } - - pub fn self_t_mut(&mut self) -> Option<&mut SelfType> { - match self { - Self::FuncMethod(t) | Self::ProcMethod { before: t, .. } => Some(t), - _ => None, + Self::Func => Str::ever("->"), + Self::Proc => Str::ever("=>"), } } } @@ -1053,7 +974,6 @@ impl Ownership { #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct ArgsOwnership { - pub self_: Option, pub non_defaults: Vec, pub var_params: Option, pub defaults: Vec<(Str, Ownership)>, @@ -1061,9 +981,6 @@ pub struct ArgsOwnership { impl fmt::Display for ArgsOwnership { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some(self_) = self.self_.as_ref() { - write!(f, "({self_:?}).")?; - } write!(f, "(")?; for (i, o) in self.non_defaults.iter().enumerate() { if i != 0 { @@ -1084,13 +1001,11 @@ impl fmt::Display for ArgsOwnership { impl ArgsOwnership { pub const fn new( - self_: Option, non_defaults: Vec, var_params: Option, defaults: Vec<(Str, Ownership)>, ) -> Self { Self { - self_, non_defaults, var_params, defaults, @@ -1123,11 +1038,13 @@ pub enum Type { NotImplemented, Ellipsis, // これはクラスのほうで型推論用のマーカーではない Never, // {} - MonoClass(Str), - MonoTrait(Str), + Mono(Str), /* Polymorphic types */ Ref(Box), - RefMut(Box), + RefMut { + before: Box, + after: Option>, + }, Subr(SubrType), // CallableはProcの上位型なので、変数に!をつける Callable { @@ -1147,14 +1064,10 @@ pub enum Type { And(Box, Box), Not(Box, Box), Or(Box, Box), - PolyClass { + Poly { name: Str, params: Vec, - }, // T(params) - PolyTrait { - name: Str, - params: Vec, - }, // T(params) + }, /* Special types (inference-time types) */ MonoQVar(Str), // QuantifiedTyの中で使う一般化型変数、利便性のためMonoとは区別する PolyQVar { @@ -1195,11 +1108,19 @@ impl PartialEq for Type { | (Self::NotImplemented, Self::NotImplemented) | (Self::Ellipsis, Self::Ellipsis) | (Self::Never, Self::Never) => true, - (Self::MonoClass(l), Self::MonoClass(r)) | (Self::MonoTrait(l), Self::MonoTrait(r)) => { - l == r - } + (Self::Mono(l), Self::Mono(r)) => l == r, (Self::MonoQVar(l), Self::MonoQVar(r)) => l == r, - (Self::Ref(l), Self::Ref(r)) | (Self::RefMut(l), Self::RefMut(r)) => l == r, + (Self::Ref(l), Self::Ref(r)) => l == r, + ( + Self::RefMut { + before: l1, + after: l2, + }, + Self::RefMut { + before: r1, + after: r2, + }, + ) => l1 == r1 && l2 == r2, (Self::Subr(l), Self::Subr(r)) => l == r, ( Self::Callable { @@ -1229,11 +1150,7 @@ impl PartialEq for Type { | (Self::Not(ll, lr), Self::Not(rl, rr)) | (Self::Or(ll, lr), Self::Or(rl, rr)) => ll == rl && lr == rr, ( - Self::PolyClass { - name: ln, - params: lps, - } - | Self::PolyTrait { + Self::Poly { name: ln, params: lps, } @@ -1241,11 +1158,7 @@ impl PartialEq for Type { name: ln, params: lps, }, - Self::PolyClass { - name: rn, - params: rps, - } - | Self::PolyTrait { + Self::Poly { name: rn, params: rps, } @@ -1290,12 +1203,21 @@ impl LimitedDisplay for Type { return write!(f, "..."); } match self { - Self::MonoClass(name) | Self::MonoTrait(name) => write!(f, "{name}"), - Self::Ref(t) | Self::RefMut(t) => { + Self::Mono(name) => write!(f, "{name}"), + Self::Ref(t) => { write!(f, "{}(", self.name())?; t.limited_fmt(f, limit - 1)?; write!(f, ")") } + Self::RefMut { before, after } => { + write!(f, "{}(", self.name())?; + before.limited_fmt(f, limit - 1)?; + if let Some(after) = after { + write!(f, " ~> ")?; + after.limited_fmt(f, limit - 1)?; + } + write!(f, ")") + } Self::Callable { param_ts, return_t } => { write!(f, "Callable((")?; for (i, t) in param_ts.iter().enumerate() { @@ -1338,7 +1260,7 @@ impl LimitedDisplay for Type { write!(f, " or ")?; rhs.limited_fmt(f, limit - 1) } - Self::PolyClass { name, params } | Self::PolyTrait { name, params } => { + Self::Poly { name, params } => { write!(f, "{name}(")?; for (i, tp) in params.iter().enumerate() { if i > 0 { @@ -1427,7 +1349,7 @@ impl From<&str> for Type { "Inf" => Self::Inf, "NegInf" => Self::NegInf, "_" => Self::Obj, - other => Self::MonoClass(Str::rc(other)), + other => Self::Mono(Str::rc(other)), } } } @@ -1451,15 +1373,17 @@ impl HasType for Type { } fn inner_ts(&self) -> Vec { match self { - Self::Ref(t) | Self::RefMut(t) => { + Self::Ref(t) => { vec![t.as_ref().clone()] } + Self::RefMut { before, .. } => { + // REVIEW: + vec![before.as_ref().clone()] + } // Self::And(ts) | Self::Or(ts) => , Self::Subr(_sub) => todo!(), Self::Callable { param_ts, .. } => param_ts.clone(), - Self::PolyClass { params, .. } | Self::PolyTrait { params, .. } => { - params.iter().filter_map(get_t_from_tp).collect() - } + Self::Poly { params, .. } => params.iter().filter_map(get_t_from_tp).collect(), _ => vec![], } } @@ -1483,7 +1407,13 @@ impl HasLevel for Type { fn update_level(&self, level: Level) { match self { Self::FreeVar(v) => v.update_level(level), - Self::Ref(t) | Self::RefMut(t) => t.update_level(level), + Self::Ref(t) => t.update_level(level), + Self::RefMut { before, after } => { + before.update_level(level); + if let Some(after) = after { + after.update_level(level); + } + } Self::Callable { param_ts, return_t } => { for p in param_ts.iter() { p.update_level(level); @@ -1491,7 +1421,6 @@ impl HasLevel for Type { return_t.update_level(level); } Self::Subr(subr) => { - subr.kind.update_level(level); for pt in subr.non_default_params.iter() { pt.typ().update_level(level); } @@ -1512,7 +1441,7 @@ impl HasLevel for Type { t.update_level(level); } } - Self::PolyClass { params, .. } | Self::PolyTrait { params, .. } => { + Self::Poly { params, .. } => { for p in params.iter() { p.update_level(level); } @@ -1539,7 +1468,13 @@ impl HasLevel for Type { fn lift(&self) { match self { Self::FreeVar(v) => v.lift(), - Self::Ref(t) | Self::RefMut(t) => t.lift(), + Self::Ref(t) => t.lift(), + Self::RefMut { before, after } => { + before.lift(); + if let Some(after) = after { + after.lift(); + } + } Self::Callable { param_ts, return_t } => { for p in param_ts.iter() { p.lift(); @@ -1547,7 +1482,6 @@ impl HasLevel for Type { return_t.lift(); } Self::Subr(subr) => { - subr.kind.lift(); for pt in subr.non_default_params.iter() { pt.typ().lift(); } @@ -1566,7 +1500,7 @@ impl HasLevel for Type { t.lift(); } } - Self::PolyClass { params, .. } | Self::PolyTrait { params, .. } => { + Self::Poly { params, .. } => { for p in params.iter() { p.lift(); } @@ -1617,12 +1551,12 @@ impl Type { fv.link(&t.mutate()); Self::FreeVar(fv) } - Self::Int => class("Int!"), - Self::Nat => class("Nat!"), - Self::Ratio => class("Ratio!"), - Self::Float => class("Float!"), - Self::Bool => class("Bool!"), - Self::Str => class("Str!"), + Self::Int => mono("Int!"), + Self::Nat => mono("Nat!"), + Self::Ratio => mono("Ratio!"), + Self::Float => mono("Float!"), + Self::Bool => mono("Bool!"), + Self::Str => mono("Str!"), _ => todo!(), } } @@ -1655,47 +1589,6 @@ impl Type { } } - pub fn is_class(&self) -> bool { - match self { - Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_class(), - Self::Obj - | Self::Int - | Self::Nat - | Self::Ratio - | Self::Float - | Self::Bool - | Self::Str - | Self::NoneType - | Self::Code - | Self::Module - | Self::Frame - | Self::Error - | Self::Inf - | Self::NegInf - | Self::Type - | Self::Class - | Self::Trait - | Self::Patch - | Self::NotImplemented - | Self::Ellipsis - | Self::Never - | Self::Subr(_) - | Self::Callable { .. } - | Self::Record(_) - | Self::Quantified(_) => true, - Self::MonoClass(_) | Self::PolyClass { .. } => true, - _ => false, - } - } - - pub fn is_trait(&self) -> bool { - match self { - Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_trait(), - Self::MonoTrait(_) | Self::PolyTrait { .. } => true, - _ => false, - } - } - pub fn is_mut(&self) -> bool { match self { Self::FreeVar(fv) => { @@ -1705,13 +1598,12 @@ impl Type { fv.unbound_name().unwrap().ends_with('!') } } - Self::MonoClass(name) - | Self::MonoTrait(name) + Self::Mono(name) | Self::MonoQVar(name) - | Self::PolyClass { name, .. } - | Self::PolyTrait { name, .. } + | Self::Poly { name, .. } | Self::PolyQVar { name, .. } | Self::MonoProj { rhs: name, .. } => name.ends_with('!'), + Self::Refinement(refine) => refine.t.is_mut(), _ => false, } } @@ -1720,11 +1612,12 @@ impl Type { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_nonelike(), Self::NoneType => true, - Self::PolyClass { name, params } if &name[..] == "Option" || &name[..] == "Option!" => { + Self::Poly { name, params } if &name[..] == "Option" || &name[..] == "Option!" => { let inner_t = enum_unwrap!(params.first().unwrap(), TyParam::Type); inner_t.is_nonelike() } - Self::PolyClass { name, params } if &name[..] == "Tuple" => params.is_empty(), + Self::Poly { name, params } if &name[..] == "Tuple" => params.is_empty(), + Self::Refinement(refine) => refine.t.is_nonelike(), _ => false, } } @@ -1738,11 +1631,11 @@ impl Type { Self::FreeVar(fv) => { fv.unbound_name().map(|n| &n[..] == name).unwrap_or(false) || fv - .crack_bound_types() + .get_bound_types() .map(|(sub, sup)| sub.contains_tvar(name) || sup.contains_tvar(name)) .unwrap_or(false) } - Self::PolyClass { params, .. } | Self::PolyTrait { params, .. } => { + Self::Poly { params, .. } => { for param in params.iter() { match param { TyParam::Type(t) if t.contains_tvar(name) => { @@ -1754,6 +1647,8 @@ impl Type { false } Self::Subr(subr) => subr.contains_tvar(name), + // TODO: preds + Self::Refinement(refine) => refine.t.contains_tvar(name), _ => false, } } @@ -1761,13 +1656,13 @@ impl Type { pub fn args_ownership(&self) -> ArgsOwnership { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().args_ownership(), + Self::Refinement(refine) => refine.t.args_ownership(), Self::Subr(subr) => { - let self_ = subr.kind.self_t().map(|t| t.ownership()); let mut nd_args = vec![]; for nd_param in subr.non_default_params.iter() { let ownership = match nd_param.typ() { Self::Ref(_) => Ownership::Ref, - Self::RefMut(_) => Ownership::RefMut, + Self::RefMut { .. } => Ownership::RefMut, _ => Ownership::Owned, }; nd_args.push(ownership); @@ -1777,12 +1672,12 @@ impl Type { for d_param in subr.default_params.iter() { let ownership = match d_param.typ() { Self::Ref(_) => Ownership::Ref, - Self::RefMut(_) => Ownership::RefMut, + Self::RefMut { .. } => Ownership::RefMut, _ => Ownership::Owned, }; d_args.push((d_param.name().unwrap().clone(), ownership)); } - ArgsOwnership::new(self_, nd_args, var_args, d_args) + ArgsOwnership::new(nd_args, var_args, d_args) } _ => todo!(), } @@ -1791,30 +1686,13 @@ impl Type { pub fn ownership(&self) -> Ownership { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().ownership(), + Self::Refinement(refine) => refine.t.ownership(), Self::Ref(_) => Ownership::Ref, - Self::RefMut(_) => Ownership::RefMut, + Self::RefMut { .. } => Ownership::RefMut, _ => Ownership::Owned, } } - /// 共通部分(A and B)を返す - /// 型同士の包含関係はここでは検査しない(TypeCheckerでする) - pub fn intersection(lhs: &Self, rhs: &Self) -> Self { - if lhs == rhs { - return lhs.clone(); - } - match (lhs, rhs) { - (Self::FreeVar(_), _) | (_, Self::FreeVar(_)) => { - todo!() - } - // { .i: Int } and { .s: Str } == { .i: Int, .s: Str } - (Self::Record(l), Self::Record(r)) => Self::Record(l.clone().concat(r.clone())), - (t, Self::Obj) | (Self::Obj, t) => t.clone(), - (_, Self::Never) | (Self::Never, _) => Self::Never, - (l, r) => and(l.clone(), r.clone()), - } - } - pub fn name(&self) -> Str { match self { Self::Obj => Str::ever("Obj"), @@ -1826,8 +1704,8 @@ impl Type { Self::Str => Str::ever("Str"), Self::NoneType => Str::ever("NoneType"), Self::Type => Str::ever("Type"), - Self::Class => Str::ever("Class"), - Self::Trait => Str::ever("Trait"), + Self::Class => Str::ever("ClassType"), + Self::Trait => Str::ever("TraitType"), Self::Patch => Str::ever("Patch"), Self::Code => Str::ever("Code"), Self::Module => Str::ever("Module"), @@ -1835,12 +1713,12 @@ impl Type { Self::Error => Str::ever("Error"), Self::Inf => Str::ever("Inf"), Self::NegInf => Str::ever("NegInf"), - Self::MonoClass(name) | Self::MonoTrait(name) | Self::MonoQVar(name) => name.clone(), + Self::Mono(name) | Self::MonoQVar(name) => name.clone(), Self::And(_, _) => Str::ever("And"), Self::Not(_, _) => Str::ever("Not"), Self::Or(_, _) => Str::ever("Or"), Self::Ref(_) => Str::ever("Ref"), - Self::RefMut(_) => Str::ever("RefMut"), + Self::RefMut { .. } => Str::ever("RefMut"), Self::Subr(SubrType { kind: SubrKind::Func, .. @@ -1849,19 +1727,9 @@ impl Type { kind: SubrKind::Proc, .. }) => Str::ever("Proc"), - Self::Subr(SubrType { - kind: SubrKind::FuncMethod(_), - .. - }) => Str::ever("FuncMethod"), - Self::Subr(SubrType { - kind: SubrKind::ProcMethod { .. }, - .. - }) => Str::ever("ProcMethod"), Self::Callable { .. } => Str::ever("Callable"), Self::Record(_) => Str::ever("Record"), - Self::PolyClass { name, .. } - | Self::PolyTrait { name, .. } - | Self::PolyQVar { name, .. } => name.clone(), + Self::Poly { name, .. } | Self::PolyQVar { name, .. } => name.clone(), // NOTE: compiler/codegen/convert_to_python_methodでクラス名を使うため、こうすると都合が良い Self::Refinement(refine) => refine.t.name(), Self::Quantified(_) => Str::ever("Quantified"), @@ -1879,6 +1747,14 @@ impl Type { } } + /// assert!((A and B).contains_intersec(B)) + pub fn contains_intersec(&self, typ: &Type) -> bool { + match self { + Type::And(t1, t2) => t1.contains_intersec(typ) || t2.contains_intersec(typ), + _ => self == typ, + } + } + pub fn tvar_name(&self) -> Option { match self { Self::FreeVar(fv) => fv.unbound_name(), @@ -1902,7 +1778,7 @@ impl Type { matches!(self, Self::Subr { .. } | Self::Callable { .. }) } - pub fn is_tyvar(&self) -> bool { + pub fn is_unbound_var(&self) -> bool { matches!(self, Self::FreeVar(fv) if fv.is_unbound()) } @@ -1916,7 +1792,10 @@ impl Type { fv.crack().has_qvar() } } - Self::Ref(t) | Self::RefMut(t) => t.has_qvar(), + Self::Ref(t) => t.has_qvar(), + Self::RefMut { before, after } => { + before.has_qvar() || after.as_ref().map(|t| t.has_qvar()).unwrap_or(false) + } Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => { lhs.has_qvar() || rhs.has_qvar() } @@ -1932,9 +1811,7 @@ impl Type { quant.unbound_callable.has_unbound_var() || quant.bounds.iter().any(|tb| tb.has_qvar()) } - Self::PolyClass { params, .. } | Self::PolyTrait { params, .. } => { - params.iter().any(|tp| tp.has_qvar()) - } + Self::Poly { params, .. } => params.iter().any(|tp| tp.has_qvar()), Self::MonoProj { lhs, .. } => lhs.has_qvar(), _ => false, } @@ -1943,7 +1820,10 @@ impl Type { pub fn is_cachable(&self) -> bool { match self { Self::FreeVar(_) => false, - Self::Ref(t) | Self::RefMut(t) => t.is_cachable(), + Self::Ref(t) => t.is_cachable(), + Self::RefMut { before, after } => { + before.is_cachable() && after.as_ref().map(|t| t.is_cachable()).unwrap_or(true) + } Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => { lhs.is_cachable() && rhs.is_cachable() } @@ -1951,15 +1831,13 @@ impl Type { param_ts.iter().all(|t| t.is_cachable()) && return_t.is_cachable() } Self::Subr(subr) => { - subr.kind.is_cachable() - && subr - .non_default_params - .iter() - .all(|pt| pt.typ().has_unbound_var()) + subr.non_default_params + .iter() + .all(|pt| pt.typ().is_cachable()) && subr .var_params .as_ref() - .map(|pt| pt.typ().has_unbound_var()) + .map(|pt| pt.typ().is_cachable()) .unwrap_or(false) && subr.default_params.iter().all(|pt| pt.typ().is_cachable()) && subr.return_t.is_cachable() @@ -1971,9 +1849,9 @@ impl Type { Self::Quantified(quant) => { quant.unbound_callable.is_cachable() || quant.bounds.iter().all(|b| b.is_cachable()) } - Self::PolyClass { params, .. } - | Self::PolyTrait { params, .. } - | Self::PolyQVar { params, .. } => params.iter().all(|p| p.is_cachable()), + Self::Poly { params, .. } | Self::PolyQVar { params, .. } => { + params.iter().all(|p| p.is_cachable()) + } Self::MonoProj { lhs, .. } => lhs.is_cachable(), _ => true, } @@ -1988,7 +1866,11 @@ impl Type { fv.crack().has_unbound_var() } } - Self::Ref(t) | Self::RefMut(t) => t.has_unbound_var(), + Self::Ref(t) => t.has_unbound_var(), + Self::RefMut { before, after } => { + before.has_unbound_var() + || after.as_ref().map(|t| t.has_unbound_var()).unwrap_or(false) + } Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => { lhs.has_unbound_var() || rhs.has_unbound_var() } @@ -1996,11 +1878,9 @@ impl Type { param_ts.iter().any(|t| t.has_unbound_var()) || return_t.has_unbound_var() } Self::Subr(subr) => { - subr.kind.has_unbound_var() - || subr - .non_default_params - .iter() - .any(|pt| pt.typ().has_unbound_var()) + subr.non_default_params + .iter() + .any(|pt| pt.typ().has_unbound_var()) || subr .var_params .as_ref() @@ -2020,9 +1900,9 @@ impl Type { quant.unbound_callable.has_unbound_var() || quant.bounds.iter().any(|b| b.has_unbound_var()) } - Self::PolyClass { params, .. } - | Self::PolyTrait { params, .. } - | Self::PolyQVar { params, .. } => params.iter().any(|p| p.has_unbound_var()), + Self::Poly { params, .. } | Self::PolyQVar { params, .. } => { + params.iter().any(|p| p.has_unbound_var()) + } Self::MonoProj { lhs, .. } => lhs.has_no_unbound_var(), _ => false, } @@ -2035,20 +1915,18 @@ impl Type { pub fn typarams_len(&self) -> Option { match self { Self::FreeVar(fv) if fv.is_linked() => fv.crack().typarams_len(), + Self::Refinement(refine) => refine.t.typarams_len(), // REVIEW: - Self::Ref(_) | Self::RefMut(_) => Some(1), + Self::Ref(_) | Self::RefMut { .. } => Some(1), Self::And(_, _) | Self::Or(_, _) | Self::Not(_, _) => Some(2), Self::Subr(subr) => Some( - subr.kind.inner_len() - + subr.non_default_params.len() + subr.non_default_params.len() + subr.var_params.as_ref().map(|_| 1).unwrap_or(0) + subr.default_params.len() + 1, ), Self::Callable { param_ts, .. } => Some(param_ts.len() + 1), - Self::PolyClass { params, .. } - | Self::PolyTrait { params, .. } - | Self::PolyQVar { params, .. } => Some(params.len()), + Self::Poly { params, .. } | Self::PolyQVar { params, .. } => Some(params.len()), _ => None, } } @@ -2057,15 +1935,14 @@ impl Type { match self { Self::FreeVar(f) if f.is_linked() => f.crack().typarams(), Self::FreeVar(_unbound) => vec![], - Self::Ref(t) | Self::RefMut(t) => vec![TyParam::t(*t.clone())], + Self::Refinement(refine) => refine.t.typarams(), + Self::Ref(t) | Self::RefMut { before: t, .. } => vec![TyParam::t(*t.clone())], Self::And(lhs, rhs) | Self::Not(lhs, rhs) | Self::Or(lhs, rhs) => { vec![TyParam::t(*lhs.clone()), TyParam::t(*rhs.clone())] } Self::Subr(subr) => subr.typarams(), Self::Callable { param_ts: _, .. } => todo!(), - Self::PolyClass { params, .. } - | Self::PolyTrait { params, .. } - | Self::PolyQVar { params, .. } => params.clone(), + Self::Poly { params, .. } | Self::PolyQVar { params, .. } => params.clone(), _ => vec![], } } @@ -2073,10 +1950,8 @@ impl Type { pub fn self_t(&self) -> Option<&Type> { match self { Self::FreeVar(fv) if fv.is_linked() => todo!("linked: {fv}"), - Self::Subr(SubrType { - kind: SubrKind::FuncMethod(self_t) | SubrKind::ProcMethod { before: self_t, .. }, - .. - }) => Some(self_t), + Self::Refinement(refine) => refine.t.self_t(), + Self::Subr(subr) => subr.self_t(), _ => None, } } @@ -2084,6 +1959,7 @@ impl Type { pub const fn non_default_params(&self) -> Option<&Vec> { match self { Self::FreeVar(_) => panic!("fv"), + Self::Refinement(refine) => refine.t.non_default_params(), Self::Subr(SubrType { non_default_params, .. }) => Some(non_default_params), @@ -2095,6 +1971,7 @@ impl Type { pub const fn var_args(&self) -> Option<&Box> { match self { Self::FreeVar(_) => panic!("fv"), + Self::Refinement(refine) => refine.t.var_args(), Self::Subr(SubrType { var_params: var_args, .. @@ -2107,6 +1984,7 @@ impl Type { pub const fn default_params(&self) -> Option<&Vec> { match self { Self::FreeVar(_) => panic!("fv"), + Self::Refinement(refine) => refine.t.default_params(), Self::Subr(SubrType { default_params, .. }) => Some(default_params), _ => None, } @@ -2115,6 +1993,7 @@ impl Type { pub const fn return_t(&self) -> Option<&Type> { match self { Self::FreeVar(_) => panic!("fv"), + Self::Refinement(refine) => refine.t.return_t(), Self::Subr(SubrType { return_t, .. }) | Self::Callable { return_t, .. } => { Some(return_t) } @@ -2125,6 +2004,7 @@ impl Type { pub fn mut_return_t(&mut self) -> Option<&mut Type> { match self { Self::FreeVar(_) => panic!("fv"), + Self::Refinement(refine) => refine.t.mut_return_t(), Self::Subr(SubrType { return_t, .. }) | Self::Callable { return_t, .. } => { Some(return_t) } @@ -2184,7 +2064,7 @@ impl From<&Type> for TypeCode { Type::Float => Self::Float64, Type::Bool => Self::Bool, Type::Str => Self::Str, - Type::MonoClass(name) => match &name[..] { + Type::Mono(name) => match &name[..] { "Int!" => Self::Int32, "Nat!" => Self::Nat64, "Float!" => Self::Float64, @@ -2192,7 +2072,7 @@ impl From<&Type> for TypeCode { "Str!" => Self::Str, _ => Self::Other, }, - Type::PolyClass { name, .. } => match &name[..] { + Type::Poly { name, .. } => match &name[..] { "Array" | "Array!" => Self::Array, "Func" => Self::Func, "Proc" => Self::Proc, @@ -2361,98 +2241,98 @@ impl TypePair { (Type::Int, Type::Float) => Self::IntFloat, (Type::Int, Type::Str) => Self::IntStr, (Type::Int, Type::Bool) => Self::IntBool, - (Type::Int, Type::PolyClass { name, .. }) if &name[..] == "Array" => Self::IntArray, - (Type::Int, Type::PolyClass { name, .. }) if &name[..] == "Func" => Self::IntFunc, - (Type::Int, Type::PolyClass { name, .. }) if &name[..] == "Proc" => Self::IntProc, + (Type::Int, Type::Poly { name, .. }) if &name[..] == "Array" => Self::IntArray, + (Type::Int, Type::Poly { name, .. }) if &name[..] == "Func" => Self::IntFunc, + (Type::Int, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::IntProc, (Type::Nat, Type::Int) => Self::NatInt, (Type::Nat, Type::Nat) => Self::NatNat, (Type::Nat, Type::Float) => Self::NatFloat, (Type::Nat, Type::Str) => Self::NatStr, (Type::Nat, Type::Bool) => Self::NatBool, - (Type::Nat, Type::PolyClass { name, .. }) if &name[..] == "Array" => Self::NatArray, - (Type::Nat, Type::PolyClass { name, .. }) if &name[..] == "Func" => Self::NatFunc, - (Type::Nat, Type::PolyClass { name, .. }) if &name[..] == "Proc" => Self::NatProc, + (Type::Nat, Type::Poly { name, .. }) if &name[..] == "Array" => Self::NatArray, + (Type::Nat, Type::Poly { name, .. }) if &name[..] == "Func" => Self::NatFunc, + (Type::Nat, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::NatProc, (Type::Float, Type::Int) => Self::FloatInt, (Type::Float, Type::Nat) => Self::FloatNat, (Type::Float, Type::Float) => Self::FloatFloat, (Type::Float, Type::Str) => Self::FloatStr, (Type::Float, Type::Bool) => Self::FloatBool, - (Type::Float, Type::PolyClass { name, .. }) if &name[..] == "Array" => Self::FloatArray, - (Type::Float, Type::PolyClass { name, .. }) if &name[..] == "Func" => Self::FloatFunc, - (Type::Float, Type::PolyClass { name, .. }) if &name[..] == "Proc" => Self::FloatProc, + (Type::Float, Type::Poly { name, .. }) if &name[..] == "Array" => Self::FloatArray, + (Type::Float, Type::Poly { name, .. }) if &name[..] == "Func" => Self::FloatFunc, + (Type::Float, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::FloatProc, (Type::Bool, Type::Int) => Self::BoolInt, (Type::Bool, Type::Nat) => Self::BoolNat, (Type::Bool, Type::Float) => Self::BoolFloat, (Type::Bool, Type::Str) => Self::BoolStr, (Type::Bool, Type::Bool) => Self::BoolBool, - (Type::Bool, Type::PolyClass { name, .. }) if &name[..] == "Array" => Self::BoolArray, - (Type::Bool, Type::PolyClass { name, .. }) if &name[..] == "Func" => Self::BoolFunc, - (Type::Bool, Type::PolyClass { name, .. }) if &name[..] == "Proc" => Self::BoolProc, + (Type::Bool, Type::Poly { name, .. }) if &name[..] == "Array" => Self::BoolArray, + (Type::Bool, Type::Poly { name, .. }) if &name[..] == "Func" => Self::BoolFunc, + (Type::Bool, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::BoolProc, (Type::Str, Type::Int) => Self::StrInt, (Type::Str, Type::Nat) => Self::StrNat, (Type::Str, Type::Float) => Self::StrFloat, (Type::Str, Type::Bool) => Self::StrBool, (Type::Str, Type::Str) => Self::StrStr, - (Type::Str, Type::PolyClass { name, .. }) if &name[..] == "Array" => Self::StrArray, - (Type::Str, Type::PolyClass { name, .. }) if &name[..] == "Func" => Self::StrFunc, - (Type::Str, Type::PolyClass { name, .. }) if &name[..] == "Proc" => Self::StrProc, + (Type::Str, Type::Poly { name, .. }) if &name[..] == "Array" => Self::StrArray, + (Type::Str, Type::Poly { name, .. }) if &name[..] == "Func" => Self::StrFunc, + (Type::Str, Type::Poly { name, .. }) if &name[..] == "Proc" => Self::StrProc, // 要素数は検査済みなので、気にする必要はない - (Type::PolyClass { name, .. }, Type::Int) if &name[..] == "Array" => Self::ArrayInt, - (Type::PolyClass { name, .. }, Type::Nat) if &name[..] == "Array" => Self::ArrayNat, - (Type::PolyClass { name, .. }, Type::Float) if &name[..] == "Array" => Self::ArrayFloat, - (Type::PolyClass { name, .. }, Type::Str) if &name[..] == "Array" => Self::ArrayStr, - (Type::PolyClass { name, .. }, Type::Bool) if &name[..] == "Array" => Self::ArrayBool, - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name, .. }, Type::Int) if &name[..] == "Array" => Self::ArrayInt, + (Type::Poly { name, .. }, Type::Nat) if &name[..] == "Array" => Self::ArrayNat, + (Type::Poly { name, .. }, Type::Float) if &name[..] == "Array" => Self::ArrayFloat, + (Type::Poly { name, .. }, Type::Str) if &name[..] == "Array" => Self::ArrayStr, + (Type::Poly { name, .. }, Type::Bool) if &name[..] == "Array" => Self::ArrayBool, + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Array" && &rn[..] == "Array" => { Self::ArrayArray } - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Array" && &rn[..] == "Func" => { Self::ArrayFunc } - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Array" && &rn[..] == "Proc" => { Self::ArrayProc } - (Type::PolyClass { name, .. }, Type::Int) if &name[..] == "Func" => Self::FuncInt, - (Type::PolyClass { name, .. }, Type::Nat) if &name[..] == "Func" => Self::FuncNat, - (Type::PolyClass { name, .. }, Type::Float) if &name[..] == "Func" => Self::FuncFloat, - (Type::PolyClass { name, .. }, Type::Str) if &name[..] == "Func" => Self::FuncStr, - (Type::PolyClass { name, .. }, Type::Bool) if &name[..] == "Func" => Self::FuncBool, - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name, .. }, Type::Int) if &name[..] == "Func" => Self::FuncInt, + (Type::Poly { name, .. }, Type::Nat) if &name[..] == "Func" => Self::FuncNat, + (Type::Poly { name, .. }, Type::Float) if &name[..] == "Func" => Self::FuncFloat, + (Type::Poly { name, .. }, Type::Str) if &name[..] == "Func" => Self::FuncStr, + (Type::Poly { name, .. }, Type::Bool) if &name[..] == "Func" => Self::FuncBool, + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Func" && &rn[..] == "Array" => { Self::FuncArray } - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Func" && &rn[..] == "Func" => { Self::FuncFunc } - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Func" && &rn[..] == "Proc" => { Self::FuncProc } - (Type::PolyClass { name, .. }, Type::Int) if &name[..] == "Proc" => Self::ProcInt, - (Type::PolyClass { name, .. }, Type::Nat) if &name[..] == "Proc" => Self::ProcNat, - (Type::PolyClass { name, .. }, Type::Float) if &name[..] == "Proc" => Self::ProcFloat, - (Type::PolyClass { name, .. }, Type::Str) if &name[..] == "Proc" => Self::ProcStr, - (Type::PolyClass { name, .. }, Type::Bool) if &name[..] == "Proc" => Self::ProcBool, - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name, .. }, Type::Int) if &name[..] == "Proc" => Self::ProcInt, + (Type::Poly { name, .. }, Type::Nat) if &name[..] == "Proc" => Self::ProcNat, + (Type::Poly { name, .. }, Type::Float) if &name[..] == "Proc" => Self::ProcFloat, + (Type::Poly { name, .. }, Type::Str) if &name[..] == "Proc" => Self::ProcStr, + (Type::Poly { name, .. }, Type::Bool) if &name[..] == "Proc" => Self::ProcBool, + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Proc" && &rn[..] == "Array" => { Self::ProcArray } - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Proc" && &rn[..] == "Func" => { Self::ProcFunc } - (Type::PolyClass { name: ln, .. }, Type::PolyClass { name: rn, .. }) + (Type::Poly { name: ln, .. }, Type::Poly { name: rn, .. }) if &ln[..] == "Proc" && &rn[..] == "Proc" => { Self::ProcProc diff --git a/compiler/erg_type/typaram.rs b/compiler/erg_type/typaram.rs index f84ef708..a4a037e2 100644 --- a/compiler/erg_type/typaram.rs +++ b/compiler/erg_type/typaram.rs @@ -448,12 +448,12 @@ impl TyParam { } pub fn free_var(level: usize, t: Type) -> Self { - let constraint = Constraint::type_of(t); + let constraint = Constraint::new_type_of(t); Self::FreeVar(FreeTyParam::new_unbound(level, constraint)) } pub fn named_free_var(name: Str, level: usize, t: Type) -> Self { - let constraint = Constraint::type_of(t); + let constraint = Constraint::new_type_of(t); Self::FreeVar(FreeTyParam::new_named_unbound(name, level, constraint)) } diff --git a/compiler/erg_type/value.rs b/compiler/erg_type/value.rs index e9e0720c..704e0a29 100644 --- a/compiler/erg_type/value.rs +++ b/compiler/erg_type/value.rs @@ -17,11 +17,92 @@ use erg_common::{fmt_iter, impl_display_from_debug, switch_lang}; use erg_common::{RcArray, Str}; use crate::codeobj::CodeObj; -use crate::constructors::{array, class, poly_class, refinement, tuple}; +use crate::constructors::{array, mono, poly, refinement, tuple}; use crate::free::fresh_varname; use crate::typaram::TyParam; use crate::{ConstSubr, HasType, Predicate, Type}; +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum TypeKind { + Class, + Subclass, + Trait, + Subtrait, + StructuralTrait, +} + +/// Class +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct GenTypeObj { + pub kind: TypeKind, + pub t: Type, // andやorが入る可能性あり + pub require_or_sup: Box, + pub impls: Option>, + pub additional: Option>, +} + +impl fmt::Display for GenTypeObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "<{:?} {}>", self.kind, self.t) + } +} + +impl GenTypeObj { + pub fn new( + kind: TypeKind, + t: Type, + require_or_sup: TypeObj, + impls: Option, + additional: Option, + ) -> Self { + Self { + kind, + t, + require_or_sup: Box::new(require_or_sup), + impls: impls.map(Box::new), + additional: additional.map(Box::new), + } + } + + pub fn meta_type(&self) -> Type { + match self.kind { + TypeKind::Class | TypeKind::Subclass => Type::Class, + TypeKind::Trait | TypeKind::Subtrait | TypeKind::StructuralTrait => Type::Trait, + } + } +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum TypeObj { + Builtin(Type), + Generated(GenTypeObj), +} + +impl fmt::Display for TypeObj { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + TypeObj::Builtin(t) => write!(f, "{t}"), + TypeObj::Generated(t) => write!(f, "{t}"), + } + } +} + +impl TypeObj { + pub const fn typ(&self) -> &Type { + match self { + TypeObj::Builtin(t) => t, + TypeObj::Generated(t) => &t.t, + } + } + + pub fn contains_intersec(&self, other: &Type) -> bool { + match self { + TypeObj::Builtin(t) => t.contains_intersec(other), + TypeObj::Generated(t) => t.t.contains_intersec(other), + } + } +} + /// 値オブジェクト /// コンパイル時評価ができ、シリアライズも可能 #[derive(Clone, PartialEq, Default)] @@ -37,7 +118,7 @@ pub enum ValueObj { Record(Dict), Code(Box), Subr(ConstSubr), - Type(Box), + Type(TypeObj), None, Ellipsis, NotImplemented, @@ -92,7 +173,7 @@ impl fmt::Debug for ValueObj { } write!(f, "}}") } - Self::Subr(subr) => write!(f, "{subr:?}"), + Self::Subr(subr) => write!(f, "{subr}"), Self::Type(t) => write!(f, "{t}"), Self::None => write!(f, "None"), Self::Ellipsis => write!(f, "Ellipsis"), @@ -262,8 +343,24 @@ impl HasType for ValueObj { } impl ValueObj { - pub fn t(t: Type) -> Self { - ValueObj::Type(Box::new(t)) + pub fn builtin_t(t: Type) -> Self { + ValueObj::Type(TypeObj::Builtin(t)) + } + + pub fn gen_t( + kind: TypeKind, + t: Type, + require_or_sup: TypeObj, + impls: Option, + additional: Option, + ) -> Self { + ValueObj::Type(TypeObj::Generated(GenTypeObj::new( + kind, + t, + require_or_sup, + impls, + additional, + ))) } pub fn is_num(&self) -> bool { @@ -274,6 +371,10 @@ impl ValueObj { } } + pub const fn is_type(&self) -> bool { + matches!(self, Self::Type(_)) + } + pub const fn is_mut(&self) -> bool { matches!(self, Self::Mut(_)) } @@ -376,20 +477,24 @@ impl ValueObj { Self::Record(rec) => { Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect()) } - Self::Subr(_) => todo!(), - Self::Type(_) => Type::Type, + Self::Subr(subr) => subr.class(), + Self::Type(t_obj) => match t_obj { + // TODO: builtin + TypeObj::Builtin(_t) => Type::Type, + TypeObj::Generated(gen_t) => gen_t.meta_type(), + }, Self::None => Type::NoneType, Self::Ellipsis => Type::Ellipsis, Self::NotImplemented => Type::NotImplemented, Self::Inf => Type::Inf, Self::NegInf => Type::NegInf, Self::Mut(m) => match &*m.borrow() { - Self::Int(_) => class("Int!"), - Self::Nat(_) => class("Nat!"), - Self::Float(_) => class("Float!"), - Self::Str(_) => class("Str!"), - Self::Bool(_) => class("Bool!"), - Self::Array(arr) => poly_class( + Self::Int(_) => mono("Int!"), + Self::Nat(_) => mono("Nat!"), + Self::Float(_) => mono("Float!"), + Self::Str(_) => mono("Str!"), + Self::Bool(_) => mono("Bool!"), + Self::Array(arr) => poly( "Array!", vec![ TyParam::t(arr.iter().next().unwrap().class()), @@ -641,6 +746,26 @@ impl ValueObj { _ => None, } } + + pub fn try_get_attr(&self, attr: &Field) -> Option { + match self { + Self::Type(typ) => match typ { + TypeObj::Builtin(builtin) => todo!("{builtin}{attr}"), + TypeObj::Generated(gen) => match &gen.t { + Type::Record(rec) => { + let t = rec.get(attr)?; + Some(ValueObj::builtin_t(t.clone())) + } + _ => None, + }, + }, + Self::Record(rec) => { + let v = rec.get(attr)?; + Some(v.clone()) + } + _ => None, + } + } } pub mod value_set { diff --git a/doc/EN/faq_general.md b/doc/EN/faq_general.md index 331212e5..8f371ab4 100644 --- a/doc/EN/faq_general.md +++ b/doc/EN/faq_general.md @@ -15,10 +15,10 @@ A: Erg code is transpiled into Python bytecode. That is, it runs on the same int We have been influenced by more languages than we can count on both hands, but Python, Rust, Nim, and Haskell have been the strongest influences. We inherited many semantics from Python, expression-oriented and trait from Rust, procedures from Nim, and functional programming-related features from Haskell. -## Languages that can call Python include Julia. Why did you create Erg? +## There are already languages that can call Python, such as Julia. Why did you create Erg? -A: One of the motivations for Erg's design was to have a language that is easy to use, yet has a powerful type system. That is, a language with type inference, Kind, dependent types, etc. -Julia can be typed, but it is really a dynamically typed language and does not have the compile-time error detection benefits of statically typed languages. +A: One of the motivations for Erg's design was to have a language that is easy to use, yet has a powerful type system. That is a language with type inference, dependent types, etc. +Julia can be typed, but it is really a dynamically typed language and does not have the advantage of perfect compile-time type error detection like statically typed languages. ## Erg supports multiple styles of programming, including functional and object-oriented programming. Isn't this contrary to Python's "There should be one --and preferably only one-- obvious way to do it."? diff --git a/doc/EN/syntax/type/04_class.md b/doc/EN/syntax/type/04_class.md index b345aa65..f1c673c5 100644 --- a/doc/EN/syntax/type/04_class.md +++ b/doc/EN/syntax/type/04_class.md @@ -227,9 +227,9 @@ print! {i = 1}.bar # C.new({i = 1}).bar # ``` -## Difference from data class +## Difference from Data Class -There are two types of classes: regular classes, which are record classes through `Class`, and data classes, which inherit (`Inherit`) from record classes. +There are two types of classes: regular classes, which are generated with `Class(record)`, and data classes, which are generated with `Inherit(record)`. The data class inherits the functionality of the record class and has features such as decomposition assignment, `==` and `hash` implemented by default, etc. On the other hand, the data class has its own equivalence relation and format display. On the other hand, if you want to define your own equivalence relations or formatting displays, you should use the normal class. @@ -241,9 +241,9 @@ print! c # c == d # TypeError: `==` is not implemented for `C` D = Inherit {i = Int} -e = D.new {i = 1} -f = D.new {i = 2} -print! e # D{i = 1} +e = D::{i = 1} # same as `e = D.new {i = 1}` +f = D::{i = 2} +print! e # D(i=1) assert e ! = f ``` diff --git a/doc/JA/faq_general.md b/doc/JA/faq_general.md index f950b405..c86fcc92 100644 --- a/doc/JA/faq_general.md +++ b/doc/JA/faq_general.md @@ -1,6 +1,6 @@ # Erg FAQ -[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/faq_general.md%26commit_hash%3Deccd113c1512076c367fb87ea73406f91ff83ba7)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=eccd113c1512076c367fb87ea73406f91ff83ba7) +[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/faq_general.md%26commit_hash%3D521426cba21ed8b6eae5aff965dd14ef99af1228)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228) このFAQは一般のErg入門者向けです。 個別の(よくある)技術的な問題については[こちら](./faq_technical.md)を、文法の決定経緯(なぜこのような文法になったのか)などについては diff --git a/doc/zh_CN/faq_general.md b/doc/zh_CN/faq_general.md index a7d61bbd..c71b17c9 100644 --- a/doc/zh_CN/faq_general.md +++ b/doc/zh_CN/faq_general.md @@ -1,6 +1,6 @@ # Erg常见问题 -[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/faq_general.md%26commit_hash%3Deccd113c1512076c367fb87ea73406f91ff83ba7)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=eccd113c1512076c367fb87ea73406f91ff83ba7) +[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/faq_general.md%26commit_hash%3D521426cba21ed8b6eae5aff965dd14ef99af1228)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228) 此常见问题解答适用于一般 Erg 初学者。 对于个别(常见)技术问题,请参阅 [此处](./faq_technical.md) 了解个别(常见)技术问题,以及 @@ -17,7 +17,7 @@ A: Erg 代码被转译成 Python 字节码。也就是说,它运行在与 Pyth 我们受到的语言多于我们双手所能指望的数量,但 Python、Rust、Nim 和 Haskell 的影响最大。 我们从 Python 继承了许多语义,从 Rust 继承了面向表达式和 trait,从 Nim 继承了过程,从 Haskell 继承了函数式编程相关的特性。 -## 可以调用 Python 的语言包括 Julia。你为什么创建 Erg? +## 已经有一些语言可以调用Python,比如Julia。为什么要创建Erg? 答:Erg 设计的动机之一是拥有一种易于使用且具有强大类型系统的语言。即具有类型推断、Kind、依赖类型等的语言。 Julia 是可以有类型的,但它确实是一种动态类型语言,不具备静态类型语言的编译时错误检测优势。 diff --git a/doc/zh_TW/faq_general.md b/doc/zh_TW/faq_general.md index 2aa5d5cf..77a21dc2 100644 --- a/doc/zh_TW/faq_general.md +++ b/doc/zh_TW/faq_general.md @@ -1,6 +1,6 @@ # Erg常見問題 -[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/faq_general.md%26commit_hash%3Deccd113c1512076c367fb87ea73406f91ff83ba7)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=eccd113c1512076c367fb87ea73406f91ff83ba7) +[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/faq_general.md%26commit_hash%3D521426cba21ed8b6eae5aff965dd14ef99af1228)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228) 此常見問題解答適用於一般 Erg 初學者。 對於個別(常見)技術問題,請參閱 [此處](./faq_technical.md) 了解個別(常見)技術問題,以及 @@ -17,7 +17,7 @@ A: Erg 代碼被轉譯成 Python 字節碼。也就是說,它運行在與 Pyth 我們受到的語言多于我們雙手所能指望的數量,但 Python、Rust、Nim 和 Haskell 的影響最大。 我們從 Python 繼承了許多語義,從 Rust 繼承了面向表達式和 trait,從 Nim 繼承了過程,從 Haskell 繼承了函數式編程相關的特性。 -## 可以調用 Python 的語言包括 Julia。你為什么創建 Erg? +## 已經有一些語言可以調用Python,比如Julia。為什麼要創建Erg? 答:Erg 設計的動機之一是擁有一種易于使用且具有強大類型系統的語言。即具有類型推斷、Kind、依賴類型等的語言。 Julia 是可以有類型的,但它確實是一種動態類型語言,不具備靜態類型語言的編譯時錯誤檢測優勢。 diff --git a/examples/add.er b/examples/add.er index 3ccac7bf..b0cc46b9 100644 --- a/examples/add.er +++ b/examples/add.er @@ -1,7 +1,7 @@ Point = Class {x = Int; y = Int}, Impl := Add() and Eq() Point. new x, y = Self::__new__ {x; y} - norm &self = self::x**2 + self::y**2 + norm self = self::x**2 + self::y**2 @Impl Add() `+` self, other = Self.new(self::x + other::x, self::y + other::y) diff --git a/examples/class.er b/examples/class.er index 709c5886..49081aeb 100644 --- a/examples/class.er +++ b/examples/class.er @@ -1,17 +1,25 @@ +# Inheritance is prohibited by default. Remove this decorator and check for errors. @Inheritable Point2D = Class {x = Int; y = Int} +Point2D:: + one = 1 Point2D. - new x, y = Self::__new__ {x = x; y = y} - norm ref self = self::x**2 + self::y**2 + zero = Point2D::one - 1 + norm self = self::x**2 + self::y**2 Point3D = Inherit Point2D, Additional := {z = Int} Point3D. + # Overloading is prohibited by default. Remove this decorator and check for errors. @Override - new x, y, z = Self::__new__ {x = x; y = y; z = z} + new x, y, z = + Point3D::__new__ {x; y; z} @Override - norm ref self = self::x**2 + self::y**2 + self::z**2 + norm self = self::x**2 + self::y**2 + self::z**2 -UnpackPoint2D = Class {x = Int; y = Int}, Impl := Unpack - -p = UnpackPoint2D::{x = 1; y = 2} -UnpackPoint2D::{x = x; y = x} = p +# `Point2D::__new__` is private, use `Point2D.new` instead +p = Point2D.new {x = 1; y = 2} +print! p, p.norm() +print! Point2D.zero +# print! Point2D::one # cannot access private variables +q = Point3D.new 1, 2, 3 +print! q, q.norm() diff --git a/examples/unpack.er b/examples/unpack.er new file mode 100644 index 00000000..b4823e43 --- /dev/null +++ b/examples/unpack.er @@ -0,0 +1,5 @@ +UnpackPoint2D = Class {x = Int; y = Int}, Impl := Unpack + +q = UnpackPoint2D::{x = 1; y = 2} +UnpackPoint2D::{x; y} = q +print! x, y