diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..0aa48f1d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,17 @@ +# Contributing to Erg + +## Documents + +If you are thinking of contributing to Erg, or are interested in the internal structure of Erg, you can take a look at the documents under [doc/dev_guide](./doc/JA/dev_guide/) (currently only Japanese). + +## Bug reports + +If you find any behavior that you think is a bug in Erg, I would appreciate it if you would [report](https://github.com/erg-lang/erg/issues/new/choose) it. Please make sure that the same bug has not already been reported as an issue. + +If you type `cargo run --features debug`, Erg will be built in debug mode. This mode may dump information that may be useful for investigating bugs. I would appreciate it if you could report error logs in this mode. + +Also, the environment in which the bug occurred need not be reported if it is clear that the bug was not caused by the environment. + +## Asking questions + +If you have any questions, please feel free to ask them on the [Discord channel](https://discord.gg/zfAAUbgGr4). diff --git a/Cargo.toml b/Cargo.toml index b123819d..82ff3a2e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg" -version = "0.2.2" +version = "0.2.4" description = "The Erg programming language" authors = ["Shunsuke Shibayama "] license = "MIT OR Apache-2.0" @@ -31,9 +31,9 @@ japanese = [ ] [dependencies] -erg_common = { version = "0.2.2", path = "./compiler/erg_common" } -erg_parser = { version = "0.2.2", path = "./compiler/erg_parser" } -erg_compiler = { version = "0.2.2", path = "./compiler/erg_compiler" } +erg_common = { version = "0.2.4", path = "./compiler/erg_common" } +erg_parser = { version = "0.2.4", path = "./compiler/erg_parser" } +erg_compiler = { version = "0.2.4", path = "./compiler/erg_compiler" } # [workspace] # member = ["cm", "dyne"] diff --git a/README.md b/README.md index f7a74608..7b80be27 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ -
[Erg](https://erg-lang.github.io/) is a statically typed language that is Python compatible. +
[Erg](https://erg-lang.github.io/) is a statically typed language that is Python-compatible.

Build status @@ -14,7 +14,7 @@ ## Erg can be recommended to a person that: -* uses Python, but want Rust-like robustness and comfortable compiler support. +* uses Python, but wants Rust-like robustness and comfortable compiler support. * and yet, doesn't need the verbose type specifications & memory management model like Rust. * wants a simple and consistent language like ML. * wants a practical general-purpose language with dependent/refinement types. @@ -26,7 +26,7 @@ 1. Robustness - Erg has a smart & powerful type system. For example, Erg can do null checking (Option type), division by zero and out-of-range addresses in arrays at compile time. + Erg has a smart & powerful type system. For example, Erg can do null checking (Option type), division by zero, and out-of-range addresses in arrays at compile time. ```python rand = pyimport "random" @@ -102,6 +102,7 @@ # SyntaxError: cannot call a procedural method in a function # hint: only methods of mutable types can change the state of objects + # Code that uses a lot of side effects is redundant, so you will naturally write pure code Counter! = Inherit Int! Counter!. new i: Int = Self!::__new__ !i @@ -146,7 +147,7 @@ 3│ l.push!(x) ^^^^^ AttributeError: Array object has no attribute `.push!` - hint: in order to update the internal state of an object, make it mutable by using `!` operator + hint: to update the internal state of an object, make it mutable by using `!` operator hint: `Array` has `push`, see https://erg-lang.github.io/docs/prelude/Array/##push for more information hint: `Array!` has `push!`, see https://erg-lang.github.io/docs/prelude/Array!/##push! for more information ``` diff --git a/README_JA.md b/README_JA.md index ed8c5da9..f974e7eb 100644 --- a/README_JA.md +++ b/README_JA.md @@ -100,6 +100,7 @@ # SyntaxError: 関数の中でプロシージャルメソッドは呼び出せません # ヒント: 可変型メソッドだけがオブジェクトの状態を変更できます + # 副作用を多用するコードは自然と冗長になるため、自然と純粋なコードを書くように動機づけられます Counter! = Inherit Int! Counter!. new i: Int = Self!::__new__ !i diff --git a/TODO.md b/TODO.md index 2d21e0d8..7012b988 100644 --- a/TODO.md +++ b/TODO.md @@ -55,7 +55,7 @@ * [ ] Mutable type * [x] Dependent mutable method * [x] Projection type - * [ ] Polymorphic projection type + * [ ] Polymorphic projection-type * [x] Subtyping * [x] Refinement subtyping * [x] Nominal subtyping @@ -70,13 +70,13 @@ * [x] procedure call * [ ] mutable type * [x] Implement reference types (for methods) -* [ ] Implement a ownership checker +* [ ] Implement an ownership checker * [x] Implement a move checker * [x] Implement a borrow checker * [ ] Implement a cycle-reference detector -* [ ] Implement a compiletime evaluator +* [ ] Implement a compile-time evaluator * [ ] Compiletime operator - * [ ] Compiletime function + * [ ] Compile-time function * [ ] Maintain unit tests * [ ] Implement a Python parser * [ ] Make code readable diff --git a/assets/erg_logo.png b/assets/erg_logo.png index 882f329e..0fc172c8 100644 Binary files a/assets/erg_logo.png and b/assets/erg_logo.png differ diff --git a/assets/erg_logo.svg b/assets/erg_logo.svg index 810c3ac7..a9cc427d 100644 --- a/assets/erg_logo.svg +++ b/assets/erg_logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/erg_logo_with_slogan.svg b/assets/erg_logo_with_slogan.svg index 2fdbbe76..38353746 100644 --- a/assets/erg_logo_with_slogan.svg +++ b/assets/erg_logo_with_slogan.svg @@ -1 +1,100 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/erg_logo_with_slogan_transparent.png b/assets/erg_logo_with_slogan_transparent.png index f2d725d1..d798bc2b 100644 Binary files a/assets/erg_logo_with_slogan_transparent.png and b/assets/erg_logo_with_slogan_transparent.png differ diff --git a/assets/erg_logo_with_slogan_transparent.svg b/assets/erg_logo_with_slogan_transparent.svg index 99a327ca..6b9d2b19 100644 --- a/assets/erg_logo_with_slogan_transparent.svg +++ b/assets/erg_logo_with_slogan_transparent.svg @@ -1 +1,102 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/cargo_publish.bat b/cargo_publish.bat new file mode 100644 index 00000000..ec2fdd3e --- /dev/null +++ b/cargo_publish.bat @@ -0,0 +1,21 @@ +@echo off + +if %~dp0 == C:%homepath%\GitHub\erg\ ( + cd compiler/erg_common + echo publish erg_common ... + cargo publish + timeout 20 + cd ../erg_parser + echo publish erg_parser ... + cargo publish + timeout 20 + cd ../erg_compiler + echo publish erg_compiler ... + cargo publish + timeout 20 + cd ../../ + cargo publish + echo completed +) else ( + echo Use this command in the project root +) diff --git a/cargo_publish.sh b/cargo_publish.sh new file mode 100644 index 00000000..e69de29b diff --git a/compiler/erg_common/Cargo.toml b/compiler/erg_common/Cargo.toml index 50974286..bec58612 100644 --- a/compiler/erg_common/Cargo.toml +++ b/compiler/erg_common/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_common" -version = "0.2.2" +version = "0.2.4" description = "A common components library of Erg" authors = ["Shunsuke Shibayama "] license = "MIT OR Apache-2.0" diff --git a/compiler/erg_common/codeobj.rs b/compiler/erg_common/codeobj.rs index e5d491db..0632e300 100644 --- a/compiler/erg_common/codeobj.rs +++ b/compiler/erg_common/codeobj.rs @@ -126,9 +126,15 @@ impl HasType for CodeObj { fn ref_t(&self) -> &Type { &Type::Code } + fn ref_mut_t(&mut self) -> &mut Type { + todo!() + } fn signature_t(&self) -> Option<&Type> { None } + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl fmt::Debug for CodeObj { diff --git a/compiler/erg_common/error.rs b/compiler/erg_common/error.rs index 84988a1f..d5cc76bb 100644 --- a/compiler/erg_common/error.rs +++ b/compiler/erg_common/error.rs @@ -317,7 +317,7 @@ impl ErrorCore { } pub fn unreachable(fn_name: &str, line: u32) -> Self { - Self::bug(0, Location::Unknown, fn_name, line) + Self::bug(line as usize, Location::Unknown, fn_name, line) } pub fn bug(errno: usize, loc: Location, fn_name: &str, line: u32) -> Self { diff --git a/compiler/erg_common/traits.rs b/compiler/erg_common/traits.rs index e2dc40e2..37798e09 100644 --- a/compiler/erg_common/traits.rs +++ b/compiler/erg_common/traits.rs @@ -299,14 +299,12 @@ pub trait ImmutableStream: Sized { // for Runnable::run fn expect_block(src: &str) -> bool { src.ends_with(&['=', ':']) - || src.ends_with(":=") || src.ends_with("->") || src.ends_with("=>") - || src.ends_with("do") - || src.ends_with("do!") } -/// this trait implements REPL (Read-Eval-Print-Loop) automatically +/// This trait implements REPL (Read-Eval-Print-Loop) automatically +/// The `exec` method is called for file input, etc. pub trait Runnable: Sized { type Err: ErrorDisplay; type Errs: MultiErrorDisplay; @@ -316,6 +314,7 @@ pub trait Runnable: Sized { fn finish(&mut self); // called when the :exit command is received. fn clear(&mut self); fn eval(&mut self, src: Str) -> Result; + fn exec(&mut self) -> Result<(), Self::Errs>; fn ps1(&self) -> String { ">>> ".to_string() @@ -333,13 +332,7 @@ pub trait Runnable: Sized { let mut instance = Self::new(cfg); let res = match instance.input() { Input::File(_) | Input::Pipe(_) | Input::Str(_) => { - match instance.eval(instance.input().read()) { - Ok(s) => { - println!("{s}"); - Ok(()) - } - Err(e) => Err(e), - } + instance.exec() } Input::REPL => { let output = stdout(); @@ -497,6 +490,9 @@ pub trait HasType { fn ref_t(&self) -> &Type; // 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す fn signature_t(&self) -> Option<&Type>; + // 最後にHIR全体の型変数を消すために使う + fn ref_mut_t(&mut self) -> &mut Type; + fn signature_mut_t(&mut self) -> Option<&mut Type>; #[inline] fn t(&self) -> Type { self.ref_t().clone() diff --git a/compiler/erg_common/tsort.rs b/compiler/erg_common/tsort.rs index bb243df2..9cb7ba7f 100644 --- a/compiler/erg_common/tsort.rs +++ b/compiler/erg_common/tsort.rs @@ -42,30 +42,35 @@ fn reorder_by_key(mut g: Graph, idx: Vec) -> Graph { g } -fn dfs(g: &Graph, v: T, used: &mut Set, idx: &mut Vec) { +fn dfs(g: &Graph, v: T, used: &mut Set, idx: &mut Vec) -> Result<(), ()> { used.insert(v.clone()); for node_id in g.iter().find(|n| n.id == v).unwrap().depends_on.iter() { + // detecting cycles + if used.contains(node_id) && !idx.contains(node_id) { + return Err(()); + } if !used.contains(node_id) { - dfs(g, node_id.clone(), used, idx); + dfs(g, node_id.clone(), used, idx)?; } } idx.push(v); + Ok(()) } /// perform topological sort on a graph -pub fn tsort(g: Graph) -> Graph { +pub fn tsort(g: Graph) -> Result, ()> { let n = g.len(); let mut idx = Vec::with_capacity(n); let mut used = Set::new(); for v in g.iter() { if !used.contains(&v.id) { - dfs(&g, v.id.clone(), &mut used, &mut idx); + dfs(&g, v.id.clone(), &mut used, &mut idx)?; } } - reorder_by_key(g, idx) + Ok(reorder_by_key(g, idx)) } -fn _test() { +fn _test() -> Result<(), ()> { let v = vec!["e", "d", "b", "a", "c"]; let idx = vec![3, 2, 4, 1, 0]; assert_eq!(vec!["a", "b", "c", "d", "e"], _reorder_by_idx(v, idx)); @@ -83,5 +88,6 @@ fn _test() { on_2.clone(), ]; let dag = vec![en_0, o0_1, on_2, e0_3, ond_4]; - assert_eq!(sorted, tsort(dag)); + assert_eq!(sorted, tsort(dag)?); + Ok(()) } diff --git a/compiler/erg_common/ty.rs b/compiler/erg_common/ty.rs index f6e84cb3..015b72eb 100644 --- a/compiler/erg_common/ty.rs +++ b/compiler/erg_common/ty.rs @@ -89,10 +89,15 @@ pub trait HasLevel { // REVIEW: TyBoundと微妙に役割が被っている #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Constraint { + /// :> T SupertypeOf(Type), + /// <: T SubtypeOf(Type), + /// :> Sub, <: Sup Sandwiched { sub: Type, sup: Type }, + /// : T TypeOf(Type), + Uninited, } impl fmt::Display for Constraint { @@ -102,11 +107,20 @@ impl fmt::Display for Constraint { Self::SubtypeOf(sup) => write!(f, "<: {sup}"), Self::Sandwiched { sub, sup } => write!(f, ":> {sub}, <: {sup}"), Self::TypeOf(ty) => write!(f, ": {}", ty), + Self::Uninited => write!(f, ""), } } } impl Constraint { + pub const fn sandwiched(sub: Type, sup: Type) -> Self { + Self::Sandwiched { sub, sup } + } + + pub const fn is_uninited(&self) -> bool { + matches!(self, Self::Uninited) + } + pub fn typ(&self) -> Option<&Type> { match self { Self::TypeOf(ty) => Some(ty), @@ -114,6 +128,13 @@ impl Constraint { } } + pub fn sub_type(&self) -> Option<&Type> { + match self { + Self::SupertypeOf(ty) => Some(ty), + _ => None, + } + } + pub fn super_type(&self) -> Option<&Type> { match self { Self::SubtypeOf(ty) => Some(ty), @@ -269,7 +290,23 @@ impl Free { } } - pub fn unwrap(self) -> T { + pub fn get_name(&self) -> Option { + match self.0.clone_inner() { + FreeKind::Linked(_) => panic!("the value is linked"), + FreeKind::Unbound { .. } => None, + FreeKind::NamedUnbound { name, .. } => Some(name), + } + } + + pub fn unwrap_unbound(self) -> (Option, usize, Constraint) { + match self.0.clone_inner() { + FreeKind::Linked(_) => panic!("the value is linked"), + FreeKind::Unbound { constraint, lev, .. } => (None, lev, constraint), + | FreeKind::NamedUnbound { name, lev, constraint } => (Some(name), lev, constraint), + } + } + + pub fn unwrap_linked(self) -> T { match self.0.clone_inner() { FreeKind::Linked(t) => t, FreeKind::Unbound { .. } | FreeKind::NamedUnbound { .. } => { @@ -289,6 +326,14 @@ impl Free { }) } + pub fn crack_constraint(&self) -> Ref<'_, Constraint> { + Ref::map(self.0.borrow(), |f| match f { + FreeKind::Linked(_) => panic!("the value is linked"), + FreeKind::Unbound { constraint, .. } + | FreeKind::NamedUnbound { constraint, .. } => constraint, + }) + } + pub fn type_of(&self) -> Option { self.0.borrow().constraint().and_then(|c| c.typ().cloned()) } @@ -307,6 +352,30 @@ impl Free { ) } + pub fn constraint_is_typeof(&self) -> bool { + matches!( + &*self.0.borrow(), + FreeKind::Unbound { constraint, .. } + | FreeKind::NamedUnbound { constraint, .. } if constraint.typ().is_some() + ) + } + + pub fn constraint_is_supertypeof(&self) -> bool { + matches!( + &*self.0.borrow(), + FreeKind::Unbound { constraint, .. } + | FreeKind::NamedUnbound { constraint, .. } if constraint.sub_type().is_some() + ) + } + + pub fn constraint_is_subtypeof(&self) -> bool { + matches!( + &*self.0.borrow(), + FreeKind::Unbound { constraint, .. } + | FreeKind::NamedUnbound { constraint, .. } if constraint.super_type().is_some() + ) + } + pub fn is_linked(&self) -> bool { matches!(&*self.0.borrow(), FreeKind::Linked(_)) } @@ -812,6 +881,13 @@ impl TyParam { _ => true, } } + + pub fn update_constraint(&self, new_constraint: Constraint) { + match self { + Self::Type(t) => { t.update_constraint(new_constraint) }, + _ => {} + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -824,6 +900,7 @@ pub enum TyParamOrdering { NotEqual, // Less or Greater GreaterEqual, // Greater or Equal Any, + NoRelation, } use TyParamOrdering::*; @@ -877,7 +954,7 @@ impl TyParamOrdering { GreaterEqual => LessEqual, Equal => NotEqual, NotEqual => Equal, - Any => Any, + Any | NoRelation => Any, } } } @@ -1692,6 +1769,8 @@ pub enum Type { }, // e.g. T.U ASTOmitted, // call中のcalleeの型など、不要な部分に付ける Failure, // when failed to infer + /// used to represent `TyParam` is not initialized (see `erg_compiler::context::instantiate_tp`) + Uninited, } impl fmt::Display for Type { @@ -1802,6 +1881,10 @@ impl HasType for Type { fn ref_t(&self) -> &Type { self } + #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + self + } fn inner_ts(&self) -> Vec { match self { Self::Ref(t) | Self::RefMut(t) | Self::VarArgs(t) => { @@ -1817,6 +1900,9 @@ impl HasType for Type { fn signature_t(&self) -> Option<&Type> { None } + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl HasLevel for Type { @@ -2044,7 +2130,7 @@ impl Type { Self::poly("Iter", vec![TyParam::t(t)]) } - pub fn refer(t: Type) -> Self { + pub fn ref_(t: Type) -> Self { Self::Ref(Box::new(t)) } @@ -2315,6 +2401,14 @@ impl Type { Self::Quantified(QuantifiedType::new(unbound_t, bounds)) } + pub fn is_mono_q(&self) -> bool { + match self { + Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_mono_q(), + Self::MonoQVar(_) => true, + _ => false, + } + } + pub fn mutate(self) -> Self { match self { Self::Int => Self::IntMut, @@ -2403,10 +2497,14 @@ impl Type { pub fn rec_eq(&self, other: &Self) -> bool { match (self, other) { - (Self::FreeVar(v), other) | (other, Self::FreeVar(v)) => match &*v.borrow() { + (Self::FreeVar(v), other) => match &*v.borrow() { FreeKind::Linked(t) => t.rec_eq(other), _ => self == other, }, + (self_, Self::FreeVar(v)) => match &*v.borrow() { + FreeKind::Linked(t) => t.rec_eq(self_), + _ => self_ == other, + }, (Self::Ref(l), Self::Ref(r)) | (Self::RefMut(l), Self::RefMut(r)) => l.rec_eq(r), (Self::Subr(l), Self::Subr(r)) => { match (&l.kind, &r.kind) { @@ -2578,6 +2676,7 @@ impl Type { Self::MonoProj { .. } => "MonoProj", Self::ASTOmitted => "ASTOmitted", Self::Failure => "", + Self::Uninited => "", } } @@ -2662,7 +2761,7 @@ impl Type { pub fn typarams(&self) -> Vec { match self { Self::FreeVar(f) if f.is_linked() => f.crack().typarams(), - Self::FreeVar(_unbound) => todo!(), + Self::FreeVar(_unbound) => vec![], Self::Ref(t) | Self::RefMut(t) => vec![TyParam::t(*t.clone())], Self::And(param_ts) | Self::Or(param_ts) | Self::Not(param_ts) => { param_ts.iter().map(|t| TyParam::t(t.clone())).collect() @@ -2745,6 +2844,13 @@ impl Type { _ => None, } } + + pub fn update_constraint(&self, new_constraint: Constraint) { + match self { + Self::FreeVar(fv) => { fv.update_constraint(new_constraint); }, + _ => {}, + } + } } pub mod type_constrs { @@ -2770,6 +2876,11 @@ pub mod type_constrs { Type::mono_q(name) } + #[inline] + pub fn mono_proj>(lhs: Type, rhs: S) -> Type { + Type::mono_proj(lhs, rhs) + } + #[inline] pub fn poly>(name: S, params: Vec) -> Type { Type::poly(name, params) @@ -2890,6 +3001,7 @@ impl From<&Type> for TypeCode { "Proc" => Self::Proc, _ => Self::Other, }, + Type::Refinement(refine) => Self::from(&*refine.t), _ => Self::Other, } } @@ -3148,6 +3260,8 @@ impl TypePair { { Self::ProcProc } + (Type::Refinement(refine), r) => Self::new(&*refine.t, r), + (l, Type::Refinement(refine)) => Self::new(l, &*refine.t), (_, _) => Self::Others, } } diff --git a/compiler/erg_common/value.rs b/compiler/erg_common/value.rs index 39a4d5ab..bcd348d5 100644 --- a/compiler/erg_common/value.rs +++ b/compiler/erg_common/value.rs @@ -233,6 +233,9 @@ impl HasType for ValueObj { fn ref_t(&self) -> &Type { panic!("cannot get reference of the const") } + fn ref_mut_t(&mut self) -> &mut Type { + panic!("cannot get mutable reference of the const") + } /// その要素だけの集合型を返す、クラスが欲しい場合は.classで #[inline] fn t(&self) -> Type { @@ -246,6 +249,9 @@ impl HasType for ValueObj { fn signature_t(&self) -> Option<&Type> { None } + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl ValueObj { diff --git a/compiler/erg_compiler/Cargo.toml b/compiler/erg_compiler/Cargo.toml index b8e063c0..a8e827f1 100644 --- a/compiler/erg_compiler/Cargo.toml +++ b/compiler/erg_compiler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_compiler" -version = "0.2.2" +version = "0.2.4" description = "Centimetre: the Erg compiler" authors = ["Shunsuke Shibayama "] license = "MIT OR Apache-2.0" @@ -15,8 +15,8 @@ debug = [ "erg_common/debug", "erg_parser/debug" ] japanese = [ "erg_common/japanese", "erg_parser/japanese" ] [dependencies] -erg_common = { version = "0.2.2", path = "../erg_common" } -erg_parser = { version = "0.2.2", path = "../erg_parser" } +erg_common = { version = "0.2.4", path = "../erg_common" } +erg_parser = { version = "0.2.4", path = "../erg_parser" } [lib] path = "lib.rs" diff --git a/compiler/erg_compiler/compile.rs b/compiler/erg_compiler/compile.rs index a8973115..a59a8405 100644 --- a/compiler/erg_compiler/compile.rs +++ b/compiler/erg_compiler/compile.rs @@ -130,6 +130,10 @@ impl Runnable for Compiler { self.code_generator.clear(); } + fn exec(&mut self) -> Result<(), Self::Errs> { + todo!() + } + fn eval(&mut self, src: Str) -> Result { let codeobj = self.compile(src, "eval")?; Ok(codeobj.code_info()) diff --git a/compiler/erg_compiler/context.rs b/compiler/erg_compiler/context.rs index 0a23ddff..a1b2f23b 100644 --- a/compiler/erg_compiler/context.rs +++ b/compiler/erg_compiler/context.rs @@ -1,5 +1,6 @@ //! Defines `Context`. //! `Context` is used for type inference and type checking. +// use std::cmp::Ordering; use std::fmt; use std::mem; use std::option::Option; // conflicting to Type::Option @@ -9,8 +10,6 @@ use erg_common::error::{ErrorCore, Location}; use erg_common::levenshtein::levenshtein; use erg_common::set::Set; use erg_common::traits::{HasType, Locational, Stream}; -use erg_common::tsort::tsort; -use erg_common::tsort::{Graph, Node}; use erg_common::ty::fresh_varname; use erg_common::ty::{ ConstObj, Constraint, FreeKind, HasLevel, IntervalOp, ParamTy, Predicate, RefinementType, @@ -19,7 +18,7 @@ use erg_common::ty::{ use erg_common::value::ValueObj; use erg_common::Str; use erg_common::{ - assume_unreachable, enum_unwrap, fmt_slice, fmt_vec, fn_name, get_hash, log, set, try_map, + assume_unreachable, enum_unwrap, fmt_slice, fn_name, get_hash, log, set, try_map, }; use Predicate as Pred; use TyParamOrdering::*; @@ -33,6 +32,7 @@ use ast::{ use erg_parser::ast; use erg_parser::token::{Token, TokenKind}; +use crate::error::readable_name; use crate::error::{binop_to_dname, unaryop_to_dname, TyCheckError, TyCheckErrors, TyCheckResult}; use crate::eval::Evaluator; use crate::hir; @@ -40,6 +40,53 @@ use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind, Visibility}; use Mutability::*; use Visibility::*; +type Trait = Type; + +/// ``` +/// TyParamIdx::new(Add(R, O), O) => Nth(1) +/// TyParamIdx::new(Add(R, F(O, I)), O) => Nested(Nth(1), 0) +/// ``` +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum TyParamIdx { + Nth(usize), + Nested(Box, usize), +} + +impl TyParamIdx { + pub fn search(search_from: &Type, target: &Type) -> Option { + match search_from { + Type::Poly{ params, .. } => { + for (i, tp) in params.iter().enumerate() { + match tp { + TyParam::Type(t) if t.rec_eq(target) => { return Some(Self::Nth(i)) }, + TyParam::Type(t) if t.is_monomorphic() => {}, + other => todo!("{other:?}"), + } + } + None + }, + _ => todo!(), + } + } + + /// ``` + /// Nested(Nth(1), 0).select(F(X, G(Y, Z))) == Y + /// ``` + pub fn select(self, from: &Type) -> Type { + match self { + Self::Nth(n) => { + let tps = from.typarams(); + let tp = tps.iter().nth(n).unwrap(); + match tp { + TyParam::Type(t) => *t.clone(), + _ => todo!(), + } + }, + Self::Nested(_, _) => todo!(), + } + } +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum DefaultInfo { NonDefault, @@ -122,8 +169,6 @@ pub enum RegistrationMode { use RegistrationMode::*; -type TyBoundGraph = Graph; - /// Context for instantiating a quantified type /// 量化型をインスタンス化するための文脈 #[derive(Debug, Clone)] @@ -134,155 +179,156 @@ pub struct TyVarContext { } impl TyVarContext { - pub fn new(level: usize, bounds: Set) -> Self { + pub fn new(level: usize, bounds: Set, ctx: &Context) -> Self { let mut self_ = Self { level, tyvar_instances: Dict::new(), typaram_instances: Dict::new(), }; - for bound in Self::sort_bounds(bounds) { - self_.instantiate_bound(bound); + // TODO: this is valid but cause a crash: T <: Ord T + for bound in bounds.into_iter() { + self_.instantiate_bound(bound, ctx); } self_ } - fn sort_bounds(_bounds: Set) -> impl Iterator { - let mut graph = TyBoundGraph::new(); - for bound in _bounds.into_iter() { - let depends_on = Self::bound_dependencies(&bound); - graph.push(Node::new(Str::rc(bound.lhs()), bound, depends_on)); - } - let graph = tsort(graph); - graph.into_iter().map(|node| node.data) - } - - fn bound_dependencies(_bound: &TyBound) -> Vec { - // TODO: Polymorphic lhs - match _bound { - TyBound::Subtype { sup, .. } => Self::rec_t_inner_qvars(sup, vec![]), - TyBound::Supertype { sub, .. } => Self::rec_t_inner_qvars(sub, vec![]), - TyBound::Sandwiched { mid, .. } => Self::rec_t_inner_qvars(mid, vec![]), - TyBound::Instance { t, .. } => Self::rec_t_inner_qvars(t, vec![]), - } - } - - fn rec_t_inner_qvars(t: &Type, dep: Vec) -> Vec { - match t { - Type::MonoQVar(name) | Type::PolyQVar { name, .. } => { - [dep, vec![name.clone()]].concat() + fn instantiate_const_template(&mut self, var_name: &str, _callee_name: &Str, ct: &ConstTemplate) -> TyParam { + match ct { + ConstTemplate::Obj(o) => { + match o { + ConstObj::Type(t) if t.is_mono_q() => { + if t.name() == "Self" { + let constraint = Constraint::TypeOf(Type); + let t = Type::named_free_var(Str::rc(var_name), self.level, constraint); + TyParam::t(t) + } else { + todo!() + } + }, + ConstObj::Type(t) => TyParam::t(*t.clone()), + v @ ConstObj::Value(_) => TyParam::ConstObj(v.clone()), + other => todo!("{other}"), + } + }, + ConstTemplate::App { .. } => { + todo!() } - Type::FreeVar(fv) if fv.is_linked() => Self::rec_t_inner_qvars(&fv.crack(), dep), - Type::Ref(t) | Type::RefMut(t) => Self::rec_t_inner_qvars(t, dep), - Type::Poly { params, .. } => params.iter().fold(dep, |acc, arg| { - [acc, Self::rec_tp_inner_qvars(arg, vec![])].concat() - }), - Type::VarArgs(t) => Self::rec_t_inner_qvars(t, dep), - Type::Subr(_subr) => todo!(), - Type::Callable { - param_ts: _, - return_t: _, - } => todo!(), - Type::And(_) | Type::Or(_) | Type::Not(_) => todo!(), - Type::Record(_) => todo!(), - Type::Quantified(_) => todo!(), - Type::Refinement(_) => todo!(), - _ => dep, } } - fn rec_tp_inner_qvars(tp: &TyParam, dep: Vec) -> Vec { - match tp { - TyParam::MonoQVar(name) | TyParam::PolyQVar { name, .. } => { - [dep, vec![name.clone()]].concat() + fn instantiate_poly(&mut self, tvar_name: &str, name: &Str, params: Vec, ctx: &Context) -> Type { + if let Some(temp_defaults) = ctx.rec_get_const_param_defaults(&name) { + let c = ctx.rec_type_ctx_by_name(name).unwrap_or_else(|| panic!("{} not found", name)); + let defined_params_len = c.params.len(); + let given_params_len = params.len(); + if defined_params_len < given_params_len { panic!() } + let inst_non_defaults = params.into_iter().map(|p| self.instantiate_tp(p)).collect(); + let mut inst_defaults = vec![]; + for c in temp_defaults.into_iter().take(defined_params_len - given_params_len) { + let c = self.instantiate_const_template(tvar_name, name, c); + inst_defaults.push(c); } - TyParam::FreeVar(fv) if fv.is_linked() => Self::rec_tp_inner_qvars(&fv.crack(), dep), - TyParam::Type(t) => Self::rec_t_inner_qvars(t, dep), - TyParam::App { args, .. } | TyParam::Array(args) | TyParam::Tuple(args) => { - args.iter().fold(dep, |acc, arg| { - [acc, Self::rec_tp_inner_qvars(arg, vec![])].concat() - }) - } - TyParam::UnaryOp { .. } => todo!(), - TyParam::BinOp { .. } => todo!(), - _ => dep, + Type::poly( + name, + [inst_non_defaults, inst_defaults].concat(), + ) + } else { + Type::poly( + name, + params.into_iter().map(|p| self.instantiate_tp(p)).collect(), + ) } } - fn instantiate_bound(&mut self, bound: TyBound) { + fn instantiate_bound(&mut self, bound: TyBound, ctx: &Context) { match bound { TyBound::Subtype { sub, sup } => { let sup = match sup { - Type::Poly { name, params } => Type::poly( - name, - params.into_iter().map(|p| self.instantiate_tp(p)).collect(), - ), + Type::Poly { name, params } => { + self.instantiate_poly(sub.name(), &name, params, ctx) + } Type::MonoProj { lhs, rhs } => Type::mono_proj(self.instantiate_t(*lhs), rhs), sup => sup, }; let constraint = Constraint::SubtypeOf(sup); - let name = Str::rc(sub.name()); - self.push_tyvar( - name.clone(), - Type::named_free_var(name, self.level, constraint), - ); + if let Some(tv) = self.tyvar_instances.get(sub.name()) { + tv.update_constraint(constraint); + } else if let Some(tp) = self.typaram_instances.get(sub.name()) { + tp.update_constraint(constraint); + } else { + let name = Str::rc(sub.name()); + self.push_tyvar(name.clone(), Type::named_free_var(name, self.level, constraint)); + } } TyBound::Supertype { sup, sub } => { let sub = match sub { - Type::Poly { name, params } => Type::poly( - name, - params.into_iter().map(|p| self.instantiate_tp(p)).collect(), - ), + Type::Poly { name, params } => { + self.instantiate_poly(sup.name(), &name, params, ctx) + } Type::MonoProj { lhs, rhs } => Type::mono_proj(self.instantiate_t(*lhs), rhs), sub => sub, }; let constraint = Constraint::SupertypeOf(sub); - let name = Str::rc(sup.name()); - self.push_tyvar( - name.clone(), - Type::named_free_var(name, self.level, constraint), - ); + if let Some(tv) = self.tyvar_instances.get(sup.name()) { + tv.update_constraint(constraint); + } else if let Some(tp) = self.typaram_instances.get(sup.name()) { + tp.update_constraint(constraint); + } else { + let name = Str::rc(sup.name()); + self.push_tyvar(name.clone(), Type::named_free_var(name, self.level, constraint)); + } } TyBound::Sandwiched { sub, mid, sup } => { let sub = match sub { - Type::Poly { name, params } => Type::poly( - name, - params.into_iter().map(|p| self.instantiate_tp(p)).collect(), - ), + Type::Poly { name, params } => { + self.instantiate_poly(mid.name(), &name, params, ctx) + } Type::MonoProj { lhs, rhs } => Type::mono_proj(self.instantiate_t(*lhs), rhs), sub => sub, }; let sup = match sup { - Type::Poly { name, params } => Type::poly( - name, - params.into_iter().map(|p| self.instantiate_tp(p)).collect(), - ), + Type::Poly { name, params } => { + self.instantiate_poly(mid.name(), &name, params, ctx) + } Type::MonoProj { lhs, rhs } => Type::mono_proj(self.instantiate_t(*lhs), rhs), sup => sup, }; let constraint = Constraint::Sandwiched { sub, sup }; - let name = Str::rc(mid.name()); - self.push_tyvar( - name.clone(), - Type::named_free_var(name, self.level, constraint), - ); + if let Some(tv) = self.tyvar_instances.get(mid.name()) { + tv.update_constraint(constraint); + } else if let Some(tp) = self.typaram_instances.get(mid.name()) { + tp.update_constraint(constraint); + } else { + let name = Str::rc(mid.name()); + self.push_tyvar(name.clone(), Type::named_free_var(name, self.level, constraint)); + } } TyBound::Instance { name, t } => { let t = match t { - Type::Poly { name, params } => Type::poly( - name, - params.into_iter().map(|p| self.instantiate_tp(p)).collect(), - ), + Type::Poly { name, params } => { + self.instantiate_poly(&name[..], &name, params, ctx) + } t => t, }; + let constraint = Constraint::TypeOf(t.clone()); // TODO: type-like types if t == Type { - let constraint = Constraint::TypeOf(t); - self.push_tyvar( - name.clone(), - Type::named_free_var(name, self.level, constraint), - ); + if let Some(tv) = self.tyvar_instances.get(&name) { + tv.update_constraint(constraint); + } else if let Some(tp) = self.typaram_instances.get(&name) { + tp.update_constraint(constraint); + } else { + self.push_tyvar( + name.clone(), + Type::named_free_var(name, self.level, constraint), + ); + } } else { - self.push_typaram(name.clone(), TyParam::named_free_var(name, self.level, t)); + if let Some(tp) = self.typaram_instances.get(&name) { + tp.update_constraint(constraint); + } else { + self.push_typaram(name.clone(), TyParam::named_free_var(name, self.level, t)); + } } } } @@ -292,7 +338,7 @@ impl TyVarContext { todo!() } - pub(crate) fn instantiate_t(&self, quantified: Type) -> Type { + pub(crate) fn instantiate_t(&mut self, quantified: Type) -> Type { match quantified { Type::MonoQVar(n) => { if let Some(t) = self.get_tyvar(&n) { @@ -304,14 +350,16 @@ impl TyVarContext { todo!() } } else { - todo!() + let tv = Type::named_free_var(n.clone(), self.level, Constraint::Uninited); + self.push_tyvar(n, tv.clone()); + tv } } other => todo!("{other}"), } } - fn instantiate_tp(&self, quantified: TyParam) -> TyParam { + fn instantiate_tp(&mut self, quantified: TyParam) -> TyParam { match quantified { TyParam::MonoQVar(n) => { if let Some(t) = self.get_typaram(&n) { @@ -319,7 +367,9 @@ impl TyVarContext { } else if let Some(t) = self.get_tyvar(&n) { TyParam::t(t.clone()) } else { - panic!("Type parameter {n} is not found. This is a bug.") + let tp = TyParam::named_free_var(n.clone(), self.level, Type::Uninited); + self.push_typaram(n, tp.clone()); + tp } } TyParam::Type(t) => { @@ -329,7 +379,9 @@ impl TyVarContext { } else if let Some(t) = self.get_tyvar(&n) { TyParam::t(t.clone()) } else { - panic!("Type variable {n} is not found. This is a bug.") + let tv = Type::named_free_var(n.clone(), self.level, Constraint::Uninited); + self.push_tyvar(n, tv.clone()); + TyParam::t(tv) } } else { todo!("{t}") @@ -366,6 +418,22 @@ impl TyVarContext { } } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum ConstTemplate { + Obj(ConstObj), + App{ name: Str, non_default_args: Vec, default_args: Vec }, +} + +impl ConstTemplate { + pub const fn app(name: &'static str, non_default_args: Vec, default_args: Vec) -> Self { + ConstTemplate::App { + name: Str::ever(name), + non_default_args, + default_args, + } + } +} + /// Represents the context of the current scope #[derive(Debug)] pub struct Context { @@ -375,21 +443,28 @@ pub struct Context { // ユーザー定義APIでのみ使う pub(crate) bounds: Vec, pub(crate) preds: Vec, - // for looking up the parent scope + /// for looking up the parent scope pub(crate) outer: Option>, + // e.g. { "Add": [ConstObjTemplate::App("Self", vec![])]) + pub(crate) const_param_defaults: Dict>, + // Superclasses/supertraits by a patch are not included here // 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 - // K: メソッド名, V: それを実装するパッチたち - // 提供メソッドはスコープごとに実装を切り替えることができる - pub(crate) _method_impl_patches: Dict>, - // K: 多相トレイトの名前, V: 実装(小さい順) - // e.g. { "Add": [Add(Nat, Nat), Add(Int, Int), ...], ... } - pub(crate) poly_trait_impls: Dict>, - // .0: 関係付けるパッチ(glue patch), .1: サブタイプになる型, .2: スーパータイプになるトレイト - // 一つの型ペアを接着パッチは同時に一つまでしか存在しないが、付け替えは可能 - pub(crate) glue_patch_and_types: Vec<(VarName, Type, Type)>, - // stores declared names (not initialized) + /// K: method name, V: impl patch + /// Provided methods can switch implementations on a scope-by-scope basis + /// K: メソッド名, V: それを実装するパッチたち + /// 提供メソッドはスコープごとに実装を切り替えることができる + pub(crate) method_impl_patches: Dict>, + /// K: name of the polymorphic trait, V: (type, monomorphised trait that the type implements) + /// K: 多相トレイトの名前, V: (型, その型が実装する単相化トレイト) + /// e.g. { "Add": [(Nat, Add(Nat)), (Int, Add(Int)), ...], ... } + pub(crate) poly_trait_impls: Dict>, + /// .0: glue patch, .1: type as subtype, .2: trait as supertype + /// .0: 関係付けるパッチ(glue patch), .1: サブタイプになる型, .2: スーパータイプになるトレイト + /// 一つの型ペアを接着パッチは同時に一つまでしか存在しないが、付け替えは可能 + pub(crate) glue_patch_and_types: Vec<(VarName, Type, Trait)>, + /// stores declared names (not initialized) pub(crate) decls: Dict, // stores defined names // 型の一致はHashMapでは判定できないため、keyはVarNameとして1つずつ見ていく @@ -401,7 +476,6 @@ pub struct Context { pub(crate) params: Vec<(Option, VarInfo)>, pub(crate) locals: Dict, pub(crate) consts: Dict, - // FIXME: Compilerが持つ pub(crate) eval: Evaluator, // stores user-defined type context pub(crate) types: Dict, @@ -501,7 +575,8 @@ impl Context { outer: outer.map(Box::new), super_classes, super_traits, - _method_impl_patches: Dict::default(), + const_param_defaults: Dict::default(), + method_impl_patches: Dict::default(), poly_trait_impls: Dict::default(), glue_patch_and_types: Vec::default(), params: params_, @@ -961,7 +1036,7 @@ impl Context { TyCheckError::return_type_error( e.core.loc, e.caused_by, - name.inspect(), + readable_name(name.inspect()), spec_ret_t, body_t, ) @@ -1121,6 +1196,7 @@ impl Context { TyBound::sandwiched(sub.clone(), Type::mono(name.clone()), sup.clone()) } Constraint::TypeOf(t) => TyBound::instance(Str::rc(&name[..]), t.clone()), + Constraint::Uninited => unreachable!(), }; (TyParam::mono_q(&name), set! {bound}) } @@ -1138,6 +1214,7 @@ impl Context { TyBound::sandwiched(sub.clone(), Type::mono(name.clone()), sup.clone()) } Constraint::TypeOf(t) => TyBound::instance(Str::rc(&name[..]), t.clone()), + Constraint::Uninited => unreachable!(), }; (TyParam::mono_q(name), set! {bound}) } @@ -1180,6 +1257,7 @@ impl Context { TyBound::sandwiched(sub.clone(), Type::mono(name.clone()), sup.clone()) } Constraint::TypeOf(t) => TyBound::instance(Str::rc(&name[..]), t.clone()), + Constraint::Uninited => unreachable!(), }; (Type::mono(&name), set! {bound}) } @@ -1197,6 +1275,7 @@ impl Context { TyBound::sandwiched(sub.clone(), Type::mono(name.clone()), sup.clone()) } Constraint::TypeOf(t) => TyBound::instance(Str::rc(&name[..]), t.clone()), + Constraint::Uninited => unreachable!(), }; (Type::mono(name), set! {bound}) } @@ -1290,10 +1369,10 @@ impl Context { fn instantiate_tp(quantified: TyParam, tv_ctx: TyVarContext) -> (TyParam, TyVarContext) { match quantified { TyParam::MonoQVar(n) => { - if let Some(t) = tv_ctx.get_typaram(&n) { - (t.clone(), tv_ctx) - } else if let Some(_t) = tv_ctx.get_tyvar(&n) { - todo!() + if let Some(tp) = tv_ctx.get_typaram(&n) { + (tp.clone(), tv_ctx) + } else if let Some(t) = tv_ctx.get_tyvar(&n) { + (TyParam::t(t.clone()), tv_ctx) } else { panic!("type parameter {n} is not defined") } @@ -1325,8 +1404,16 @@ impl Context { MonoQVar(n) => { if let Some(t) = tv_ctx.get_tyvar(&n) { (t.clone(), tv_ctx) - } else if let Some(_t) = tv_ctx.get_typaram(&n) { - todo!() + } else if let Some(tp) = tv_ctx.get_typaram(&n) { + if let TyParam::Type(t) = tp { + (*t.clone(), tv_ctx) + } else { + todo!( + "typaram_insts: {}\ntyvar_insts:{}\n{tp}", + tv_ctx.typaram_instances, + tv_ctx.tyvar_instances, + ) + } } else { panic!("the type variable {n} is not defined") } @@ -1390,7 +1477,7 @@ impl Context { } Ref(t) => { let (t, tv_ctx) = Self::instantiate_t(*t, tv_ctx); - (Type::refer(t), tv_ctx) + (Type::ref_(t), tv_ctx) } RefMut(t) => { let (t, tv_ctx) = Self::instantiate_t(*t, tv_ctx); @@ -1418,7 +1505,7 @@ impl Context { fn instantiate(&self, quantified: Type, callee: &hir::Expr) -> TyCheckResult { match quantified { Quantified(quant) => { - let tv_ctx = TyVarContext::new(self.level, quant.bounds); + let tv_ctx = TyVarContext::new(self.level, quant.bounds, &self); let (t, _) = Self::instantiate_t(*quant.unbound_callable, tv_ctx); match &t { Type::Subr(subr) => { @@ -1475,9 +1562,11 @@ impl Context { .iter() .chain(subr.default_params.iter()); for (param_ty, pos_arg) in params.clone().zip(pos_args) { + let arg_t = pos_arg.expr.ref_t(); + let param_t = ¶m_ty.ty; self.sub_unify( - pos_arg.expr.ref_t(), - ¶m_ty.ty, + arg_t, + param_t, None, Some(pos_arg.loc()), ) @@ -1485,13 +1574,13 @@ impl Context { // REVIEW: let name = callee.var_full_name().unwrap_or_else(|| "".to_string()); let name = - name + "::" + param_ty.name.as_ref().map(|s| &s[..]).unwrap_or(""); + name + "::" + param_ty.name.as_ref().map(|s| readable_name(&s[..])).unwrap_or(""); TyCheckError::type_mismatch_error( e.core.loc, e.caused_by, &name[..], - ¶m_ty.ty, - pos_arg.expr.ref_t(), + param_t, + arg_t, ) })?; if let Some(name) = ¶m_ty.name { @@ -1537,7 +1626,7 @@ impl Context { // FIXME: fn deref_tp(&self, tp: TyParam) -> TyCheckResult { match tp { - TyParam::FreeVar(fv) if fv.is_linked() => Ok(fv.unwrap()), + TyParam::FreeVar(fv) if fv.is_linked() => Ok(fv.unwrap_linked()), TyParam::Type(t) => Ok(TyParam::t(self.deref_tyvar(*t)?)), TyParam::App { name, mut args } => { for param in args.iter_mut() { @@ -1545,37 +1634,78 @@ impl Context { } Ok(TyParam::App { name, args }) } + TyParam::BinOp { .. } => todo!(), + TyParam::UnaryOp { .. } => todo!(), + TyParam::Array(_) | TyParam::Tuple(_) => todo!(), t => Ok(t), } } + fn deref_constraint(&self, constraint: Constraint) -> TyCheckResult { + match constraint { + Constraint::SubtypeOf(sup) => { + Ok(Constraint::SubtypeOf(self.deref_tyvar(sup)?)) + }, + Constraint::Sandwiched { sub, sup } => { + Ok(Constraint::sandwiched(self.deref_tyvar(sub)?, self.deref_tyvar(sup)?)) + }, + Constraint::SupertypeOf(sub) => { + Ok(Constraint::SupertypeOf(self.deref_tyvar(sub)?)) + }, + Constraint::TypeOf(t) => { + Ok(Constraint::TypeOf(self.deref_tyvar(t)?)) + }, + _ => unreachable!(), + } + } + + /// e.g. + /// ``` + /// deref_tyvar(?T(<: Int)[n]): ?T => Int (if self.level <= n) + /// deref_tyvar((Int)): (Int) => Int + /// ``` fn deref_tyvar(&self, t: Type) -> TyCheckResult { match t { - // in toplevel: ?T(<: Int)[n] should replaced to Int (if n > 0) - Type::FreeVar(fv) if fv.is_unbound() => { - match fv.borrow().constraint().unwrap() { - Constraint::SubtypeOf(sup) | Constraint::Sandwiched { sup, .. } - if self.level <= fv.level().unwrap() => - { - return Ok(sup.clone()); - } - // REVIEW: really? - Constraint::SupertypeOf(sub) if self.level <= fv.level().unwrap() => { - return Ok(sub.clone()); - } - _ => {} + Type::FreeVar(fv) if fv.constraint_is_typeof() => Ok(Type::FreeVar(fv)), + // ?T(<: Int)[n] => Int + Type::FreeVar(fv) if fv.constraint_is_subtypeof() => { + if self.level <= fv.level().unwrap() { + Ok(fv.crack_constraint().super_type().unwrap().clone()) + } else { + Ok(Type::FreeVar(fv)) } - Ok(Type::FreeVar(fv)) - } - Type::FreeVar(fv) if fv.is_linked() => Ok(fv.unwrap()), - // 未連携型変数のチェックはモジュール全体の型検査が終わった後にやる + }, + // ?T(<: Add(?R(<: T), ?O(<: U)) => ?T(<: Add(T, U)) + Type::FreeVar(fv) if fv.is_unbound() => { + if self.level == 0 { + match &*fv.crack_constraint() { + Constraint::SupertypeOf(t) + | Constraint::SubtypeOf(t) => Ok(t.clone()), + Constraint::Sandwiched { sub, .. } => Ok(sub.clone()), + Constraint::TypeOf(_) => { + Err(TyCheckError::unreachable(fn_name!(), line!())) + }, + _ => unreachable!(), + } + } else { + let new_constraint = fv.crack_constraint().clone(); + let new_constraint = self.deref_constraint(new_constraint)?; + fv.update_constraint(new_constraint); + Ok(Type::FreeVar(fv)) + } + }, + Type::FreeVar(fv) if fv.is_linked() => { + let t = fv.unwrap_linked(); + self.deref_tyvar(t) + }, + // 未連携型変数が残っているかのチェックはモジュール全体の型検査が終わった後にやる // Type::FreeVar(_) => // Err(TyCheckError::checker_bug(0, Location::Unknown, fn_name!(), line!())), Type::Poly { name, mut params } => { for param in params.iter_mut() { *param = self.deref_tp(mem::take(param))?; } - Ok(Type::poly(name, params)) + Ok(Type::Poly { name, params }) } Type::Subr(mut subr) => { match &mut subr.kind { @@ -1604,42 +1734,81 @@ impl Context { } } - /// e.g. - /// monomorphise_t(Add(Nat, Nat)): (Add(Nat, Nat) => Nat) - /// monomorphise_t(Add(Nat, ?O)): (?O => Nat, Add(Nat, Nat) => Nat) - pub(crate) fn monomorphise(&self, maybe_poly: Type) -> TyCheckResult { - match maybe_poly { - Type::Subr(mut subr) => { - if let Some(self_t) = subr.kind.self_t_mut() { - *self_t = self.monomorphise(mem::take(self_t))?; + pub(crate) fn deref_toplevel(&mut self, mut hir: hir::HIR) -> TyCheckResult { + self.level = 0; + for chunk in hir.module.iter_mut() { + self.deref_expr_t(chunk).map_err(|e| e)?; + } + Ok(hir) + } + + fn deref_expr_t(&self, expr: &mut hir::Expr) -> TyCheckResult<()> { + match expr { + hir::Expr::Lit(_) => Ok(()), + hir::Expr::Accessor(acc) => { + let t = acc.ref_mut_t(); + *t = self.deref_tyvar(mem::take(t))?; + match acc { + hir::Accessor::Attr(attr) => { + self.deref_expr_t(&mut attr.obj)?; + } + hir::Accessor::Local(_) => {} + _ => todo!(), } - for param_t in subr.non_default_params.iter_mut() { - param_t.ty = self.monomorphise(mem::take(&mut param_t.ty))?; - } - for param_t in subr.default_params.iter_mut() { - param_t.ty = self.monomorphise(mem::take(&mut param_t.ty))?; - } - subr.return_t = Box::new(self.monomorphise(mem::take(&mut subr.return_t))?); - Ok(Type::Subr(subr)) + Ok(()) + }, + hir::Expr::Array(_array) => { + todo!() + }, + hir::Expr::Dict(_dict) => { + todo!() } - Type::Poly { name, params } => { - let impls = self.rec_get_trait_impls(&name); - if impls.is_empty() { - panic!("{} is not implemented", name); + hir::Expr::BinOp(binop) => { + let t = binop.signature_mut_t().unwrap(); + *t = self.deref_tyvar(mem::take(t))?; + self.deref_expr_t(&mut binop.lhs)?; + self.deref_expr_t(&mut binop.rhs)?; + Ok(()) + }, + hir::Expr::UnaryOp(unaryop) => { + let t = unaryop.signature_mut_t().unwrap(); + *t = self.deref_tyvar(mem::take(t))?; + self.deref_expr_t(&mut unaryop.expr)?; + Ok(()) + }, + hir::Expr::Call(call) => { + let t = call.signature_mut_t().unwrap(); + *t = self.deref_tyvar(mem::take(t))?; + for arg in call.args.pos_args.iter_mut() { + self.deref_expr_t(&mut arg.expr)?; } - let min = self - .smallest_t(impls.clone().into_iter()) - .unwrap_or_else(move || { - panic!("cannot determine the smallest type: {}", fmt_vec(&impls)) - }); - dbg!(&min); - for (param, min_param) in params.iter().zip(min.typarams()) { - self.unify_tp(param, &min_param, None, None, false)?; - } - dbg!(¶ms); - Ok(min) + Ok(()) + } + hir::Expr::Decl(decl) => { + decl.t = self.deref_tyvar(mem::take(&mut decl.t))?; + Ok(()) + }, + hir::Expr::Def(def) => { + 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::Lambda(lambda) => { + lambda.t = self.deref_tyvar(mem::take(&mut lambda.t))?; + for chunk in lambda.body.iter_mut() { + self.deref_expr_t(chunk)?; + } + Ok(()) } - _ => Ok(maybe_poly), } } @@ -1878,6 +2047,11 @@ impl Context { (lt @ Type::FreeVar(lfv), rt @ Type::FreeVar(rfv)) if lfv.is_unbound() && rfv.is_unbound() => { + if lfv.constraint_is_typeof() && !rfv.constraint_is_typeof() { + lfv.update_constraint(rfv.crack_constraint().clone()); + } else if rfv.constraint_is_typeof() && !lfv.constraint_is_typeof() { + rfv.update_constraint(lfv.crack_constraint().clone()); + } if lfv.level().unwrap() > rfv.level().unwrap() { lfv.link(rt); } else { @@ -2055,7 +2229,7 @@ impl Context { } Ok(()) } - (l, r) if self.same_type_of(l, r, None, None) => Ok(()), + (l, r) if self.formal_same_type_of(l, r, None, None) => Ok(()), (l, r) => Err(TyCheckError::re_unification_error( l, r, @@ -2067,6 +2241,10 @@ impl Context { } /// Assuming that `sub` is a subtype of `sup`, fill in the type variable to satisfy the assumption + /// + /// When comparing arguments and parameter, the left side is the argument (found) and the right side is the parameter (expected) + /// + /// The parameter type must be a supertype of the argument type /// ``` /// sub_unify({I: Int | I == 0}, ?T(<: Ord)): (/* OK */) /// sub_unify(Int, ?T(:> Nat)): (?T :> Int) @@ -2102,40 +2280,113 @@ impl Context { | FreeKind::Unbound { constraint, .. } => match constraint { // sub_unify(Nat, ?T(:> Int)): (/* OK */) // sub_unify(Int, ?T(:> Nat)): (?T :> Int) - Constraint::SupertypeOf(sub) if self.rec_full_supertype_of(l, sub) => { - *constraint = Constraint::SupertypeOf(l.clone()); + // sub_unify(Str, ?T(:> Int)): (/* ?T = Str or Int */) // TODO: + Constraint::SupertypeOf(sub) => { + if self.rec_full_supertype_of(l, sub) { + *constraint = Constraint::SupertypeOf(l.clone()); + } else if self.rec_full_subtype_of(l, sub) { + /* OK */ + } else { + todo!() + } } - // sub_unify(Nat, ?T(<: Int)): (/* OK */) - // sub_unify(Int, ?T(<: Nat)): Error! - Constraint::SubtypeOf(sup) if self.rec_full_supertype_of(l, sup) => { - return Err(TyCheckError::subtyping_error( - l, - sup, - sub_loc, - sup_loc, - self.caused_by(), - )) + // sub_unify(Nat, ?T(<: Int)): (Nat <: ?T <: Int) + // sub_unify(Nat, ?T(<: Add(?R, ?O))): (Nat <: ?T <: Add(?R, ?O)) + // sub_unify(Int, ?T(<: Nat)): (/* Error */) + // sub_unify(Str, ?T(<: Int)): (/* Error */) + Constraint::SubtypeOf(sup) => { + if !self.rec_full_subtype_of(l, sup) { + return Err(TyCheckError::subtyping_error( + l, + sup, + sub_loc, + sup_loc, + self.caused_by(), + )) + } else { + *constraint = Constraint::sandwiched(l.clone(), mem::take(sup)); + } } - // sub_unify(Nat, (Ratio :> ?T :> Int)): (/* OK */) - // sub_unify(Int, (Ratio :> ?T :> Nat)): (Ratio :> ?T :> Int) - Constraint::Sandwiched { sub, sup } - if self.rec_full_supertype_of(l, sub) => - { - *constraint = Constraint::Sandwiched { - sub: l.clone(), - sup: mem::take(sup), - }; + // sub_unify(Nat, (Int <: ?T <: Ratio)): (/* OK */) + // sub_unify(Int, (Nat <: ?T <: Ratio)): (Int <: ?T <: Ratio) + // sub_unify(Str, (Nat <: ?T <: Ratio)): (/* Error */) + // sub_unify({0}, ({1} <: ?T <: Nat)): ({0, 1} <: ?T <: Nat)) + Constraint::Sandwiched { sub, sup } => { + if self.rec_full_no_relation_of(l, sup) { + return Err(TyCheckError::subtyping_error( + l, + sup, // TODO: + sub_loc, + sup_loc, + self.caused_by(), + )) + } else { + let union = self.union(l, sub); + *constraint = Constraint::sandwiched(union, mem::take(sub)); + } } Constraint::TypeOf(_t) => { *constraint = Constraint::SupertypeOf(l.clone()); - } + }, _ => {} }, _ => {} } return Ok(()); } - (Type::FreeVar(fv), _r) if fv.is_linked() => todo!(), + (Type::FreeVar(fv), r) if fv.is_unbound() => { + match &mut *fv.borrow_mut() { + FreeKind::NamedUnbound { constraint, .. } + | FreeKind::Unbound { constraint, .. } => match constraint { + // sub_unify(?T(:> Int), Nat): (/* Error */) + // sub_unify(?T(:> Nat), Int): (Nat <: ?T <: Int) + // sub_unify(?T(:> Nat), Str): (/* Error */) + Constraint::SupertypeOf(sub) => { + if !self.rec_full_subtype_of(sub, r) { + return Err(TyCheckError::subtyping_error( + sub, + r, + sub_loc, + sup_loc, + self.caused_by(), + )) + } else { + *constraint = Constraint::sandwiched(sub.clone(), r.clone()); + } + } + // sub_unify(?T(<: Int), Nat): (?T(<: Nat)) + // sub_unify(?T(<: Nat), Int): (/* OK */) + // sub_unify(?T(<: Str), Int): (/* Error */) // TODO: + Constraint::SubtypeOf(sup) + if self.rec_full_supertype_of(sup, r) => + { + *constraint = Constraint::SubtypeOf(r.clone()); + } + // sub_unify((Int <: ?T <: Ratio), Nat): (/* Error */) + // sub_unify((Nat <: ?T <: Ratio), Int): (/* OK */) + // sub_unify((Nat <: ?T <: Int), Str): (/* Error */) + Constraint::Sandwiched { sub, sup: _ } + if !self.rec_full_subtype_of(sub, r) => + { + return Err(TyCheckError::subtyping_error( + sub, + r, + sub_loc, + sup_loc, + self.caused_by(), + )) + } + // sub_unify(?T(: Type), Int): (?T(<: Int)) + Constraint::TypeOf(_t) => { + *constraint = Constraint::SubtypeOf(r.clone()); + }, + _ => {} + }, + _ => {} + } + return Ok(()); + }, + (Type::FreeVar(_fv), _r) => todo!(), (l @ Refinement(_), r @ Refinement(_)) => return self.unify(l, r, sub_loc, sup_loc), _ => {} } @@ -2168,7 +2419,7 @@ impl Context { if self.formal_supertype_of(l, maybe_sub, Some(&bounds), Some(&variance)) && self.formal_supertype_of(r, maybe_sup, Some(&bounds), Some(&variance)) { - let tv_ctx = TyVarContext::new(self.level, bounds); + let tv_ctx = TyVarContext::new(self.level, bounds, &self); let (l, _) = Self::instantiate_t(l.clone(), tv_ctx.clone()); let (r, _) = Self::instantiate_t(r.clone(), tv_ctx); Some((l, r)) @@ -2795,13 +3046,11 @@ impl Context { self.substitute_call(callee, &instance, pos_args, kw_args)?; log!("Substituted:\ninstance: {instance}"); let res = self.deref_tyvar(instance)?; - log!("Eliminated:\nres: {res}\n"); - let res = self.eval.eval_t_params(res, self, self.level)?; + log!("Derefed:\nres: {res}\n"); + let res = self.eval.eval_t_params(res, &self, self.level)?; log!("Params Evaluated:\nres: {res}\n"); let res = self.deref_tyvar(res)?; - log!("Eliminated (2):\nres: {res}\n"); - let res = self.monomorphise(res)?; - log!("Monomorphised:\nres: {res}\n"); + log!("Derefed (2):\nres: {res}\n"); self.propagate(&res, callee)?; log!("Propagated:\nres: {res}\n"); Ok(res) @@ -2816,7 +3065,7 @@ impl Context { ) -> bool { match (lhs, rhs) { (TyParam::Type(lhs), TyParam::Type(rhs)) => { - return self.same_type_of(lhs, rhs, bounds, lhs_variance) + return self.formal_same_type_of(lhs, rhs, bounds, lhs_variance) } (TyParam::Mono(l), TyParam::Mono(r)) => { if let (Some((l, _)), Some((r, _))) = ( @@ -2824,7 +3073,7 @@ impl Context { self.types.iter().find(|(t, _)| t.name() == &r[..]), ) { return self.formal_supertype_of(l, r, bounds, None) - || self.subtype_of(l, r, bounds, lhs_variance); + || self.formal_subtype_of(l, r, bounds, lhs_variance); } } (TyParam::MonoQVar(name), other) | (other, TyParam::MonoQVar(name)) => { @@ -2890,6 +3139,11 @@ impl Context { self.rec_full_supertype_of(rhs, lhs) } + /// !(L :> R || L <: R) + pub(crate) fn rec_full_no_relation_of(&self, lhs: &Type, rhs: &Type) -> bool { + !self.rec_full_supertype_of(lhs, rhs) && !self.rec_full_subtype_of(lhs, rhs) + } + pub(crate) fn _rec_full_same_type_of(&self, lhs: &Type, rhs: &Type) -> bool { self.rec_full_supertype_of(lhs, rhs) && self.rec_full_subtype_of(lhs, rhs) } @@ -3013,10 +3267,10 @@ impl Context { && self.formal_supertype_of(&ls.return_t, &rs.return_t, bounds, lhs_variance) // covariant && ls.non_default_params.iter() .zip(rs.non_default_params.iter()) - .all(|(l, r)| self.subtype_of(&l.ty, &r.ty, bounds, lhs_variance)) + .all(|(l, r)| self.formal_subtype_of(&l.ty, &r.ty, bounds, lhs_variance)) && ls.default_params.iter() .zip(rs.default_params.iter()) - .all(|(l, r)| self.subtype_of(&l.ty, &r.ty, bounds, lhs_variance)) + .all(|(l, r)| self.formal_subtype_of(&l.ty, &r.ty, bounds, lhs_variance)) // contravariant } // RefMut, OptionMut are invariant @@ -3034,8 +3288,11 @@ impl Context { Constraint::SubtypeOf(sup) => { self.formal_supertype_of(sup, rhs, bounds, lhs_variance) } - // `(?T :> X) :> Y` is true, - Constraint::SupertypeOf(_) => true, + // `(?T :> X) :> Y` is true + // `(?T :> Str) :> Int` is true (?T :> Str or Int) + Constraint::SupertypeOf(_sub) => { + true + }, // `(Nat <: ?T <: Ratio) :> Nat` can be true Constraint::Sandwiched { sup, .. } => { self.formal_supertype_of(sup, rhs, bounds, lhs_variance) @@ -3050,22 +3307,29 @@ impl Context { panic!() } } + Constraint::Uninited => unreachable!(), }, } } - (lhs, FreeVar(v)) => { - match &*v.borrow() { + (lhs, FreeVar(fv)) => { + match &*fv.borrow() { FreeKind::Linked(t) => self.formal_supertype_of(lhs, t, bounds, lhs_variance), FreeKind::Unbound { constraint, .. } | FreeKind::NamedUnbound { constraint, .. } => match constraint { - // `Nat :> (?T <: Int)` can be true => `X :> (?T <: Y)` can be true - Constraint::SubtypeOf(_sup) => true, + // ?T cannot be `Never` + // `Nat :> (?T <: Int)` can be true + // `Int :> (?T <: Nat)` can be true + // `Str :> (?T <: Int)` is false + Constraint::SubtypeOf(sup) => { + self.formal_supertype_of(lhs, sup, bounds, lhs_variance) + || self.formal_subtype_of(lhs, sup, bounds, lhs_variance) + }, // `Int :> (?T :> Nat)` can be true, `Nat :> (?T :> Int)` is false Constraint::SupertypeOf(sub) => { self.formal_supertype_of(lhs, sub, bounds, lhs_variance) } // `Int :> (Nat <: ?T <: Ratio)` can be true, `Nat :> (Int <: ?T <: Ratio)` is false - Constraint::Sandwiched { sub, .. } => { + Constraint::Sandwiched { sub, sup: _ } => { self.formal_supertype_of(lhs, sub, bounds, lhs_variance) } Constraint::TypeOf(t) => { @@ -3075,6 +3339,7 @@ impl Context { panic!() } } + Constraint::Uninited => unreachable!(), }, } } @@ -3109,8 +3374,12 @@ impl Context { let nat = Type::Refinement(self.into_refinement(Nat)); self.formal_supertype_of(re, &nat, bounds, lhs_variance) } - // Int :> {I: Int | ...} == true, Real :> {I: Int | ...} == false, Int :> {I: Str| ...} == false - (l, Refinement(r)) => self.formal_supertype_of(l, &r.t, bounds, lhs_variance), + // Int :> {I: Int | ...} == true + // Real :> {I: Int | ...} == false + // Int :> {I: Str| ...} == false + (l, Refinement(r)) => { + self.formal_supertype_of(l, &r.t, bounds, lhs_variance) + }, // ({I: Int | True} :> Int) == true, ({N: Nat | ...} :> Int) == false, ({I: Int | I >= 0} :> Int) == false (Refinement(l), r) => { if l.preds @@ -3175,7 +3444,7 @@ impl Context { && lp.iter().zip(rp.iter()).zip(lhs_variance.iter()).all( |((l, r), variance)| match (l, r, variance) { (TyParam::Type(l), TyParam::Type(r), Variance::Contravariant) => { - self.subtype_of(l, r, bounds, Some(lhs_variance)) + self.formal_subtype_of(l, r, bounds, Some(lhs_variance)) } (TyParam::Type(l), TyParam::Type(r), Variance::Covariant) => { self.formal_supertype_of(l, r, bounds, Some(lhs_variance)) @@ -3197,7 +3466,7 @@ impl Context { if let Some(bound) = bs.iter().find(|b| b.mentions_as_subtype(name)) { self.formal_supertype_of(bound.t(), r, bounds, lhs_variance) } else if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(name)) { - if self.same_type_of(bound.t(), &Type::Type, bounds, lhs_variance) { + if self.formal_same_type_of(bound.t(), &Type::Type, bounds, lhs_variance) { true } else { todo!() @@ -3223,7 +3492,7 @@ impl Context { } /// lhs <: rhs? - pub(crate) fn subtype_of( + pub(crate) fn formal_subtype_of( &self, lhs: &Type, rhs: &Type, @@ -3233,7 +3502,7 @@ impl Context { self.formal_supertype_of(rhs, lhs, bounds, lhs_variance) } - pub(crate) fn same_type_of( + pub(crate) fn formal_same_type_of( &self, lhs: &Type, rhs: &Type, @@ -3241,7 +3510,7 @@ impl Context { lhs_variance: Option<&Vec>, ) -> bool { self.formal_supertype_of(lhs, rhs, bounds, lhs_variance) - && self.subtype_of(lhs, rhs, bounds, lhs_variance) + && self.formal_subtype_of(lhs, rhs, bounds, lhs_variance) } fn try_cmp( @@ -3319,6 +3588,8 @@ impl Context { (Any, Less) => Some(Less), (Any, Equal | LessEqual) => Some(LessEqual), (Any, Greater | NotEqual | GreaterEqual | Any) => Some(Any), + (l, r) => + todo!("cmp({inf}, {sup}) = {l:?}, cmp({inf}, {sup}) = {r:?}"), } } else { None } } @@ -3374,7 +3645,7 @@ impl Context { fn union_refinement(&self, lhs: &RefinementType, rhs: &RefinementType) -> RefinementType { if !self.formal_supertype_of(&lhs.t, &rhs.t, None, None) - && !self.subtype_of(&lhs.t, &rhs.t, None, None) + && !self.formal_subtype_of(&lhs.t, &rhs.t, None, None) { log!("{lhs}\n{rhs}"); todo!() @@ -3552,24 +3823,25 @@ impl Context { match self.min(lhs, rhs) { Some(l) if l == lhs => TyParamOrdering::Less, Some(_) => TyParamOrdering::Greater, - None => todo!("{lhs}, {rhs}"), + None => TyParamOrdering::NoRelation, } } // TODO: fn smallest_pair>(&self, ts: I) -> Option<(Type, Type)> { - ts.min_by(|(_, lhs), (_, rhs)| self.cmp_t(lhs, rhs).try_into().unwrap()) - } - - fn smallest_t>(&self, ts: I) -> Option { - ts.min_by(|lhs, rhs| { - let cmp = self.cmp_t(lhs, rhs); - cmp.try_into().unwrap_or_else(|_| panic!("{cmp:?}")) + ts.min_by(|(_, lhs), (_, rhs)| { + // HACK: Equal for unrelated types + // This doesn't work with [Nat, Str, Int] for example + self.cmp_t(lhs, rhs).try_into().unwrap() // _or(Ordering::Equal) }) } fn smallest_ref_t<'t, I: Iterator>(&self, ts: I) -> Option<&'t Type> { - ts.min_by(|lhs, rhs| self.cmp_t(lhs, rhs).try_into().unwrap()) + ts.min_by(|lhs, rhs| { + // HACK: Equal for unrelated types + // This doesn't work with [Int, Str, Nat] for example + self.cmp_t(lhs, rhs).try_into().unwrap() //_or(Ordering::Equal) + }) } pub(crate) fn get_local(&self, name: &Token, namespace: &Str) -> TyCheckResult { @@ -3707,7 +3979,11 @@ impl Context { /// tと一致ないしそれよりも大きい型のContextを返す fn sorted_type_ctxs<'a>(&'a self, t: &'a Type) -> impl Iterator { let mut ctxs = self._type_ctxs(t).collect::>(); - ctxs.sort_by(|(lhs, _), (rhs, _)| self.cmp_t(lhs, rhs).try_into().unwrap()); + ctxs.sort_by(|(lhs, _), (rhs, _)| { + // HACK: Equal for unrelated types + // This doesn't work with [Int, Str, Nat] for example + self.cmp_t(lhs, rhs).try_into().unwrap_or_else(|_| panic!("{lhs}, {rhs}")) // _or(Ordering::Equal) + }); ctxs.into_iter().map(|(_, ctx)| ctx) } @@ -3716,10 +3992,6 @@ impl Context { self.types.iter().filter_map(move |(maybe_sup, ctx)| { let bounds = ctx.type_params_bounds(); let variance = ctx.type_params_variance(); - if t.name().contains("Range") && maybe_sup.name().contains("Range") { - dbg!(&bounds, &variance); - dbg!(maybe_sup, t); - } if self.formal_supertype_of(maybe_sup, t, Some(&bounds), Some(&variance)) { Some((maybe_sup, ctx)) } else { @@ -3760,17 +4032,30 @@ impl Context { } } - fn rec_get_trait_impls(&self, name: &Str) -> Vec { - let impls = if let Some(impls) = self.poly_trait_impls.get(name) { - impls.clone() - } else { - vec![] - }; - if let Some(outer) = &self.outer { - [impls, outer.rec_get_trait_impls(name)].concat() - } else { - impls + pub(crate) fn rec_type_ctx_by_name<'a>( + &'a self, + t_name: &'a str, + ) -> Option<&'a Context> { + if let Some((_, ctx)) = self.types + .iter() + .find(|(t, _ctx)| t.name() == t_name) + { + return Some(ctx); } + if let Some(outer) = &self.outer { + outer.rec_type_ctx_by_name(t_name) + } else { + None + } + } + + 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 { + outer.rec_get_const_param_defaults(name) + } else { None } } // 再帰サブルーチン/型の推論を可能にするため、予め登録しておく diff --git a/compiler/erg_compiler/effectcheck.rs b/compiler/erg_compiler/effectcheck.rs index 484d88e0..4c4fd8b1 100644 --- a/compiler/erg_compiler/effectcheck.rs +++ b/compiler/erg_compiler/effectcheck.rs @@ -48,10 +48,10 @@ impl SideEffectChecker { self.check_def(def, true); } Expr::Call(call) => { - for parg in call.args.pos_args().iter() { + for parg in call.args.pos_args.iter() { self.check_expr(&parg.expr, true); } - for kwarg in call.args.kw_args().iter() { + for kwarg in call.args.kw_args.iter() { self.check_expr(&kwarg.expr, true); } } @@ -169,11 +169,11 @@ impl SideEffectChecker { .push(EffectError::has_effect(expr, self.full_path())); } call.args - .pos_args() + .pos_args .iter() .for_each(|parg| self.check_expr(&parg.expr, allow_self_effect)); call.args - .kw_args() + .kw_args .iter() .for_each(|kwarg| self.check_expr(&kwarg.expr, allow_self_effect)); } diff --git a/compiler/erg_compiler/error.rs b/compiler/erg_compiler/error.rs index 581cd53a..2a62f2fe 100644 --- a/compiler/erg_compiler/error.rs +++ b/compiler/erg_compiler/error.rs @@ -64,9 +64,9 @@ pub fn readable_name(name: &str) -> &str { "__pow__" => "`**`", "__mod__" => "`%`", "__rng__" => "`..`", - "__lrng__" => "`<..`", - "__rrng__" => "`..<`", - "__lrrng__" => "`<..<`", + "__lorng__" => "`<..`", + "__rorng__" => "`..<`", + "__orng__" => "`<..<`", "__and__" => "`and`", "__or__" => "`or`", "__in__" => "`in`", @@ -373,7 +373,6 @@ impl TyCheckError { expect: &Type, found: &Type, ) -> Self { - let name = readable_name(name); Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( format!("the type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), format!("{name}の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}") @@ -387,7 +386,6 @@ impl TyCheckError { expect: &Type, found: &Type, ) -> Self { - let name = readable_name(name); Self::new(ErrorCore::new(0, TypeError, loc, switch_lang!( format!("the return type of {name} is mismatched:\nexpected: {GREEN}{expect}{RESET}\nbut found: {RED}{found}{RESET}"), format!("{name}の戻り値の型が違います。\n予期した型: {GREEN}{expect}{RESET}\n与えられた型: {RED}{found}{RESET}") @@ -395,7 +393,6 @@ impl TyCheckError { } pub fn uninitialized_error(loc: Location, caused_by: Str, name: &str, t: &Type) -> Self { - let name = readable_name(name); Self::new( ErrorCore::new( 0, @@ -450,6 +447,15 @@ impl TyCheckError { ) } + pub fn dummy_infer_error(fn_name: &str, line: u32) -> Self { + Self::new(ErrorCore::unreachable(fn_name, line), "".into()) + } + + pub fn not_relation(fn_name: &str, line: u32) -> Self { + Self::new(ErrorCore::unreachable(fn_name, line), "".into()) + } + + pub fn reassign_error(loc: Location, caused_by: Str, name: &str) -> Self { let name = readable_name(name); Self::new( diff --git a/compiler/erg_compiler/eval.rs b/compiler/erg_compiler/eval.rs index 11967591..d44b54a1 100644 --- a/compiler/erg_compiler/eval.rs +++ b/compiler/erg_compiler/eval.rs @@ -38,9 +38,9 @@ impl SubstContext { } } - fn substitute(&self, quant_t: Type, ty_ctx: &Context, level: usize) -> TyCheckResult { + fn substitute(&self, quant_t: Type, ty_ctx: &Context, level: usize, ctx: &Context) -> TyCheckResult { let bounds = ty_ctx.type_params_bounds(); - let tv_ctx = TyVarContext::new(level, bounds); + let tv_ctx = TyVarContext::new(level, bounds, ctx); let (inst, _) = Context::instantiate_t(quant_t, tv_ctx); for param in inst.typarams() { self.substitute_tp(¶m, ty_ctx)?; @@ -355,7 +355,7 @@ impl Evaluator { if let Ok(obj) = ty_ctx.get_local(&Token::symbol(&rhs), &ctx.name) { if let ConstObj::Type(quant_t) = obj { let subst_ctx = SubstContext::new(&lhs, ty_ctx); - let t = subst_ctx.substitute(*quant_t, ty_ctx, level)?; + let t = subst_ctx.substitute(*quant_t, ty_ctx, level, ctx)?; let t = self.eval_t_params(t, ctx, level)?; return Ok(t); } else { @@ -363,9 +363,13 @@ impl Evaluator { } } } - todo!() + if let Some(outer) = &ctx.outer { + self.eval_t_params(Type::MonoProj { lhs, rhs }, outer, level) + } else { + todo!("{lhs}.{rhs} not found in {}", erg_common::fmt_iter(ctx.rec_sorted_type_ctxs(&lhs))) + } } - Type::Ref(l) => Ok(Type::refer(self.eval_t_params(*l, ctx, level)?)), + Type::Ref(l) => Ok(Type::ref_(self.eval_t_params(*l, ctx, level)?)), Type::RefMut(l) => Ok(Type::ref_mut(self.eval_t_params(*l, ctx, level)?)), Type::VarArgs(l) => Ok(Type::var_args(self.eval_t_params(*l, ctx, level)?)), Type::Poly { name, mut params } => { diff --git a/compiler/erg_compiler/hir.rs b/compiler/erg_compiler/hir.rs index aa766bde..cddca0e5 100644 --- a/compiler/erg_compiler/hir.rs +++ b/compiler/erg_compiler/hir.rs @@ -14,6 +14,8 @@ use erg_common::{ use erg_parser::ast::{fmt_lines, DefId, Params, VarName, VarPattern}; use erg_parser::token::{Token, TokenKind}; +use crate::error::readable_name; + #[derive(Debug, Clone)] pub struct Literal { pub data: ValueObj, // for constant folding @@ -26,10 +28,17 @@ impl HasType for Literal { fn ref_t(&self) -> &Type { &self.t } + fn ref_mut_t(&mut self) -> &mut Type { + &mut self.t + } #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl NestedDisplay for Literal { @@ -129,8 +138,8 @@ impl KwArg { #[derive(Debug, Clone)] pub struct Args { - pos_args: Vec, - kw_args: Vec, + pub pos_args: Vec, + pub kw_args: Vec, paren: Option<(Token, Token)>, } @@ -199,14 +208,6 @@ impl Args { self.kw_args.len() } - pub fn pos_args(&self) -> &[PosArg] { - &self.pos_args[..] - } - - pub fn kw_args(&self) -> &[KwArg] { - &self.kw_args[..] - } - pub fn push_pos(&mut self, pos: PosArg) { self.pos_args.push(pos); } @@ -284,9 +285,17 @@ impl HasType for Local { &self.t } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + &mut self.t + } + #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl Locational for Local { @@ -333,9 +342,17 @@ impl HasType for Attribute { &self.t } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + &mut self.t + } + #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl Attribute { @@ -369,9 +386,17 @@ impl HasType for Subscript { &self.t } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + &mut self.t + } + #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl Subscript { @@ -416,9 +441,21 @@ impl HasType for Accessor { } } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + match self { + Self::Local(n) | Self::SelfDot(n) => n.ref_mut_t(), + Self::Attr(a) => a.ref_mut_t(), + Self::Subscr(s) => s.ref_mut_t(), + } + } + #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl Accessor { @@ -440,11 +477,11 @@ impl Accessor { pub fn var_full_name(&self) -> Option { match self { - Self::Local(local) => Some(local.inspect().to_string()), + Self::Local(local) => Some(readable_name(local.inspect()).to_string()), Self::Attr(attr) => attr .obj .var_full_name() - .map(|n| n + "." + attr.name.inspect()), + .map(|n| n + "." + readable_name(attr.name.inspect())), Self::Subscr(_) | Self::SelfDot(_) => todo!(), } } @@ -473,9 +510,17 @@ impl HasType for Array { &self.t } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + &mut self.t + } + #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl NestedDisplay for Array { @@ -500,7 +545,7 @@ impl Array { guard: Option, ) -> Self { let elem_t = elems - .pos_args() + .pos_args .first() .map(|a| a.expr.t()) .unwrap_or_else(|| Type::free_var(level, Constraint::TypeOf(Type::Type))); @@ -530,6 +575,9 @@ impl HasType for Dict { fn ref_t(&self) -> &Type { todo!() } + fn ref_mut_t(&mut self) -> &mut Type { + todo!() + } fn t(&self) -> Type { todo!() } @@ -537,6 +585,10 @@ impl HasType for Dict { fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl NestedDisplay for Dict { @@ -568,7 +620,7 @@ pub struct BinOp { impl NestedDisplay for BinOp { fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, level: usize) -> fmt::Result { - writeln!(f, "`{}`:", self.op.content)?; + write!(f, "`{}`: {}:\n", self.op.content, self.sig_t)?; self.lhs.fmt_nest(f, level + 1)?; writeln!(f)?; self.rhs.fmt_nest(f, level + 1) @@ -580,6 +632,9 @@ impl HasType for BinOp { fn ref_t(&self) -> &Type { self.sig_t.return_t().unwrap() } + fn ref_mut_t(&mut self) -> &mut Type { + self.sig_t.mut_return_t().unwrap() + } #[inline] fn lhs_t(&self) -> &Type { self.sig_t.lhs_t() @@ -592,6 +647,10 @@ impl HasType for BinOp { fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + Some(&mut self.sig_t) + } } impl_display_from_nested!(BinOp); @@ -620,6 +679,9 @@ impl HasType for UnaryOp { fn ref_t(&self) -> &Type { self.sig_t.return_t().unwrap() } + fn ref_mut_t(&mut self) -> &mut Type { + self.sig_t.mut_return_t().unwrap() + } #[inline] fn lhs_t(&self) -> &Type { self.expr.ref_t() @@ -632,6 +694,10 @@ impl HasType for UnaryOp { fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + Some(&mut self.sig_t) + } } impl NestedDisplay for UnaryOp { @@ -678,6 +744,10 @@ impl HasType for Call { self.sig_t.return_t().unwrap() } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + self.sig_t.mut_return_t().unwrap() + } + #[inline] fn lhs_t(&self) -> &Type { self.sig_t.lhs_t() } @@ -689,6 +759,10 @@ impl HasType for Call { fn signature_t(&self) -> Option<&Type> { Some(&self.sig_t) } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + Some(&mut self.sig_t) + } } impl Locational for Call { @@ -723,6 +797,10 @@ impl HasType for Block { self.last().unwrap().ref_t() } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + self.last_mut().unwrap().ref_mut_t() + } + #[inline] fn t(&self) -> Type { self.last().unwrap().t() } @@ -730,6 +808,10 @@ impl HasType for Block { fn signature_t(&self) -> Option<&Type> { self.last().unwrap().signature_t() } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + self.last_mut().unwrap().signature_mut_t() + } } impl NestedDisplay for Block { @@ -810,7 +892,7 @@ pub struct Lambda { op: Token, pub body: Block, pub id: usize, - t: Type, + pub t: Type, } impl HasType for Lambda { @@ -819,9 +901,17 @@ impl HasType for Lambda { &self.t } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + &mut self.t + } + #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl NestedDisplay for Lambda { @@ -884,7 +974,7 @@ impl Signature { #[derive(Debug, Clone)] pub struct Decl { pub sig: Signature, - t: Type, + pub t: Type, } impl NestedDisplay for Decl { @@ -996,6 +1086,19 @@ impl HasType for Expr { _ => &Type::NoneType, } } + fn ref_mut_t(&mut self) -> &mut Type { + match self { + Expr::Lit(lit) => lit.ref_mut_t(), + Expr::Accessor(accessor) => accessor.ref_mut_t(), + Expr::Array(array) => array.ref_mut_t(), + Expr::Dict(dict) => dict.ref_mut_t(), + Expr::BinOp(bin) => bin.ref_mut_t(), + Expr::UnaryOp(unary) => unary.ref_mut_t(), + Expr::Call(call) => call.ref_mut_t(), + Expr::Lambda(lambda) => lambda.ref_mut_t(), + _ => todo!(), + } + } fn signature_t(&self) -> Option<&Type> { match self { Expr::BinOp(bin) => bin.signature_t(), @@ -1004,6 +1107,14 @@ impl HasType for Expr { _ => None, } } + fn signature_mut_t(&mut self) -> Option<&mut Type> { + match self { + Expr::BinOp(bin) => bin.signature_mut_t(), + Expr::UnaryOp(unary) => unary.signature_mut_t(), + Expr::Call(call) => call.signature_mut_t(), + _ => None, + } + } } impl Expr { diff --git a/compiler/erg_compiler/initialize.rs b/compiler/erg_compiler/initialize.rs index 3a544f18..4ef7703d 100644 --- a/compiler/erg_compiler/initialize.rs +++ b/compiler/erg_compiler/initialize.rs @@ -10,14 +10,13 @@ use Type::*; use erg_parser::ast::VarName; -use crate::context::{Context, DefaultInfo, ParamSpec}; +use crate::context::{Context, DefaultInfo, ParamSpec, ConstTemplate}; use crate::varinfo::{Mutability, VarInfo, VarKind, Visibility}; use DefaultInfo::*; use Mutability::*; use VarKind::*; use Visibility::*; -// NOTE: TyParam::MonoQuantVarは生成時に型を指定する必要があるが、逆にそちらがあれば型境界を指定しなくてもよい impl Context { fn register_decl(&mut self, name: &'static str, t: Type, vis: Visibility) { let name = VarName::from_static(name); @@ -47,6 +46,14 @@ impl Context { } } + fn register_const_param_defaults(&mut self, name: &'static str, params: Vec) { + if self.const_param_defaults.get(name).is_some() { + panic!("already registered: {name}"); + } else { + self.const_param_defaults.insert(Str::ever(name), params); + } + } + fn register_type(&mut self, t: Type, ctx: Self, muty: Mutability) { if self.types.contains_key(&t) { panic!("{} has already been registered", t.name()); @@ -57,7 +64,7 @@ impl Context { for impl_trait in ctx.super_traits.iter() { if !impl_trait.is_monomorphic() { if let Some(impls) = self.poly_trait_impls.get_mut(impl_trait.name()) { - impls.push(impl_trait.clone()); + impls.push((t.clone(), impl_trait.clone())); } else { self.poly_trait_impls .insert(Str::rc(impl_trait.name()), vec![impl_trait.clone()]); @@ -76,10 +83,10 @@ impl Context { self.locals .insert(name.clone(), VarInfo::new(Type, muty, Private, Builtin)); for method_name in ctx.locals.keys() { - if let Some(patches) = self._method_impl_patches.get_mut(method_name) { + if let Some(patches) = self.method_impl_patches.get_mut(method_name) { patches.push(name.clone()); } else { - self._method_impl_patches + self.method_impl_patches .insert(method_name.clone(), vec![name.clone()]); } } @@ -98,147 +105,108 @@ impl Context { } /// see std/prelude.er + /// All type boundaries are defined in each subroutine + /// `push_subtype_bound`, etc. are used for type boundary determination in user-defined APIs // 型境界はすべて各サブルーチンで定義する // push_subtype_boundなどはユーザー定義APIの型境界決定のために使用する fn init_builtin_traits(&mut self) { let named = Self::mono_trait("Named", vec![], Self::TOP_LEVEL); + // 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![], Self::TOP_LEVEL); - // __eq__: |Self <: Eq; R <: Eq()| Self(R).(R) -> Bool - let op_t = fn1_met(poly("Self", vec![ty_tp(mono_q("R"))]), mono_q("R"), Bool); + // __eq__: |Self <: Eq()| Self.(Self) -> Bool + let op_t = fn1_met(mono_q("Self"), mono_q("R"), Bool); let op_t = quant( op_t, - set! {subtype(mono_q("Self"), mono("Eq")), subtype(mono_q("R"), poly("Eq", vec![]))}, + set! { + subtype(mono_q("Self"), poly("Eq", vec![ty_tp(mono_q("R"))])), + static_instance("R", Type) + }, ); - eq.register_decl("__eq__", op_t, Public); - let mut ord = Self::poly_trait( - "Ord", + eq.register_decl("__eq__", op_t.clone(), Public); + let mut partial_ord = Self::poly_trait( + "PartialOrd", vec![PS::t("R", WithDefault)], - vec![mono("Eq")], + vec![poly("PartialEq", vec![ty_tp(mono_q("R"))])], Self::TOP_LEVEL, ); let op_t = fn1_met(poly("Self", vec![ty_tp(mono_q("R"))]), mono_q("R"), Bool); let op_t = quant( op_t, - set! {subtype(mono_q("Self"), mono("Ord")), subtype(mono_q("R"), poly("Ord", vec![]))}, + set! { + subtype(mono_q("Self"), poly("PartialOrd", vec![ty_tp(mono_q("R"))])), + static_instance("R", Type) + }, + ); + partial_ord.register_decl("__lt__", op_t.clone(), Public); + let ord = Self::mono_trait( + "Ord", + vec![poly("Eq", vec![]), poly("PartialOrd", vec![])], + Self::TOP_LEVEL, ); - ord.register_decl("__lt__", op_t, Public); let mut seq = Self::poly_trait( "Seq", vec![PS::t("T", NonDefault)], vec![poly("Output", vec![ty_tp(mono_q("T"))])], Self::TOP_LEVEL, ); - let self_t = poly_q("Self", vec![TyParam::t(mono_q("T"))]); + let self_t = mono_q("Self"); let t = fn0_met(self_t.clone(), Nat); - let t = quant(t, set! {subtype(self_t.clone(), mono("Seq"))}); + let t = quant(t, set! {subtype(self_t.clone(), poly("Seq", vec![TyParam::erased(Type)]))}); seq.register_decl("__len__", t, Public); let t = Type::fn1_met(self_t.clone(), Nat, mono_q("T")); let t = quant( t, - set! {subtype(self_t, mono("Seq")), static_instance("T", Type)}, + set! {subtype(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); 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, vec![], Self::TOP_LEVEL); - let (r, o) = (mono_q("R"), mono_q("O")); - let (r_bound, o_bound) = (static_instance("R", Type), static_instance("O", Type)); - let params = vec![PS::t("R", WithDefault), PS::t("O", WithDefault)]; - let ty_params = vec![mono_q_tp("R"), mono_q_tp("O")]; - let mut add = Self::poly_trait( - "Add", - params.clone(), - vec![ - poly("Output", vec![ty_tp(mono_q("R"))]), - poly("Output", vec![ty_tp(mono_q("O"))]), - ], - Self::TOP_LEVEL, - ); + let output = Self::poly_trait("Output", params.clone(), vec![], Self::TOP_LEVEL); + let r = mono_q("R"); + let r_bound = static_instance("R", Type); + let params = vec![PS::t("R", WithDefault)]; + let ty_params = vec![ty_tp(mono_q("R"))]; + let mut add = Self::poly_trait("Add", params.clone(), vec![ + poly("Output", vec![ty_tp(mono_q("R"))]), + ], Self::TOP_LEVEL); let self_bound = subtype( - poly_q("Self", ty_params.clone()), + mono_q("Self"), poly("Add", ty_params.clone()), ); - let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone()); - let op_t = quant(op_t, set! {r_bound.clone(), o_bound.clone(), self_bound}); + let op_t = fn1_met(poly_q("Self", ty_params.clone()), 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); - let mut sub = Self::poly_trait( - "Sub", - params.clone(), - vec![ - poly("Output", vec![ty_tp(mono_q("R"))]), - poly("Output", vec![ty_tp(mono_q("O"))]), - ], - Self::TOP_LEVEL, - ); + add.register_decl("AddO", Type, Public); + let mut sub = Self::poly_trait("Sub", params.clone(), vec![ + poly("Output", vec![ty_tp(mono_q("R"))]), + ], Self::TOP_LEVEL); let self_bound = subtype( - poly_q("Self", ty_params.clone()), + mono_q("Self"), poly("Sub", ty_params.clone()), ); - let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), o.clone()); - let op_t = quant(op_t, set! {r_bound, o_bound, self_bound}); + let op_t = fn1_met(poly_q("Self", ty_params.clone()), r.clone(), mono_proj(mono_q("Self"), "SubO")); + let op_t = quant(op_t, set! {r_bound.clone(), self_bound}); sub.register_decl("__sub__", op_t, Public); - let mut mul = Self::poly_trait( - "Mul", - params.clone(), - vec![ - poly("Output", vec![ty_tp(mono_q("R"))]), - poly("Output", vec![ty_tp(mono_q("O"))]), - ], - Self::TOP_LEVEL, - ); - let op_t = fn1_met(poly("Mul", ty_params.clone()), r.clone(), o.clone()); + sub.register_decl("SubO", Type, Public); + let mut mul = Self::poly_trait("Mul", params.clone(), vec![ + poly("Output", vec![ty_tp(mono_q("R"))]), + ], Self::TOP_LEVEL); + let op_t = fn1_met(poly("Mul", ty_params.clone()), r.clone(), mono_proj(mono_q("Self"), "MulO")); mul.register_decl("__mul__", op_t, Public); - let mut div = Self::poly_trait( - "Div", - params, - vec![ - poly("Output", vec![ty_tp(mono_q("R"))]), - poly("Output", vec![ty_tp(mono_q("O"))]), - ], - Self::TOP_LEVEL, - ); - let op_t = fn1_met(poly("Div", ty_params.clone()), r, o); + mul.register_decl("MulO", Type, Public); + let mut div = Self::poly_trait("Div", params.clone(), vec![ + poly("Output", vec![ty_tp(mono_q("R"))]), + ], Self::TOP_LEVEL); + let op_t = fn1_met(poly("Div", ty_params.clone()), r, mono_proj(mono_q("Self"), "DivO")); div.register_decl("__div__", op_t, Public); - /*let sup = poly( - "Add", - vec![ - mono_q_tp("Self"), - TyParam::mono_proj(mono_q_tp("Self"), "AddO"), - ], - ); - let mut closed_add = Self::mono_trait("SelfAdd", vec![sup], Self::TOP_LEVEL); - closed_add.register_decl("AddO", Type, Public); - let sup = poly( - "Sub", - vec![ - mono_q_tp("Self"), - TyParam::mono_proj(mono_q_tp("Self"), "SubO"), - ], - ); - let mut closed_sub = Self::mono_trait("SelfSub", vec![sup], Self::TOP_LEVEL); - closed_sub.register_decl("SubO", Type, Public); - let sup = poly( - "Mul", - vec![ - mono_q_tp("Self"), - TyParam::mono_proj(mono_q_tp("Self"), "MulO"), - ], - ); - let mut closed_mul = Self::mono_trait("SelfMul", vec![sup], Self::TOP_LEVEL); - closed_mul.register_decl("MulO", Type, Public); - let sup = Type::poly( - "Div", - vec![ - mono_q_tp("Self"), - TyParam::mono_proj(mono_q_tp("Self"), "DivO"), - ], - ); - let mut closed_div = Self::mono_trait("SelfDiv", vec![sup], Self::TOP_LEVEL); - closed_div.register_decl("DivO", Type, Public); - */ + div.register_decl("DivO", Type, Public); self.register_type(mono("Named"), named, Const); self.register_type(poly("Eq", vec![ty_tp(mono_q("R"))]), eq, Const); - self.register_type(poly("Ord", vec![ty_tp(mono_q("R"))]), ord, Const); + self.register_type(poly("PartialOrd", vec![ty_tp(mono_q("R"))]), partial_ord, Const); + self.register_type(mono("Ord"), ord, Const); self.register_type(poly("Seq", vec![ty_tp(mono_q("T"))]), seq, Const); self.register_type(poly("Input", vec![ty_tp(mono_q("T"))]), input, Const); self.register_type(poly("Output", vec![ty_tp(mono_q("T"))]), output, Const); @@ -247,6 +215,12 @@ impl Context { self.register_type(poly("Mul", ty_params.clone()), mul, Const); self.register_type(poly("Div", ty_params), div, Const); // self.register_type(mono("Num"), num, Const); + self.register_const_param_defaults("Eq", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]); + self.register_const_param_defaults("PartialOrd", vec![ConstTemplate::app("Self", vec![], vec![])]); + self.register_const_param_defaults("Add", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]); + self.register_const_param_defaults("Sub", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]); + self.register_const_param_defaults("Mul", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]); + self.register_const_param_defaults("Div", vec![ConstTemplate::Obj(ConstObj::t(mono_q("Self")))]); } fn init_builtin_classes(&mut self) { @@ -277,12 +251,12 @@ impl Context { vec![Obj], vec![ mono("Num"), + // mono("Eq"), // Float doesn't have an Eq implementation mono("Ord"), - mono("Eq"), - mono("Add"), - mono("Sub"), - mono("Mul"), - mono("Div"), + 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("Mutate"), ], Self::TOP_LEVEL, @@ -292,6 +266,10 @@ impl Context { 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", ConstObj::t(Float)); + float.register_const("SubO", ConstObj::t(Float)); + float.register_const("MulO", ConstObj::t(Float)); + float.register_const("DivO", ConstObj::t(Float)); float.register_impl("Real", Float, Const, Public); float.register_impl("Imag", Float, Const, Public); let mut ratio = Self::mono_class( @@ -299,12 +277,12 @@ impl Context { vec![Obj], vec![ mono("Num"), + poly("Eq", vec![ty_tp(Ratio)]), mono("Ord"), - mono("Eq"), - mono("Add"), - mono("Sub"), - mono("Mul"), - mono("Div"), + 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("Mutate"), ], Self::TOP_LEVEL, @@ -314,21 +292,25 @@ impl Context { 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", ConstObj::t(Ratio)); + ratio.register_const("SubO", ConstObj::t(Ratio)); + ratio.register_const("MulO", ConstObj::t(Ratio)); + ratio.register_const("DivO", ConstObj::t(Ratio)); ratio.register_impl("Real", Ratio, Const, Public); ratio.register_impl("Imag", Ratio, Const, Public); let mut int = Self::mono_class( "Int", vec![Obj], vec![ - poly("Add", vec![ty_tp(Int), ty_tp(Int)]), - poly("Sub", vec![ty_tp(Int), ty_tp(Int)]), - poly("Mul", vec![ty_tp(Int), ty_tp(Int)]), - poly("Div", vec![ty_tp(Int), ty_tp(Ratio)]), + 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"), mono("Rational"), mono("Integral"), - // mono("SelfOrd"), - // mono("SelfEq"), mono("Mutate"), ], Self::TOP_LEVEL, @@ -339,21 +321,25 @@ impl Context { 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", ConstObj::t(Int)); + int.register_const("SubO", ConstObj::t(Int)); + int.register_const("MulO", ConstObj::t(Int)); + int.register_const("DivO", ConstObj::t(Ratio)); int.register_impl("Real", Int, Const, Public); int.register_impl("Imag", Int, Const, Public); let mut nat = Self::mono_class( "Nat", vec![Int, Obj], vec![ - poly("Add", vec![ty_tp(Nat), ty_tp(Nat)]), - poly("Sub", vec![ty_tp(Nat), ty_tp(Int)]), - poly("Mul", vec![ty_tp(Nat), ty_tp(Nat)]), - poly("Div", vec![ty_tp(Nat), ty_tp(Ratio)]), + 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"), mono("Rational"), mono("Integral"), - // mono("SelfOrd"), - // mono("SelfEq"), mono("Mutate"), ], Self::TOP_LEVEL, @@ -374,6 +360,10 @@ impl Context { Immutable, Public, ); + nat.register_const("AddO", ConstObj::t(Nat)); + nat.register_const("SubO", ConstObj::t(Int)); + nat.register_const("MulO", ConstObj::t(Nat)); + nat.register_const("DivO", ConstObj::t(Ratio)); nat.register_impl("Real", Nat, Const, Public); nat.register_impl("Imag", Nat, Const, Public); let mut bool_ = Self::mono_class( @@ -383,8 +373,8 @@ impl Context { mono("Num"), mono("Rational"), mono("Integral"), - // mono("SelfOrd"), - // mono("SelfEq"), + poly("Eq", vec![ty_tp(Bool)]), + mono("Ord"), // mono("SelfAdd"), // mono("SelfSub"), // mono("SelfMul"), @@ -399,10 +389,12 @@ impl Context { "Str", vec![Obj], vec![ - mono("Eq"), + poly("Eq", vec![ty_tp(Str)]), + mono("Ord"), mono("Mutate"), poly("Seq", vec![ty_tp(Str)]), - poly("Add", vec![ty_tp(Str), ty_tp(Str)]), + poly("Add", vec![ty_tp(Str)]), + poly("Mul", vec![ty_tp(Nat)]) ], Self::TOP_LEVEL, ); @@ -418,12 +410,14 @@ impl Context { Immutable, Public, ); + str_.register_const("AddO", ConstObj::t(Str)); + str_.register_const("MulO", ConstObj::t(Str)); let mut array = Self::poly_class( "Array", vec![PS::t_nd("T"), PS::named_nd("N", Nat)], vec![Obj], vec![ - mono("Eq"), + poly("Eq", vec![ty_tp(Type::poly("Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")]))]), mono("Mutate"), poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))]), @@ -453,7 +447,10 @@ impl Context { let mut type_ = Self::mono_class( "Type", vec![Obj], - vec![mono("Eq"), mono("Named")], + vec![ + poly("Eq", vec![ty_tp(Type)]), + mono("Named") + ], Self::TOP_LEVEL, ); type_.register_impl( @@ -465,16 +462,18 @@ impl Context { let module = Self::mono_class( "Module", vec![Obj], - vec![mono("Eq"), mono("Named")], + vec![ + poly("Eq", vec![ty_tp(Module)]), + mono("Named") + ], Self::TOP_LEVEL, ); - let array_mut_t = Type::poly("Array!", vec![TyParam::t(mono_q("T")), mono_q_tp("N")]); + let array_mut_t = Type::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", NatMut)], - vec![Obj], + vec![poly("Range", vec![ty_tp(mono_q("T")), mono_q_tp("N")]), Obj], vec![ - mono("Eq"), mono("Mutate"), poly("Seq", vec![ty_tp(mono_q("T"))]), ], @@ -484,7 +483,7 @@ impl Context { Type::ref_mut(array_mut_t.clone()), Some(Type::ref_mut(poly( "Array!", - vec![TyParam::t(mono_q("T")), mono_q_tp("N") + value(1)], + vec![ty_tp(mono_q("T")), mono_q_tp("N") + value(1)], ))), vec![param_t("elem", mono_q("T"))], vec![], @@ -501,7 +500,7 @@ impl Context { vec![PS::t_nd("T")], vec![Obj], vec![ - mono("Eq"), + poly("Eq", vec![ty_tp(Type::poly("Range", vec![ty_tp(mono_q("T"))]))]), mono("Mutate"), poly("Seq", vec![ty_tp(mono_q("T"))]), poly("Output", vec![ty_tp(mono_q("T"))]), @@ -577,7 +576,7 @@ impl Context { fn init_builtin_procs(&mut self) { let t_print = nd_proc( - vec![param_t("objs", Type::var_args(Type::refer(Obj)))], + vec![param_t("objs", Type::var_args(Type::ref_(Obj)))], NoneType, ); let t_input = nd_proc(vec![param_t("msg", Str)], Str); @@ -616,37 +615,41 @@ impl Context { /* binary */ let l = mono_q("L"); let r = mono_q("R"); - let o = mono_q("O"); - let params = vec![mono_q_tp("R"), mono_q_tp("O")]; - let op_t = Type::func2(l.clone(), r.clone(), o.clone()); + let params = vec![ty_tp(mono_q("R"))]; + let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "AddO")); let op_t = quant( op_t, set! { static_instance("R", Type), - static_instance("O", Type), subtype(l.clone(), poly("Add", params.clone())) }, ); self.register_impl("__add__", op_t, Const, Private); - let op_t = Type::func2(l.clone(), r.clone(), o.clone()); + let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "SubO")); let op_t = quant( op_t, set! { static_instance("R", Type), - static_instance("O", Type), subtype(l.clone(), poly("Sub", params.clone())) }, ); self.register_impl("__sub__", op_t, Const, Private); - let op_t = Type::func2(l.clone(), r.clone(), o.clone()); - let op_t = quant(op_t, set! {subtype(l.clone(), poly("Mul", params.clone()))}); + let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "MulO")); + let op_t = quant(op_t, set! { + static_instance("R", Type), + subtype(l.clone(), poly("Mul", params.clone())) + }); self.register_impl("__mul__", op_t, Const, Private); - let op_t = Type::func2(l.clone(), r, o); - let op_t = quant(op_t, set! {subtype(l, poly("Mul", params))}); + let op_t = Type::func2(l.clone(), r.clone(), mono_proj(mono_q("L"), "DivO")); + let op_t = quant(op_t, set! { + static_instance("R", Type), + subtype(l, poly("Mul", params.clone())) + }); self.register_impl("__div__", op_t, Const, Private); let m = mono_q("M"); let op_t = Type::func2(m.clone(), m.clone(), m.clone()); let op_t = quant(op_t, set! {subtype(m, poly("Mul", vec![]))}); + // TODO: add bound: M == MulO self.register_impl("__pow__", op_t, Const, Private); let d = mono_q("D"); let op_t = Type::func2(d.clone(), d.clone(), d.clone()); @@ -659,7 +662,7 @@ impl Context { self.register_impl("__ne__", op_t, Const, Private); let o = mono_q("O"); let op_t = Type::func2(o.clone(), o.clone(), Bool); - let op_t = quant(op_t, set! {subtype(o, poly("Ord", vec![]))}); + let op_t = quant(op_t, set! {subtype(o, mono("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); @@ -675,7 +678,7 @@ impl Context { self.register_decl("__neg__", op_t, Private); let t = mono_q("T"); let op_t = Type::func2(t.clone(), t.clone(), Type::range(t.clone())); - let op_t = quant(op_t, set! {subtype(t, mono("Ord"))}); + let op_t = quant(op_t, set! {subtype(t.clone(), mono("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); @@ -704,17 +707,11 @@ impl Context { vec![ poly( "Add", - vec![ - TyParam::from(&o..=&p), - TyParam::from(m.clone() + o.clone()..=n.clone() + p.clone()), - ], + vec![TyParam::from(&o..=&p)], ), poly( "Sub", - vec![ - TyParam::from(&o..=&p), - TyParam::from(m.clone() - p.clone()..=n.clone() - o.clone()), - ], + vec![TyParam::from(&o..=&p)], ), ], Self::TOP_LEVEL, @@ -728,9 +725,11 @@ impl Context { let op_t = fn1_met( Type::from(&m..=&n), Type::from(&o..=&p), - Type::from(m - p..=n - o), + Type::from(m.clone() - p.clone()..=n.clone() - o.clone()), ); interval.register_impl("__sub__", op_t, Const, Public); + interval.register_const("AddO", ConstObj::t(Type::from(m.clone() + o.clone()..=n.clone() + p.clone()))); + interval.register_const("SubO", ConstObj::t(Type::from(m - p..=n - o))); self.register_patch("Interval", interval, Const); // eq.register_impl("__ne__", op_t, Const, Public); // ord.register_impl("__le__", op_t.clone(), Const, Public); diff --git a/compiler/erg_compiler/lower.rs b/compiler/erg_compiler/lower.rs index c4e765ed..3d4fc0f5 100644 --- a/compiler/erg_compiler/lower.rs +++ b/compiler/erg_compiler/lower.rs @@ -12,7 +12,7 @@ use erg_parser::ast; use erg_parser::ast::AST; use crate::context::{Context, ContextKind, RegistrationMode}; -use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings}; +use crate::error::{LowerError, LowerErrors, LowerResult, LowerWarnings, readable_name}; use crate::hir; use crate::hir::HIR; use crate::varinfo::Visibility; @@ -36,7 +36,7 @@ impl ASTLowerer { Some(Context::init_builtins()), vec![], vec![], - 0, + Context::TOP_LEVEL, ), errs: LowerErrors::empty(), warns: LowerWarnings::empty(), @@ -173,8 +173,8 @@ impl ASTLowerer { let obj = self.lower_expr(*call.obj, false)?; let t = self.ctx.get_call_t( &obj, - hir_args.pos_args(), - hir_args.kw_args(), + &hir_args.pos_args, + &hir_args.kw_args, &self.ctx.name, )?; Ok(hir::Call::new(obj, hir_args, t)) @@ -296,7 +296,7 @@ impl ASTLowerer { .outer .as_mut() .unwrap() - .import_mod(name, &call.args.pos_args().first().unwrap().expr)?; + .import_mod(name, &call.args.pos_args.first().unwrap().expr)?; } } else { todo!() @@ -395,6 +395,7 @@ impl ASTLowerer { } } let hir = HIR::new(ast.name, module); + let hir = self.ctx.deref_toplevel(hir)?; log!( "[DEBUG] {}() has completed, found errors: {}", fn_name!(), diff --git a/compiler/erg_compiler/ownercheck.rs b/compiler/erg_compiler/ownercheck.rs index 47a0280c..d331906e 100644 --- a/compiler/erg_compiler/ownercheck.rs +++ b/compiler/erg_compiler/ownercheck.rs @@ -143,15 +143,15 @@ impl OwnershipChecker { let (nd_ownerships, d_ownerships): (Vec<_>, Vec<_>) = non_defaults .iter() .enumerate() - .partition(|(i, _)| *i == call.args.pos_args().len()); + .partition(|(i, _)| *i == call.args.pos_args.len()); for (parg, (_, ownership)) in - call.args.pos_args().iter().zip(nd_ownerships.into_iter()) + call.args.pos_args.iter().zip(nd_ownerships.into_iter()) { self.check_expr(&parg.expr, *ownership); } for (kwarg, (_, ownership)) in call .args - .kw_args() + .kw_args .iter() .zip(d_ownerships.into_iter().chain(defaults.iter().enumerate())) { @@ -159,10 +159,10 @@ impl OwnershipChecker { } } ArgsOwnership::VarArgs(ownership) => { - for parg in call.args.pos_args().iter() { + for parg in call.args.pos_args.iter() { self.check_expr(&parg.expr, ownership); } - for kwarg in call.args.kw_args().iter() { + for kwarg in call.args.kw_args.iter() { self.check_expr(&kwarg.expr, ownership); } } @@ -178,12 +178,12 @@ impl OwnershipChecker { self.check_expr(&unary.expr, ownership); } Expr::Array(arr) => { - for a in arr.elems.pos_args().iter() { + for a in arr.elems.pos_args.iter() { self.check_expr(&a.expr, ownership); } } Expr::Dict(dict) => { - for a in dict.attrs.kw_args().iter() { + for a in dict.attrs.kw_args.iter() { // self.check_expr(&a.key); self.check_expr(&a.expr, ownership); } diff --git a/compiler/erg_compiler/varinfo.rs b/compiler/erg_compiler/varinfo.rs index 7db05a17..a55105b4 100644 --- a/compiler/erg_compiler/varinfo.rs +++ b/compiler/erg_compiler/varinfo.rs @@ -142,9 +142,17 @@ impl HasType for VarInfo { &self.t } #[inline] + fn ref_mut_t(&mut self) -> &mut Type { + &mut self.t + } + #[inline] fn signature_t(&self) -> Option<&Type> { None } + #[inline] + fn signature_mut_t(&mut self) -> Option<&mut Type> { + None + } } impl VarInfo { diff --git a/compiler/erg_parser/Cargo.toml b/compiler/erg_parser/Cargo.toml index 7c4ae782..321ec8fc 100644 --- a/compiler/erg_parser/Cargo.toml +++ b/compiler/erg_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "erg_parser" -version = "0.2.2" +version = "0.2.4" description = "The Erg parser" authors = ["mtshiba "] license = "MIT OR Apache-2.0" @@ -14,7 +14,7 @@ debug = [ "erg_common/debug" ] japanese = [ "erg_common/japanese" ] [dependencies] -erg_common = { version = "0.2.2", path = "../erg_common" } +erg_common = { version = "0.2.4", path = "../erg_common" } [lib] path = "lib.rs" diff --git a/compiler/erg_parser/lex.rs b/compiler/erg_parser/lex.rs index fd22cbdc..b2e3f612 100644 --- a/compiler/erg_parser/lex.rs +++ b/compiler/erg_parser/lex.rs @@ -42,6 +42,10 @@ impl Runnable for LexerRunner { #[inline] fn clear(&mut self) {} + fn exec(&mut self) -> Result<(), Self::Errs> { + todo!() + } + fn eval(&mut self, src: Str) -> Result { let lexer = Lexer::from_str(src); if cfg!(feature = "debug") { diff --git a/compiler/erg_parser/parse.rs b/compiler/erg_parser/parse.rs index 7be4a08c..94e62560 100644 --- a/compiler/erg_parser/parse.rs +++ b/compiler/erg_parser/parse.rs @@ -294,6 +294,10 @@ impl Runnable for ParserRunner { #[inline] fn clear(&mut self) {} + fn exec(&mut self) -> Result<(), Self::Errs> { + todo!() + } + fn eval(&mut self, src: Str) -> Result { let ast = self.parse_from_str(src)?; Ok(format!("{ast}")) diff --git a/doc/JA/syntax/08_procedure.md b/doc/JA/syntax/08_procedure.md index 961f4207..1cda8f4f 100644 --- a/doc/JA/syntax/08_procedure.md +++ b/doc/JA/syntax/08_procedure.md @@ -1,6 +1,6 @@ # プロシージャ -プロシージャは可変オブジェクトを取り扱う際に必要となるが、可変オブジェクトを引数に持てばプロシージャであるとは限らない。 +プロシージャは可変オブジェクトを取り扱う際に必要となりますが、可変オブジェクトを引数に持てばプロシージャであるとは限りません。 ```erg peek_str s: Str! = log s diff --git a/doc/JA/syntax/09_builtin_procs.md b/doc/JA/syntax/09_builtin_procs.md index a708c193..95dbdf96 100644 --- a/doc/JA/syntax/09_builtin_procs.md +++ b/doc/JA/syntax/09_builtin_procs.md @@ -2,8 +2,8 @@ ## id! -オブジェクトのユニークな識別番号を返す。 -純粋なErgの意味論の中では同一の構造を持つオブジェクトの間に差異を見出す事はできないが、実際のところ、オブジェクトはメモリ上の位置が異なる。`id!`はこの位置を表す数値を返す。 +オブジェクトのユニークな識別番号を返します。 +純粋なErgの意味論の中では同一の構造を持つオブジェクトの間に差異を見出す事はできませんが、実際のところ、オブジェクトはメモリ上の位置が異なります。`id!`はこの位置を表す数値を返します。 ```erg ``` diff --git a/doc/JA/syntax/11_tuple.md b/doc/JA/syntax/11_tuple.md index 4b2a9a64..3523e6a0 100644 --- a/doc/JA/syntax/11_tuple.md +++ b/doc/JA/syntax/11_tuple.md @@ -1,6 +1,6 @@ # タプル -タプルは配列と似ていますが、違う型のオブジェクトを保持することができます。 +タプルは配列と似ていますが、違う型のオブジェクトを保持できます。 このようなコレクションを非等質なコレクションと呼びます。対して等質なコレクションには配列、セットなどがあります。 ```erg @@ -25,7 +25,7 @@ t = 1, True, "a" i, b, s = t ``` -タプルは違う型のオブジェクトを保持することができますが、そのかわり配列のようなイテレーションができなくなります。 +タプルは違う型のオブジェクトを保持できますが、そのかわり配列のようなイテレーションができなくなります。 ```erg t: ({1}, {2}, {3}) = (1, 2, 3) diff --git a/doc/JA/syntax/13_record.md b/doc/JA/syntax/13_record.md index 80d8e86a..6bf2ac41 100644 --- a/doc/JA/syntax/13_record.md +++ b/doc/JA/syntax/13_record.md @@ -15,10 +15,10 @@ john["name"] # Error: john is not subscribable `.name`, `.age`の部分を属性、`"John"`, `21`の部分を属性値と呼びます。 JavaScriptのオブジェクトリテラルとの相違点は、文字列でアクセスできない点です。すなわち、属性は単なる文字列ではありません。 -これは、値へのアクセスをコンパイル時に決定するためと、辞書とレコードが別物であるためといった理由があります。つまり、`{"name": "John"}`はDict,`{name = "John"}`はレコードである。 -では、辞書とレコードはどう使い分ければいいのか。 -一般的にはレコードの使用を推奨する。レコードには、コンパイル時に要素が存在するかチェックされる、 __可視性(visibility)__ を指定できるなどのメリットがある。 -可視性の指定は、Java言語などでみられるpublic/privateの指定に相当する。詳しくは[可視性](./15_visibility.md)を参照。 +これは、値へのアクセスをコンパイル時に決定するためと、辞書とレコードが別物であるためといった理由があります。つまり、`{"name": "John"}`はDict,`{name = "John"}`はレコードです。 +では、辞書とレコードはどう使い分ければいいのでしょうか。 +一般的にはレコードの使用を推奨します。レコードには、コンパイル時に要素が存在するかチェックされる、 __可視性(visibility)__ を指定できるなどのメリットがあります。 +可視性の指定は、Java言語などでみられるpublic/privateの指定に相当します。詳しくは[可視性](./15_visibility.md)を参照してください。 ```erg a = {x = 1; .y = x + 1} @@ -27,9 +27,9 @@ a.x # AttributeError: x is private assert a.y == 2 ``` -上の例はJavaScriptに習熟している人間からすると奇妙かもしれないが、単に`x`と宣言すると外部からアクセスできない。`.`をつけると`.`でアクセスできるというわけである。 +上の例はJavaScriptに習熟している人間からすると奇妙かもしれませんが、単に`x`と宣言すると外部からアクセスできず、`.`をつけると`.`でアクセスできるというわけです。 -属性に対する明示的な型指定もできる。 +属性に対する明示的な型指定もできます。 ```erg anonymous = { @@ -39,7 +39,7 @@ anonymous = { anonymous.name.set! "John" ``` -レコードはメソッドも持てる。 +レコードはメソッドも持てます。 ```erg o = { @@ -52,8 +52,8 @@ o.inc!() assert o.i == 1 ``` -レコードに関して特筆すべき文法がある。レコードの属性値が全てクラス(構造型ではダメ)のとき、そのレコード自体が、自身の属性を要求属性とする型としてふるまうのである。 -このような型をレコード型と呼ぶ。詳しくは[レコード]の項を参照してほしい。 +レコードに関して特筆すべき文法があります。レコードの属性値が全てクラス(構造型ではダメです)のとき、そのレコード自体が、自身の属性を要求属性とする型としてふるまいます。 +このような型をレコード型と呼びます。詳しくは[レコード]の項を参照してください。 ```erg # レコード @@ -72,7 +72,7 @@ print! Named.name # Str ## レコードの分解 -レコードは以下のようにして分解することができる。 +レコードは以下のようにして分解できます。 ```erg record = {x = 1; y = 2} @@ -88,8 +88,8 @@ match point: {x = x; y = y; z = z} -> "({x}, {y}, {z})" ``` -また、レコードは属性と同名の変数があるとき、例えば`x = x`または`x = .x`を`x`に、`.x = .x`または`.x = x`を`.x`に省略することができる。 -ただし属性が一つのときはセットと区別するために`;`を付ける必要がある。 +また、レコードは属性と同名の変数があるとき、例えば`x = x`または`x = .x`を`x`に、`.x = .x`または`.x = x`を`.x`に省略できます。 +ただし、属性が一つのときはセットと区別するために`;`を付ける必要があります。 ```erg x = 1 @@ -106,7 +106,7 @@ tuple = {x} assert tuple.1 == 1 ``` -この構文を利用して、レコードを分解して変数に代入することができる。 +この構文を利用して、レコードを分解して変数に代入できます。 ```erg # same as `{x = x; y = y} = xy` @@ -121,7 +121,7 @@ assert b == 2 ## 空レコード -空のレコードは`{=}`で表される。空のレコードはUnitと同じく自身のクラスそのものでもある。 +空のレコードは`{=}`で表されます。空のレコードはUnitと同じく、自身のクラスそのものでもあります。 ```erg empty_record = {=} @@ -132,10 +132,10 @@ empty_record: Structural {=} {x = 3; y = 5}: Structural {=} ``` -空のレコードは空のDict`{:}`や空のセット`{}`とは異なる。特に`{}`とは意味が正反対なので注意が必要である(Pythonでは`{}`は空の辞書となっているが、Ergでは`!{:}`である)。 -列挙型としての`{}`は何も要素に含まない空虚な型である。`Never`型は、これをクラス化したものである。 -逆に、レコードクラスの`{=}`は要求インスタンス属性がないので、全てのオブジェクトがこれの要素になる。`Object`は、これのエイリアスである。 -`Object`(のパッチ)は`.__sizeof__`などの極めて基本的な提供メソッドを持つ。 +空のレコードは空のDict`{:}`や空のセット`{}`とは異なります。特に`{}`とは意味が正反対なので注意が必要です(Pythonでは`{}`は空の辞書となっているが、Ergでは`!{:}`です)。 +列挙型としての`{}`は何も要素に含まない空虚な型です。`Never`型は、これをクラス化したものです。 +逆に、レコードクラスの`{=}`は要求インスタンス属性がないので、全てのオブジェクトがこれの要素になります。`Object`は、これのエイリアスです。 +`Object`(のパッチ)は`.__sizeof__`などの極めて基本的な提供メソッドを持ちます。 ```erg AnyPatch = Patch Structural {=} @@ -145,13 +145,13 @@ AnyPatch = Patch Structural {=} Never = Class {} ``` -注意として、`{}`, `Never`型と構造的に等価な型・クラスは他に存在できず、ユーザーが`{}`, `Class {}`を右辺に指定して型を定義するとエラーとなる。 -これにより、例えば`1..10 or -10..-1`とするところを`1..10 and -10..-1`としてしまうようなミスを防ぐことができる。 -また、合成の結果`Object`となるような型(`Int and Str`など)を定義すると単に`Object`とするように警告が出る。 +注意として、`{}`, `Never`型と構造的に等価な型・クラスは他に存在できず、ユーザーが`{}`, `Class {}`を右辺に指定して型を定義するとエラーとなります。 +これにより、例えば`1..10 or -10..-1`とするところを`1..10 and -10..-1`としてしまうようなミスを防げます。 +また、合成の結果`Object`となるような型(`Int and Str`など)を定義すると、単に`Object`とするように警告が出ます。 ## インスタントブロック -Ergにはもう一つインスタントブロックという構文があるが、これは単に最後に評価した値を返すだけである。属性の保持はできない。 +Ergにはもう一つインスタントブロックという構文がありますが、これは単に最後に評価した値を返すだけです。属性の保持はできません。 ```erg x = @@ -166,8 +166,8 @@ y = ## データクラス -素のレコード(レコードリテラルで生成されたレコード)は、これ単体でメソッドを実装しようとすると、直接インスタンスに定義する必要がある。 -これは効率が悪く、さらに属性の数が増えていくとエラー表示などが見にくくなり使いにくい。 +素のレコード(レコードリテラルで生成されたレコード)は、これ単体でメソッドを実装しようとすると、直接インスタンスに定義する必要があります。 +これは効率が悪く、さらに属性の数が増えていくとエラー表示などが見にくくなり使いにくいです。 ```erg john = { @@ -180,8 +180,8 @@ john + 1 # TypeError: + is not implemented for {name = Str; age = Int; .greet! = Ref(Self).() => None; inc_age! = Ref!(Self).() => None}, Int ``` -そこで、このような場合はレコードクラスを継承するとよい。このようなクラスをデータクラスと呼ぶ。 -これについては[クラス](./type/04_class.md)の項で詳しく説明する。 +そこで、このような場合はレコードクラスを継承します。このようなクラスをデータクラスと呼びます。 +これについては[クラス](./type/04_class.md)の項で詳しく説明します。 ```erg Person = Inherit {name = Str; age = Nat} diff --git a/doc/JA/syntax/14_set.md b/doc/JA/syntax/14_set.md index bcd913f9..3dd485cc 100644 --- a/doc/JA/syntax/14_set.md +++ b/doc/JA/syntax/14_set.md @@ -18,7 +18,7 @@ assert {1, 2} and {2, 3} == {2} assert {1, 2} not {2} == {1} ``` -セットは等質なコレクションである。別のクラスのオブジェクトを共存させるためには等質化させなくてはならない。 +セットは等質なコレクションです。別のクラスのオブジェクトを共存させるためには、等質化させなくてはなりません。 ```erg s: {Int or Str} = {"a", 1, "b", -1} @@ -26,15 +26,15 @@ s: {Int or Str} = {"a", 1, "b", -1} ## 型としてのセット -セットは型としても扱える。このような型は __列挙型(Enum type)__ と呼ばれる。 +セットは型としても扱えます。このような型は __列挙型(Enum type)__ と呼ばれます。 ```erg i: {1, 2, 3} = 1 assert i in {1, 2, 3} ``` -セットの要素がそのまま型の要素になる。 -セット自身は違うことに注意してほしい。 +セットの要素がそのまま型の要素になります。 +セット自身は違うことに注意が必要です。 ```erg mut_set = {1, 2, 3}.into {Int; !3} diff --git a/doc/JA/syntax/18_ownership.md b/doc/JA/syntax/18_ownership.md index 2580faf7..34e7be1c 100644 --- a/doc/JA/syntax/18_ownership.md +++ b/doc/JA/syntax/18_ownership.md @@ -1,13 +1,13 @@ # 所有権システム -ErgはPythonをホスト言語にした言語であるため、メモリ管理の方法はPythonの処理系に依存している。 -しかし意味論的には、Ergのメモリ管理はPythonのそれとは別物である。顕著な違いは、所有権システムと循環参照の禁止に現れている。 +ErgはPythonをホスト言語にした言語であるため、メモリ管理の方法はPythonの処理系に依存しています。 +しかし、意味論的にはErgのメモリ管理はPythonのそれとは別物です。顕著な違いは、所有権システムと循環参照の禁止に現れています。 ## 所有権 -ErgはRustから影響を受けた所有権システムを持っている。 -Rustの所有権システムは一般的に難解だと言われているが、Ergのそれは直感的になるよう簡略化されている。 -Ergでは __可変オブジェクト__ に所有権がついており、所有権を失った後はそのオブジェクトを参照できない。 +ErgはRustから影響を受けた所有権システムを持っています。 +Rustの所有権システムは一般的に難解だと言われていますが、Ergのそれは直感的になるよう簡略化されています。 +Ergでは __可変オブジェクト__ に所有権がついており、所有権を失った後はそのオブジェクトを参照できません。 ```erg v = [1, 2, 3].into [Int; !3] @@ -22,17 +22,17 @@ print! v # error: v was moved print! w # [1, 2, 3, 4] ``` -所有権の移動はオブジェクトをサブルーチンに渡したときなどに発生する。 -渡した後も所有権をまだ持っていたい場合は、複製(cloning)、凍結(freeze)、または借用(borrowing)をする必要がある。 -ただし後述するように借用はできる場面が限られている。 +所有権の移動はオブジェクトをサブルーチンに渡したときなどに発生します。 +渡した後も所有権をまだ持っていたい場合は、複製(cloning)、凍結(freeze)、または借用(borrowing)をする必要があります。 +ただし、後述するように借用はできる場面が限られています。 ## 複製 -オブジェクトを複製してその所有権を移す。実引数に`.clone`メソッドを適用することで行う。 -複製したオブジェクトは複製元のオブジェクトと全く同一になるが、互いに独立しているので、変更の影響は受けない。 +オブジェクトを複製してその所有権を移します。実引数に`.clone`メソッドを適用することで行います。 +複製したオブジェクトは複製元のオブジェクトと全く同一になりますが、互いに独立しているので、変更の影響は受けません。 -複製はPythonのディープコピーに相当し、同一のオブジェクトをまるごと作り直すので、凍結・借用と比べて一般に計算コスト、メモリコストが高い。 -オブジェクトを複製する必要があるようなサブルーチンは、「引数を消費する」サブルーチンという。 +複製はPythonのディープコピーに相当し、同一のオブジェクトをまるごと作り直すので、凍結・借用と比べて一般に計算コスト、メモリコストが高くなります。 +オブジェクトを複製する必要があるようなサブルーチンは、「引数を消費する」サブルーチンといいます。 ```erg capitalize s: Str! = @@ -46,10 +46,10 @@ log s2, s1 # !"HELLO hello" ## 凍結 -不変オブジェクトは複数の場所から参照できることを利用して、可変オブジェクトを不変オブジェクトに変換してしまう。 -これを凍結という。凍結は可変配列からイテレータを作るときなどで使われる。 -可変配列からは直接イテレータを作ることができないので、不変配列に変換するのである。 -配列を壊したくない場合は、[`.freeze_map`メソッド](./type/mut.md)等を使う。 +不変オブジェクトは複数の場所から参照できることを利用して、可変オブジェクトを不変オブジェクトに変換します。 +これを凍結といいます。凍結は可変配列からイテレータを作るときなどで使われます。 +可変配列からは直接イテレータを作ることができないので、不変配列に変換します。 +配列を壊したくない場合は、[`.freeze_map`メソッド](./type/mut.md)等を使います。 ```erg # イテレータが出す値の合計を計算する @@ -66,8 +66,8 @@ y # この後もyは触れられる ## 借用 -借用は複製や凍結よりも低コストである。 -以下のような単純な場合では、借用を行える。 +借用は複製や凍結よりも低コストです。 +以下のような単純な場合では、借用を行えます。 ```erg peek_str ref(s: Str!) = @@ -77,8 +77,8 @@ s = !"hello" peek_str s ``` -借用した値は元のオブジェクトに対する __参照__ と呼ばれる。 -参照をまた別のサブルーチンに渡す「又貸し」はできるが、借りているだけなので消費することはできない。 +借用した値は元のオブジェクトに対する __参照__ と呼ばれます。 +参照をまた別のサブルーチンに渡す「又貸し」はできますが、借りているだけなので消費することはできません。 ```erg steal_str ref(s: Str!) = @@ -96,14 +96,14 @@ steal_str ref(s: Str!) = x ``` -Ergの参照はRustより制約が強い。参照は言語上第一級のオブジェクトであるが、明示的に生成することはできず、`ref`/`ref!`によって実引数の渡し方として指定できるのみである。 -これは、参照を配列に詰めたり参照を属性とするクラスを作ったりはできないということを意味する。 +Ergの参照はRustより制約が強いです。参照は言語上第一級のオブジェクトですが、明示的に生成することはできず、`ref`/`ref!`によって実引数の渡し方として指定できるのみです。 +これは、参照を配列に詰めたり参照を属性とするクラスを作ったりはできないということを意味します。 -とはいえ、このような制約はそもそも参照のない言語では当たり前の仕様であり、そこまで不便となることはない。 +とはいえ、このような制約はそもそも参照のない言語では当たり前の仕様であり、そこまで不便となることはありません。 ## 循環参照 -Ergでは意図せずメモリリークを起こせないように設計されており、メモリーチェッカーが循環参照を検知するとエラーを出す。ほとんどの場合、このエラーは弱参照`Weak`で解消できる。しかしこれでは巡回グラフなどの循環構造を持つオブジェクトを生成できないため、unsafe操作として循環参照を生成できるAPIを実装予定である。 +Ergでは意図せずメモリリークを起こせないように設計されており、メモリーチェッカーが循環参照を検知するとエラーを出します。ほとんどの場合、このエラーは弱参照`Weak`で解消できます。しかし、これでは巡回グラフなどの循環構造を持つオブジェクトを生成できないため、unsafe操作として循環参照を生成できるAPIを実装予定です。

Previous | Next diff --git a/doc/JA/syntax/20_naming_rule.md b/doc/JA/syntax/20_naming_rule.md index 7605f0f7..82c33236 100644 --- a/doc/JA/syntax/20_naming_rule.md +++ b/doc/JA/syntax/20_naming_rule.md @@ -1,6 +1,6 @@ # 命名規則 -変数を定数式として使いたい場合は大文字で始まらなくてはならない。二文字以降は小文字でもよい。 +変数を定数式として使いたい場合は、必ず大文字で始めます。二文字以降は小文字でもよいです。 ```erg i: Option Type = Int @@ -9,8 +9,8 @@ match i: None -> log "None" ``` -副作用のあるオブジェクトは`!`で終わらなくてはならない。プロシージャとプロシージャルメソッド、そして可変型である。 -ただし、`Proc`型自体は可変型ではない。 +副作用のあるオブジェクトは、必ず`!`で終わります。プロシージャとプロシージャルメソッド、そして可変型です。 +ただし、`Proc`型自体は可変型ではありません。 ```erg # Callable == Func or Proc @@ -20,7 +20,7 @@ match c: f -> log "func" ``` -属性を外部に公開したい場合は、`.`を始めにつけて定義する。`.`を初めにつけなかった場合非公開となる。混乱を避けるため同一のスコープ内で共存はできない。 +属性を外部に公開したい場合は、初めに`.`をつけて定義します。`.`を初めにつけなかった場合は非公開になります。混乱を避けるため同一のスコープ内で共存はできません。 ```erg o = {x = 1; .x = 2} # SyntaxError: private and public variables with the same name cannot coexist @@ -28,17 +28,17 @@ o = {x = 1; .x = 2} # SyntaxError: private and public variables with the same na ## リテラル識別子(Literal Identifiers) -以上の規則は、文字列をシングルクォート('')で囲むと回避できる。すなわち、プロシージャルオブジェクトも`!`をつけずに代入することができる。ただしこの場合、値が定数式でも定数とはみなされない。 -このようにシングルクォートで囲まれた文字列による識別子をリテラル識別子という。 -これは、Pythonなど他言語のAPI(FFI)を呼び出す際に使う。 +以上の規則は、文字列をシングルクォート('')で囲むと回避できます。すなわち、プロシージャルオブジェクトも`!`をつけずに代入することができます。ただしこの場合、値が定数式でも定数とはみなされません。 +このようにシングルクォートで囲まれた文字列による識別子をリテラル識別子といいます。 +これは、Pythonなど他言語のAPI(FFI)を呼び出す際に使います。 ```erg bar! = pyimport("foo").'bar' ``` -Ergでも有効な識別子の場合は、''で囲む必要はない。 +Ergでも有効な識別子の場合は、''で囲む必要はありません。 -さらに、リテラル識別子中では記号も空白も入れることができるため、通常は識別子として使えない文字列を識別子として使うことができる。 +さらに、リテラル識別子中では記号も空白も入れることができるため、通常は識別子として使えない文字列を識別子として使うことができます。 ```erg '∂/∂t' y diff --git a/doc/JA/syntax/21_lambda.md b/doc/JA/syntax/21_lambda.md index b3089978..f99d9c25 100644 --- a/doc/JA/syntax/21_lambda.md +++ b/doc/JA/syntax/21_lambda.md @@ -1,6 +1,6 @@ # 無名関数(anonymous function) -無名関数は、関数オブジェクトを名付けずその場で生成するための文法である。 +無名関数は、関数オブジェクトを名付けずその場で生成するための文法です。 ```erg # `->`は無名関数演算子 @@ -10,22 +10,22 @@ f = (x, y) -> x + y g = (x, y: Int): Int -> x + y ``` -引数が1つの場合は`()`を省略できる。 +引数が1つの場合は`()`を省略できます。 ```erg assert [1, 2, 3].map_collect(i -> i + 1) == [2, 3, 4] assert ((i, j) -> [i, j])(1, 2) == [1, 2] ``` -下の場合`0..9, (i -> ...)`であって`(0..9, i) -> ...`ではない。 -`->`は左辺に一つだけ引数をとる。複数の引数は一つのタプルとして受け取る。 +下の場合`0..9, (i -> ...)`であって`(0..9, i) -> ...`ではありません。 +`->`は左辺に一つだけ引数をとります。複数の引数は一つのタプルとして受け取ります。 ```erg for 0..9, i: Int -> ... ``` -無名関数では、空白による構文解釈の差異が存在する。 +無名関数では、空白による構文解釈の差異が存在します。 ```erg # この場合は`T(() -> Int)`と解釈される @@ -34,16 +34,17 @@ i: T () -> Int k: U() -> Int ``` -無名関数は引数なしでも使える。`=>`は無名プロシージャ演算子。 +無名関数は引数なしでも使えます。 ```erg +# `=>`は無名プロシージャ演算子 p! = () => print! "`p!` was called" # `() ->`, `() =>`には`do`, `do!`という糖衣構文がある # p! = do! print! "`p!` was called" p!() # `p!` was called ``` -引数なし関数は遅延初期化に使える。 +引数なし関数は遅延初期化に使えます。 ```erg time = import "time" @@ -55,8 +56,8 @@ now = if! True: do date.new("1970", "1", "1", "00", "00") ``` -型付け、パターンマッチもできる。このため、`match`関数はほとんど無名関数の力で実現されている。 -`match`関数の引数に与える無名関数は上から順番にトライされる。ので、上の方は特殊なケースを、下に行くほど一般的なケースを記述する必要がある。順番を間違えると(可能な限り)コンパイラがWarningを出す。 +型付け、パターンマッチもできます。このため、`match`関数はほとんど無名関数の力で実現されています。 +`match`関数の引数に与える無名関数は上から順番にトライされます。なので、上の方は特殊なケースを、下に行くほど一般的なケースを記述する必要があります。順番を間違えると(可能な限り)コンパイラがWarningを出します。 ```erg n = (Complex or Ratio or Int).sample!() @@ -68,7 +69,7 @@ i = match n: _ -> panic "cannot convert to Int" # 以上のいずれにも該当しない場合。matchは全パターンを網羅していなくてはならない ``` -エラーハンドリングも`?`か`match`を使用して行うのが一般的である。 +エラーハンドリングも`?`か`match`を使用して行うのが一般的です。 ```erg res: ParseResult Int diff --git a/doc/JA/syntax/22_subroutine.md b/doc/JA/syntax/22_subroutine.md index 52289780..486d95f0 100644 --- a/doc/JA/syntax/22_subroutine.md +++ b/doc/JA/syntax/22_subroutine.md @@ -16,7 +16,7 @@ some_proc!: (T, U) => V ## Func Method -メソッド型は、外部からは`Self`で指定できない。 +メソッド型は、外部からは`Self`で指定できません。 ```erg .some_method(self, x: T, y: U) => () @@ -26,7 +26,7 @@ some_proc!: (T, U) => V ## Proc Method (dependent) -以下で、型`T!`は`N: Nat`という型引数を取るとする。外部から指定する場合は型変数を使用する。 +以下で、型`T!`は`N: Nat`という型引数を取るとします。外部から指定する場合は型変数を使用します。 ```erg T!: Nat -> Type @@ -34,10 +34,10 @@ T!: Nat -> Type T!(N).some_method!: (Ref! T!(N ~> N+X), X: Nat) => () ``` -注意として、`.some_method`の型は`|N, X: Nat| Ref!(T(N ~> N+X)).({X}) => ()`となる。 -`ref!`がついていない、すなわち適用後所有権が奪われるメソッドでは、型引数の遷移(`~>`)を使用できない。 +注意として、`.some_method`の型は`|N, X: Nat| Ref!(T(N ~> N+X)).({X}) => ()`となります。 +`ref!`がついていない、すなわち適用後所有権が奪われるメソッドでは、型引数の遷移(`~>`)を使用できません。 -所有権が奪われる場合は以下のようになる。 +所有権が奪われる場合は以下のようになります。 ```erg # Nを使わないなら_で省略可 @@ -47,8 +47,8 @@ T!(N).some_method!: (Ref! T!(N ~> N+X), X: Nat) => () ## Operator -``で囲むことで通常の関数と同じように定義できる。 -`and`や`or`などの中置アルファベット演算子は囲むことで中置演算子として定義できる。 +``で囲むことで通常の関数と同じように定義できます。 +`and`や`or`などの中置アルファベット演算子は囲むことで中置演算子として定義できます。 ```erg and(x, y, z) = x and y and z diff --git a/doc/JA/syntax/23_closure.md b/doc/JA/syntax/23_closure.md index df76fac1..5d0408a6 100644 --- a/doc/JA/syntax/23_closure.md +++ b/doc/JA/syntax/23_closure.md @@ -1,6 +1,6 @@ # クロージャ -Ergのサブルーチンには、外部変数を捕捉する「クロージャ」という機能がある。 +Ergのサブルーチンには、外部変数を捕捉する「クロージャ」という機能があります。 ```erg outer = 1 @@ -8,7 +8,7 @@ f x = outer + x assert f(1) == 2 ``` -不変オブジェクトと同じく、可変オブジェクトも捕捉できる。 +不変オブジェクトと同じく、可変オブジェクトも捕捉できます。 ```erg sum = !0 @@ -22,8 +22,8 @@ p!(1) assert sum == 46 ``` -しかし、関数は可変オブジェクトを捕捉できないので注意が必要である。 -仮に可変オブジェクトが関数内で参照できると、以下のようなコードが書けてしまう。 +しかし、関数は可変オブジェクトを捕捉できないので注意が必要です。 +仮に可変オブジェクトが関数内で参照できると、以下のようなコードが書けてしまいます。 ```erg # !!! このコードは実際にはエラーになる !!! @@ -34,10 +34,10 @@ i.add! 1 assert f 1 == 2 ``` -関数は同じ引数に対して同じ値を返すべきだが、その前提が破れてしまっている。 -`i`は呼び出し時に初めて評価されることに注意してほしい。 +関数は同じ引数に対して同じ値を返すべきですが、その前提が破れてしまっています。 +`i`は呼び出し時に初めて評価されることに注意してください。 -関数定義時点での可変オブジェクトの内容がほしい場合は`.clone`する。 +関数定義時点での可変オブジェクトの内容がほしい場合は`.clone`を呼び出します。 ```erg i = !0 @@ -58,7 +58,7 @@ for! 1..10, i => assert sum == 45 ``` -上と同等のプログラムは、Pythonでは以下のように記述できる。 +上と同等のプログラムは、Pythonでは以下のように記述できます。 ```python # Python @@ -68,8 +68,8 @@ for i in range(1, 10): assert sum == 45 ``` -しかしErgではもっとシンプルな書き方を推奨する。 -サブルーチンと可変オブジェクトを使って状態を持ち回す代わりに、関数を使用する状態を局所化するスタイルである。これは関数型プログラミングと呼ばれる。 +しかし、Ergではもっとシンプルな書き方を推奨します。 +サブルーチンと可変オブジェクトを使って状態を持ち回す代わりに、関数を使用する状態を局所化するスタイルを使います。これは関数型プログラミングと呼ばれます。 ```erg # Functional style @@ -77,11 +77,11 @@ sum = (1..10).sum() assert sum == 45 ``` -上のコードは先程と全く同じ結果となるが、こちらのほうが遥かにシンプルであることが見て取れる。 +上のコードは先程と全く同じ結果になりますが、こちらのほうが遥かにシンプルであることが見て取れます。 -`fold`関数を使用すれば、合計以外にも多様な操作を行うことができる。 -`fold`はイテレータのメソッドで、各イテレーションごとに引数`f`を実行する。 -結果を蓄積するカウンタの初期値は`init`で指定し、`acc`に蓄積されていく。 +`fold`関数を使用すれば、合計以外にも多様な操作を行うことができます。 +`fold`はイテレータのメソッドで、各イテレーションごとに引数`f`を実行します。 +結果を蓄積するカウンタの初期値は`init`で指定し、`acc`に蓄積されていきます。 ```erg # start with 0, result will @@ -89,7 +89,7 @@ sum = (1..10).fold(init: 0, f: (acc, i) -> acc + i) assert sum == 45 ``` -Ergは不変オブジェクトによるプログラミングで自然と簡潔な記述となるように設計されている。 +不変オブジェクトによるプログラミングで自然と簡潔な記述となるように、Ergは設計されています。

Previous | Next diff --git a/doc/JA/syntax/25_object_system.md b/doc/JA/syntax/25_object_system.md index f6a7e764..b2a840e8 100644 --- a/doc/JA/syntax/25_object_system.md +++ b/doc/JA/syntax/25_object_system.md @@ -1,19 +1,19 @@ # Object(対象体) -変数に代入できる全てのデータ。`Object`クラスの持つ属性は以下の通り。 +変数に代入できる全てのデータです。`Object`クラスの持つ属性は以下の通りです。 -* `.__repr__`: オブジェクトの(リッチでない)文字列表現を返す -* `.__sizeof__`: オブジェクトのサイズ(ヒープ確保分含む)を返す -* `.__dir__`: オブジェクトの属性を一覧にして返す -* `.__hash__`: オブジェクトのハッシュ値を返す -* `.__getattribute__`: オブジェクトの属性を取得して返す -* `.clone`: オブジェクトのクローン(メモリ上に独立な実体を持つ)を生成して返す -* `.copy`: オブジェクトのコピー(メモリ上で同じものをさす)を返す +* `.__repr__`: オブジェクトの(リッチでない)文字列表現を返します +* `.__sizeof__`: オブジェクトのサイズ(ヒープ確保分含む)を返します +* `.__dir__`: オブジェクトの属性を一覧にして返します +* `.__hash__`: オブジェクトのハッシュ値を返します +* `.__getattribute__`: オブジェクトの属性を取得して返します +* `.clone`: オブジェクトのクローン(メモリ上に独立な実体を持つ)を生成して返します +* `.copy`: オブジェクトのコピー(メモリ上で同じものをさす)を返します ## Record(レコード) -レコードリテラル(`{attr = value; ...}`)で生成されるオブジェクト。 -このオブジェクトは`.clone`や`.__sizeof__`などの基本的なメソッドを持つ。 +レコードリテラル(`{attr = value; ...}`)で生成されるオブジェクトです。 +このオブジェクトは`.clone`や`.__sizeof__`などの基本的なメソッドを持ちます。 ```erg obj = {.x = 1} @@ -25,7 +25,7 @@ assert obj2.x == 1 and obj2.y == 2 ## Attribute(属性) -オブジェクトと関連付けられたオブジェクト。特に自身(`self`)を暗黙の第一引数にとるサブルーチン属性はメソッド(method)と呼ばれる。 +オブジェクトと関連付けられたオブジェクトです。特に自身(`self`)を暗黙の第一引数にとるサブルーチン属性はメソッド(method)と呼ばれます。 ```erg # private_attrには`.`がないことに注意 @@ -37,45 +37,45 @@ assert record.method() == 3 ## Element(要素) -特定の型に属するオブジェクト(e.g. `1`は`Int`型の要素)。全てのオブジェクトは、少なくとも`{=}`型の要素である。 -クラスの要素の場合特にインスタンス(Instance)と呼ぶこともある。 +特定の型に属するオブジェクト(e.g. `1`は`Int`型の要素)です。全てのオブジェクトは、少なくとも`{=}`型の要素です。 +クラスの要素の場合特にインスタンス(Instance)と呼ぶこともあります。 ## Subroutine(サブルーチン) -関数またはプロシージャのインスタンスであるオブジェクトを示す(メソッドも含む)。サブルーチンを表すクラスは`Subroutine`である。 -より一般に`.__call__`を実装するオブジェクトは`Callable`(呼び出し可能オブジェクト)と呼ばれる。 +関数またはプロシージャのインスタンスであるオブジェクトを示す(メソッドも含む)。サブルーチンを表すクラスは`Subroutine`です。 +より一般に`.__call__`を実装するオブジェクトは`Callable`(呼び出し可能オブジェクト)と呼ばれます。 ## Callable(呼び出し可能オブジェクト) -`.__call__`を実装するオブジェクト。`Subroutine`のスーパークラス。 +`.__call__`を実装するオブジェクトです。`Subroutine`のスーパークラスでもあります。 ## Type(型) -要求属性を定義し、オブジェクトを共通化するオブジェクト。 -大きく分けて多相型(Polymorphic Type)と単相型(Monomorphic Type)の2つがある。典型的な単相型は`Int`, `Str`などで、多相型には`Option Int`, `[Int; 3]`などがある。 -さらにオブジェクトの状態変更をするメソッドを定義した型は可変型(Mutable type)と呼ばれ、可変な属性に`!`をつける必要がある(e.g. 動的配列: `[T; !_]`)。 +要求属性を定義し、オブジェクトを共通化するオブジェクトです。 +大きく分けて多相型(Polymorphic Type)と単相型(Monomorphic Type)の2つがあります。典型的な単相型は`Int`, `Str`などで、多相型には`Option Int`, `[Int; 3]`などがあります。 +さらにオブジェクトの状態変更をするメソッドを定義した型は可変型(Mutable type)と呼ばれ、可変な属性に`!`をつける必要があります(e.g. 動的配列: `[T; !_]`)。 ## Class(クラス) -`.__new__`, `.__init__`メソッドなどを持つ型。クラスベースのオブジェクト指向を実現する。 +`.__new__`, `.__init__`メソッドなどを持つ型です。クラスベースのオブジェクト指向を実現します。 ## Function(関数、写像) -外部変数(静的変数除く)のread権限はあるが、外部変数のread/write権限がないサブルーチン。つまり、外部に副作用を及ぼせない。 -Ergの関数(Function)は副作用を許さないのでPythonのそれとは定義が異なる。 +外部変数(静的変数除く)のread権限はありますが、外部変数のread/write権限がないサブルーチンです。つまり、外部に副作用を及ぼせません。 +Ergの関数(Function)は副作用を許さないので、Pythonのそれとは定義が異なります。 -## Procedure(手続) +## Procedure(手続き) -外部変数のread権限および`self`、静的変数のread/write権限があり、全てのサブルーチンの使用が許可されている。外部に副作用を及ぼせる。 +外部変数のread権限および`self`、静的変数のread/write権限があり、全てのサブルーチンの使用が許可されています。外部に副作用を及ぼせます。 ## Method(メソッド) -第一引数に`self`を暗黙的にとるサブルーチン。単なる関数/プロシージャとは別の型となっている。 +第一引数に`self`を暗黙的にとるサブルーチンです。単なる関数/プロシージャとは別の型となっています。 ## Entity(エンティティ) -サブルーチンおよび型ではないオブジェクト。 -単相型エンティティ(`1`, `"a"`など)は値オブジェクト、多相型エンティティ(`[1, 2, 3], {"a": 1}`)はコンテナオブジェクトとも呼ばれる。 +サブルーチンおよび型ではないオブジェクトです。 +単相型エンティティ(`1`, `"a"`など)は値オブジェクト、多相型エンティティ(`[1, 2, 3], {"a": 1}`)はコンテナオブジェクトとも呼ばれます。

Previous | Next diff --git a/doc/JA/syntax/26_pattern_matching.md b/doc/JA/syntax/26_pattern_matching.md index 7da4a6fc..46bd341b 100644 --- a/doc/JA/syntax/26_pattern_matching.md +++ b/doc/JA/syntax/26_pattern_matching.md @@ -11,6 +11,7 @@ i = 1 i: Int = 1 # with anonymous type i: {1, 2, 3} = 2 + # function fn x = x + 1 # equals @@ -18,6 +19,7 @@ fn x: Add(Int) = x + 1 # (anonymous) function fn = x -> x + 1 fn: Int -> Int = x -> x + 1 + # higher-order type a: [Int; 4] = [0, 1, 2, 3] # or @@ -27,14 +29,16 @@ a: Array Int, 4 = [0, 1, 2, 3] ### リテラルパターン ```erg -# if `i` cannot be determined to be 1 at compile time, TypeError occurs. -# short hand of `_: {1} = i` +# もし`i`がコンパイル時に1と判断できない場合は、TypeErrorが発生する。 +# `_: {1} = i`を省略したもの 1 = i + # simple pattern matching match x: 1 -> "1" 2 -> "2" _ -> "other" + # fibonacci function fib 0 = 0 fib 1 = 1 @@ -61,8 +65,8 @@ name = match num: ### 篩パターン ```erg +# この2つは同じ Array(T, N: {N | N >= 3}) -# == Array(T, N | N >= 3) f M, N | M >= 0, N >= 1 = ... @@ -80,7 +84,7 @@ right(_, r) = r ### 可変長パターン -後述するタプル/配列/レコードパターンと組み合わせて使う。 +後述するタプル/配列/レコードパターンと組み合わせて使います。 ```erg [i, ...j] = [1, 2, 3, 4] diff --git a/doc/JA/syntax/27_comprehension.md b/doc/JA/syntax/27_comprehension.md index bb60509d..4448dfed 100644 --- a/doc/JA/syntax/27_comprehension.md +++ b/doc/JA/syntax/27_comprehension.md @@ -2,23 +2,33 @@ `[expr | (name <- iterable)+ (predicate)*]`で配列、 `{expr | (name <- iterable)+ (predicate)*}`でセット、 -`{key: value | (name <- iterable)+ (predicate)*}`でDictが作れる。 +`{key: value | (name <- iterable)+ (predicate)*}`でDictが作れます。 `|`で区切られた節のうち最初の部分をレイアウト節(配置節)といい、2番目の部分をバインド節(束縛節)、3番目の部分をガード節(条件節)という。 -ガード節は省略可能であるがバインド節は省略できず、バインド節より先にガード節を置くことはできない。 +ガード節は省略可能ですがバインド節は省略できず、バインド節より先にガード節を置くことはできません。 -e.g. +内包表記の例 ```erg +# レイアウト節はi +# バインド節はi <- [0, 1, 2] assert [i | i <- [0, 1, 2]] == [0, 1, 2] + +# レイアウト節はi / 2 +# バインド節はi <- 0..2 assert [i / 2 | i <- 0..2] == [0.0, 0.5, 1.0] + +# レイアウト節は(i, j) +# バインド節はi <- 0..2, j <- 0..2 +# ガード節は(i + j) % 2 == 0 assert [(i, j) | i <- 0..2; j <- 0..2; (i + j) % 2 == 0] == [(0, 0), (0, 2), (1, 1), (2, 0), (2, 2)] + assert {i % 2 | i <- 0..9} == {0, 1} assert {k: v | k <- ["a", "b"]; v <- [1, 2]} == {"a": 1, "b": 2} ``` -Ergの内包表記はHaskellに影響を受けているが、若干の違いがある。 -Haskellのリスト内包表記の場合、変数の順番は結果に違いをもたらすが、Ergでは関係がない。 +Ergの内包表記はHaskellに影響を受けているが、若干の違いがあります。 +Haskellのリスト内包表記の場合、変数の順番は結果に違いをもたらしますが、Ergでは関係がありません。 ```haskell -- Haskell @@ -31,7 +41,7 @@ Haskellのリスト内包表記の場合、変数の順番は結果に違いを assert [(i, j) | i <- 1..<3; j <- 3..<5] == [(i, j) | j <- 3..<5; i <- 1..<3] ``` -これはPythonと同じである。 +この仕様はPythonのものと同じです。 ```python # Python @@ -40,8 +50,8 @@ assert [(i, j) for i in range(1, 3) for j in range(3, 5)] == [(i, j) for j in ra ## 篩型 -内包表記と似たものに、篩型がある。篩型は`{Name: Type | Predicate}`という形式で作られる型(列挙型)である。 -篩型の場合、Nameは1つまででレイアウトは指定できず(ただしタプル型などにすれば複数の値は扱える)、Predicateはコンパイル時計算できるもの、つまり定数式でなくてはならない。 +内包表記と似たものに、篩型があります。篩型は`{Name: Type | Predicate}`という形式で作られる型(列挙型)です。 +篩型の場合、Nameは1つまででレイアウトは指定できず(ただしタプル型などにすれば複数の値は扱えます)、Predicateはコンパイル時計算できるもの、つまり定数式のみが指定できます。 ```erg Nat = {I: Int | I >= 0} diff --git a/doc/JA/syntax/28_spread_syntax.md b/doc/JA/syntax/28_spread_syntax.md index d8907398..52c2c658 100644 --- a/doc/JA/syntax/28_spread_syntax.md +++ b/doc/JA/syntax/28_spread_syntax.md @@ -1,6 +1,6 @@ # Spread assignment (展開代入) -分解代入において、変数の前に`...`を置くと残りの要素を全てその変数に展開できる。これを展開代入と呼ぶ。 +分解代入において、変数の前に`...`を置くと残りの要素を全てその変数に展開できます。これを展開代入と呼びます。 ```erg [x, ...y] = [1, 2, 3] @@ -13,23 +13,23 @@ assert y == (2, 3) ## Extract assignment (抽出代入) -`...`のあとに何も書かない場合、残りの要素は無視して代入される。このタイプの展開代入を特に抽出代入と呼ぶ。 -抽出代入は、モジュールやレコード内にある特定の属性をローカルに持ってくる際に便利な構文である。 +`...`のあとに何も書かない場合、残りの要素は無視して代入されます。このタイプの展開代入を特に抽出代入と呼びます。 +抽出代入は、モジュールやレコード内にある特定の属性をローカルに持ってくる際に便利な構文です。 ```erg {sin; cos; tan; ..} = import "math" ``` -このようにすると、以降はローカルで`sin, cos, tan`が使用できる。 +このようにすると、以降はローカルで`sin, cos, tan`が使用できます。 -レコードでも同じようにできる。 +レコードでも同じようにできます。 ```erg record = {x = 1; y = 2} {x; y; ...} = record ``` -全て展開したい場合は`{*} = record`とする。OCamlなどでいう`open`である。 +全て展開したい場合は`{*} = record`とします。OCamlなどでいう`open`です。 ```erg record = {x = 1; y = 2} diff --git a/doc/JA/syntax/30_error_handling.md b/doc/JA/syntax/30_error_handling.md index 6888f70a..841296fa 100644 --- a/doc/JA/syntax/30_error_handling.md +++ b/doc/JA/syntax/30_error_handling.md @@ -1,11 +1,11 @@ # エラーハンドリングシステム -主にResult型を使用する。 -ErgではError型オブジェクトを捨てる(トップレベルで対応しない)とエラーが発生する。 +主にResult型を使用します。 +ErgではError型オブジェクトを捨てる(トップレベルで対応しない)とエラーが発生します。 ## 例外、Pythonとの相互運用 -Ergは例外機構(Exception)を持たない。Pythonの関数をインポートする際は +Ergは例外機構(Exception)を持ちません。Pythonの関数をインポートする際は * 戻り値を`T or Error`型とする * `T or Panic`型(実行時エラーを出す可能性がある)とする @@ -15,8 +15,8 @@ Ergは例外機構(Exception)を持たない。Pythonの関数をインポート ## 例外とResult型 -`Result`型はエラーかもしれない値を表現する。`Result`によるエラーハンドリングはいくつかの点で例外機構よりも優れている。 -まず第一に、サブルーチンがエラーを出すかもしれないと型定義から分かり、実際に使用するときも一目瞭然なのである。 +`Result`型はエラーかもしれない値を表現します。`Result`によるエラーハンドリングはいくつかの点で例外機構よりも優れています。 +まず第一に、サブルーチンがエラーを出すかもしれないと型定義から分かり、実際に使用するときも一目瞭然です。 ```python # Python @@ -28,7 +28,7 @@ except e: print(e) ``` -上の例では、例外がどの関数から送出されたものなのか、このコードだけでは分からない。関数定義まで遡っても、その関数が例外を出すかは判別しにくい。 +上の例では、例外がどの関数から送出されたものなのか、このコードだけでは分かりません。関数定義まで遡っても、その関数が例外を出すかを判別するのは難しいです。 ```erg # Erg @@ -41,14 +41,14 @@ try!: print! e ``` -翻って、こちらの例では`foo!`と`qux!`がエラーを出しうるとわかる。 -正確には`y`も`Result`型である可能性があるが、中の値を使用するためにはいずれ対処しなくてはならない。 +翻って、こちらの例では`foo!`と`qux!`がエラーを出しうるとわかります。 +正確には`y`も`Result`型である可能性がありますが、中の値を使用するためにはいずれ対処しなくてはなりません。 -`Result`型を使用するメリットはそれだけではない。`Result`型はスレッドセーフでもある。これは、エラー情報を並列実行中に(容易に)受け渡しできるということを意味する。 +`Result`型を使用するメリットはそれだけではありません。`Result`型はスレッドセーフでもあります。これは、エラー情報を並列実行中に(容易に)受け渡しできるということを意味します。 ## Context -`Error`/`Result`型単体では副作用が発生しないので、例外と違い送出場所などの情報(Context、文脈)を持てないが、`.context`メソッドを使えば`Error`オブジェクトに情報を付加できる。`.context`メソッドは`Error`オブジェクト自身を消費して新しい`Error`オブジェクトを作るタイプのメソッドである。チェイン可能であり、複数のコンテクストを保持できる。 +`Error`/`Result`型単体では副作用が発生しないので、例外と違い送出場所などの情報(Context、文脈)を持てませんが、`.context`メソッドを使えば`Error`オブジェクトに情報を付加できます。`.context`メソッドは`Error`オブジェクト自身を消費して新しい`Error`オブジェクトを作るタイプのメソッドです。チェイン可能であり、複数のコンテクストを保持できます。 ```erg f() = @@ -62,14 +62,14 @@ f() # hint: and more hints ... ``` -なお、`.msg`や`.kind`などの`Error`の属性は副次的なものではないのでcontextではなく、最初に生成されたときのまま上書きできない。 +なお、`.msg`や`.kind`などの`Error`の属性は副次的なものではないのでcontextではなく、最初に生成されたときのまま上書きできません。 ## スタックトレース -`Result`型はその利便性から他言語でも多く取り入れられているが、例外機構と比較してエラーの発生元がわかりにくくなるというデメリットがある。 -そこで、Ergでは`Error`オブジェクトに`.stack`という属性を持たせており、擬似的に例外機構のようなスタックトレースを再現している。 -`.stack`は呼び出し元オブジェクトの配列である。Errorオブジェクトは`return`(`?`によるものも含む)されるたびにその呼出元サブルーチンを`.stack`に積んでいく。 -そして`return`ができないコンテクストで`?`されるなり`.unwrap`されるなりすると、トレースバックを表示しながらパニックする。 +`Result`型はその利便性から他言語でも多く取り入れられていますが、例外機構と比較してエラーの発生元がわかりにくくなるというデメリットがあります。 +そこで、Ergでは`Error`オブジェクトに`.stack`という属性を持たせており、擬似的に例外機構のようなスタックトレースを再現しています。 +`.stack`は呼び出し元オブジェクトの配列です。Errorオブジェクトは`return`(`?`によるものも含む)されるたびにその呼出元サブルーチンを`.stack`に積んでいきます。 +そして`return`ができないコンテクストで`?`されるなり`.unwrap`されるなりすると、トレースバックを表示しながらパニックします。 ```erg f x = @@ -95,10 +95,10 @@ i = g(1)? ## パニック -Ergには回復不能なエラーへの対処として __パニッキング__ という機構も存在する。 -回復不能なエラーとは、例えばソフト/ハードウェアの不具合など外的要因によるエラーや、それ以上コードを実行し続けても意味がないほど致命的なエラー、あるいはプログラム作成者の想定だにしないエラーなどである。これが発生した場合、プログラマの努力によって正常系に復帰させることができないため、その場でプログラムを終了させる。これを「パニックさせる」という。 +Ergには回復不能なエラーへの対処として __パニッキング__ という機構も存在します。 +回復不能なエラーとは、例えばソフト/ハードウェアの不具合など外的要因によるエラーや、それ以上コードを実行し続けても意味がないほど致命的なエラー、あるいはプログラム作成者の想定だにしないエラーなどです。これが発生した場合、プログラマの努力によって正常系に復帰させることができないため、その場でプログラムを終了させます。これを「パニックさせる」といいます。 -パニックは`panic`関数で行う。 +パニックは`panic`関数で行います。 ```erg panic "something went wrong!" diff --git a/doc/JA/syntax/31_pipeline.md b/doc/JA/syntax/31_pipeline.md index 43a837bc..9956b61b 100644 --- a/doc/JA/syntax/31_pipeline.md +++ b/doc/JA/syntax/31_pipeline.md @@ -1,24 +1,27 @@ # パイプライン演算子 -パイプライン演算子は、次のように使う。 +パイプライン演算子は、次のように使います。 ```erg assert f(g(x)) == (x |> g |> f) assert f(g(x, y)) == ((x, y) |> g |> f) ``` -つまり、`Callable(object)`という順序を`object |> Callable`と変えられるのである。 -パイプライン演算子はメソッドに対しても使える。メソッドの場合、`object.method(args)`が`object |>.method(args)`と変わる。 -単に`|>`が増えただけにも見えるが、結合強度が低めなので`()`の量を減らせる場合がある。 +つまり、`Callable(object)`という順序を`object |> Callable`に変えられます。 +パイプライン演算子はメソッドに対しても使えます。メソッドの場合、`object.method(args)`が`object |>.method(args)`と変わります。 +単に`|>`が増えただけにも見えるが、結合強度が低めなので`()`の量を減らせる場合があります。 ```erg rand = -1.0..1.0 |>.sample!() log rand # 0.2597... + 1+1*2 |>.times do log("a", end: "") # aaa -# without `|>`, the following will be `evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array)` + evens = 1..100 |>.iter |>.filter i -> i % 2 == 0 |>.collect Array -# or -_evens = 1..100 \ +# パイプライン演算子を使わずに実装する場合、 +_evens = (1..100).iter().filter(i -> i % 2 == 0).collect(Array) +# または +__evens = 1..100 \ .iter() \ .filter i -> i % 2 == 0 \ .collect Array diff --git a/doc/JA/syntax/type/02_basic.md b/doc/JA/syntax/type/02_basic.md index 958469ed..40383dc9 100644 --- a/doc/JA/syntax/type/02_basic.md +++ b/doc/JA/syntax/type/02_basic.md @@ -57,7 +57,7 @@ Iterable T = Trait { } ``` -また、クラス定義時に部分型指定を行うと、クラスが指定した型のサブタイプか静的に検査することができます。 +また、クラス定義時に部分型指定を行うと、クラスが指定した型のサブタイプか静的に検査できます。 ```erg # クラスCはShowのサブタイプ @@ -87,7 +87,7 @@ C.shoe self = ... # TypoのせいでShowが実装できていない(単なる固 ## 属性定義 -トレイトやクラスには、モジュール内でのみ属性を定義することができます。 +トレイトやクラスには、モジュール内でのみ属性を定義できます。 ```erg C = Class() diff --git a/doc/JA/syntax/type/03_trait.md b/doc/JA/syntax/type/03_trait.md index 679a4d5d..2166ddff 100644 --- a/doc/JA/syntax/type/03_trait.md +++ b/doc/JA/syntax/type/03_trait.md @@ -10,7 +10,7 @@ Norm = Trait {.x = Int; .y = Int; .norm = Self.() -> Int} トレイトは属性とメソッドを区別しません。 トレイトは宣言ができるのみで実装を持てないことに注意してください(実装は後に述べるパッチという機能で実現します)。 -トレイトは部分型指定でクラスに実装されているかチェックすることができます。 +トレイトは部分型指定でクラスに実装されているかチェックできます。 ```erg Point2D <: Norm diff --git a/doc/JA/syntax/type/04_class.md b/doc/JA/syntax/type/04_class.md index d1ce81f3..6904ca08 100644 --- a/doc/JA/syntax/type/04_class.md +++ b/doc/JA/syntax/type/04_class.md @@ -257,7 +257,7 @@ assert x1 == x2 ## 包含関係 -クラスは、要件型のサブタイプです。要件型のメソッド(パッチメソッド含む)を使用することができます。 +クラスは、要件型のサブタイプです。要件型のメソッド(パッチメソッド含む)を使用できます。 ```erg T = Trait ... diff --git a/doc/JA/syntax/type/18_mut.md b/doc/JA/syntax/type/18_mut.md index 098f822b..6ee3225b 100644 --- a/doc/JA/syntax/type/18_mut.md +++ b/doc/JA/syntax/type/18_mut.md @@ -3,7 +3,7 @@ > __Warning__: この項の情報は古く、一部に間違いを含みます。 Ergではデフォルトですべての型が不変型、すなわち内部状態を更新できないようになっています。 -しかし可変な型ももちろん定義することができます。可変型は`!`を付けて宣言します。 +しかし可変な型ももちろん定義できます。可変型は`!`を付けて宣言します。 ```erg Person! = Class({name = Str; age = Nat!}) diff --git a/doc/JA/syntax/type/advanced/GADTs.md b/doc/JA/syntax/type/advanced/GADTs.md index c3004767..b7dcec61 100644 --- a/doc/JA/syntax/type/advanced/GADTs.md +++ b/doc/JA/syntax/type/advanced/GADTs.md @@ -44,7 +44,7 @@ print! nil().head() # TypeError ``` 巷でよく説明されるGADTsの例は、以上のように中身が空か否か型で判定できるリストです。 -Ergではさらに精密化して、長さを持つリストを定義することができます。 +Ergではさらに精密化して、長さを持つリストを定義できます。 ```erg List: (Type, Nat) -> Type diff --git a/doc/JA/syntax/type/advanced/variance.md b/doc/JA/syntax/type/advanced/variance.md index 1f711bc9..5ec7174e 100644 --- a/doc/JA/syntax/type/advanced/variance.md +++ b/doc/JA/syntax/type/advanced/variance.md @@ -47,7 +47,7 @@ Ergにはもう一つ変性がある。それは非変性(non-variance)である ## 変性指定された全称型 -全称型の型変数は、その上限・下限を指定することができます。 +全称型の型変数は、その上限・下限を指定できます。 ```erg |A <: T| K(A) diff --git a/doc/JA/syntax/type/newtype.md b/doc/JA/syntax/type/newtype.md index fd2c5167..559e5bf0 100644 --- a/doc/JA/syntax/type/newtype.md +++ b/doc/JA/syntax/type/newtype.md @@ -2,7 +2,7 @@ ここでは、Rustでよく使われるnewtypeパターンのErg版を紹介します。 -Ergはでは以下のように型のエイリアスを定義することができますが、これはあくまで同じ型を指します。 +Ergはでは以下のように型のエイリアスを定義できますが、これはあくまで同じ型を指します。 ```erg UserId = Int diff --git a/src/dummy.rs b/src/dummy.rs index 26583a7d..0550f8df 100644 --- a/src/dummy.rs +++ b/src/dummy.rs @@ -1,10 +1,11 @@ +use std::fs::remove_file; use std::io::{Read, Write}; use std::net::TcpStream; use std::thread::sleep; use std::time::Duration; use erg_common::config::{ErgConfig, Input, BUILD_INFO, SEMVER}; -use erg_common::python_util::exec_py; +use erg_common::python_util::{exec_py, exec_pyc}; use erg_common::str::Str; use erg_common::traits::Runnable; @@ -16,7 +17,7 @@ use erg_compiler::Compiler; pub struct DummyVM { cfg: ErgConfig, compiler: Compiler, - stream: TcpStream, + stream: Option, } impl Runnable for DummyVM { @@ -24,23 +25,25 @@ impl Runnable for DummyVM { type Errs = CompileErrors; fn new(cfg: ErgConfig) -> Self { - println!("Starting the REPL server..."); - let code = include_str!("scripts/repl_server.py"); - exec_py(code); - println!("Connecting to the REPL server..."); - let repl_server_ip = "127.0.0.1"; - let repl_server_port = 8736; - let addr = format!("{repl_server_ip}:{repl_server_port}"); - let stream = loop { - match TcpStream::connect(&addr) { - Ok(stream) => break stream, - Err(_) => { - println!("Retrying to connect to the REPL server..."); - sleep(Duration::from_millis(500)); - continue; + let stream = if cfg.input.is_repl() { + println!("Starting the REPL server..."); + let code = include_str!("scripts/repl_server.py"); + exec_py(code); + println!("Connecting to the REPL server..."); + let repl_server_ip = "127.0.0.1"; + let repl_server_port = 8736; + let addr = format!("{repl_server_ip}:{repl_server_port}"); + loop { + match TcpStream::connect(&addr) { + Ok(stream) => break Some(stream), + Err(_) => { + println!("Retrying to connect to the REPL server..."); + sleep(Duration::from_millis(500)); + continue; + } } } - }; + } else { None }; Self { compiler: Compiler::new(cfg.copy()), cfg, @@ -59,17 +62,19 @@ impl Runnable for DummyVM { } fn finish(&mut self) { - self.stream.write_all("exit".as_bytes()).unwrap(); - let mut buf = [0; 1024]; - match self.stream.read(&mut buf) { - Result::Ok(n) => { - let s = std::str::from_utf8(&buf[..n]).unwrap(); - if s.contains("closed") { - println!("The REPL server is closed."); + if let Some(stream) = &mut self.stream { + stream.write_all("exit".as_bytes()).unwrap(); + let mut buf = [0; 1024]; + match stream.read(&mut buf) { + Result::Ok(n) => { + let s = std::str::from_utf8(&buf[..n]).unwrap(); + if s.contains("closed") { + println!("The REPL server is closed."); + } + } + Result::Err(e) => { + panic!("{}", format!("Read error: {e}")); } - } - Result::Err(e) => { - panic!("{}", format!("Read error: {e}")); } } } @@ -78,13 +83,22 @@ impl Runnable for DummyVM { self.compiler.clear(); } + fn exec(&mut self) -> Result<(), Self::Errs> { + let src = self.input().read(); + self.compiler + .compile_and_dump_as_pyc(src, "o.pyc", "exec")?; + exec_pyc("o.pyc"); + remove_file("o.pyc").unwrap(); + Ok(()) + } + fn eval(&mut self, src: Str) -> Result { self.compiler .compile_and_dump_as_pyc(src, "o.pyc", "eval")?; - let mut res = match self.stream.write("load".as_bytes()) { + let mut res = match self.stream.as_mut().unwrap().write("load".as_bytes()) { Result::Ok(_) => { let mut buf = [0; 1024]; - match self.stream.read(&mut buf) { + match self.stream.as_mut().unwrap().read(&mut buf) { Result::Ok(n) => { let s = std::str::from_utf8(&buf[..n]).unwrap(); s.to_string()