Merge branch 'main' into pr/191

This commit is contained in:
Shunsuke Shibayama 2022-10-06 11:57:49 +09:00
commit 6b14add8f8
47 changed files with 1306 additions and 540 deletions

10
Cargo.lock generated
View file

@ -15,7 +15,7 @@ dependencies = [
[[package]] [[package]]
name = "erg" name = "erg"
version = "0.5.6" version = "0.5.7-nightly.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_compiler", "erg_compiler",
@ -25,14 +25,14 @@ dependencies = [
[[package]] [[package]]
name = "erg_common" name = "erg_common"
version = "0.5.6" version = "0.5.7-nightly.1"
dependencies = [ dependencies = [
"atty", "atty",
] ]
[[package]] [[package]]
name = "erg_compiler" name = "erg_compiler"
version = "0.5.6" version = "0.5.7-nightly.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_parser", "erg_parser",
@ -41,14 +41,14 @@ dependencies = [
[[package]] [[package]]
name = "erg_parser" name = "erg_parser"
version = "0.5.6" version = "0.5.7-nightly.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
] ]
[[package]] [[package]]
name = "erg_type" name = "erg_type"
version = "0.5.6" version = "0.5.7-nightly.1"
dependencies = [ dependencies = [
"erg_common", "erg_common",
"erg_parser", "erg_parser",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg" name = "erg"
version = "0.5.6" version = "0.5.7-nightly.1"
description = "The Erg programming language" description = "The Erg programming language"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -47,10 +47,10 @@ traditional_chinese = [
pre-commit = [] pre-commit = []
[dependencies] [dependencies]
erg_common = { version = "0.5.6", path = "./compiler/erg_common" } erg_common = { version = "0.5.7-nightly.1", path = "./compiler/erg_common" }
erg_parser = { version = "0.5.6", path = "./compiler/erg_parser" } erg_parser = { version = "0.5.7-nightly.1", path = "./compiler/erg_parser" }
erg_compiler = { version = "0.5.6", path = "./compiler/erg_compiler" } erg_compiler = { version = "0.5.7-nightly.1", path = "./compiler/erg_compiler" }
erg_type = { version = "0.5.6", path = "./compiler/erg_type" } erg_type = { version = "0.5.7-nightly.1", path = "./compiler/erg_type" }
# [workspace] # [workspace]
# member = ["cm", "dyne"] # member = ["cm", "dyne"]

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_common" name = "erg_common"
version = "0.5.6" version = "0.5.7-nightly.1"
description = "A common components library of Erg" description = "A common components library of Erg"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"

View file

@ -93,7 +93,7 @@ impl Input {
let mut codes = vec![]; let mut codes = vec![];
let mut lines = BufReader::new(file).lines().skip(ln_begin - 1); let mut lines = BufReader::new(file).lines().skip(ln_begin - 1);
for _ in ln_begin..=ln_end { for _ in ln_begin..=ln_end {
codes.push(lines.next().unwrap().unwrap()); codes.push(lines.next().unwrap_or_else(|| Ok("".to_string())).unwrap());
} }
codes codes
} }

View file

@ -114,6 +114,20 @@ use ErrorKind::*;
impl_display_from_debug!(ErrorKind); impl_display_from_debug!(ErrorKind);
impl ErrorKind {
pub fn is_warning(&self) -> bool {
(60..=100).contains(&(*self as u8)) || (180..=200).contains(&(*self as u8))
}
pub fn is_error(&self) -> bool {
(0..=59).contains(&(*self as u8)) || (100..=179).contains(&(*self as u8))
}
pub fn is_exception(&self) -> bool {
(200..=255).contains(&(*self as u8))
}
}
impl From<&str> for ErrorKind { impl From<&str> for ErrorKind {
fn from(s: &str) -> ErrorKind { fn from(s: &str) -> ErrorKind {
match s { match s {
@ -467,10 +481,9 @@ pub trait ErrorDisplay {
} }
fn format_header(&self) -> String { fn format_header(&self) -> String {
let kind = self.core().kind as u8; let (color, err_or_warn) = if self.core().kind.is_warning() {
let (color, err_or_warn) = if (60..=100).contains(&kind) || (180..=200).contains(&kind) {
(YELLOW, "Warning") (YELLOW, "Warning")
} else if kind >= 200 { } else if self.core().kind.is_exception() {
("", "Exception") ("", "Exception")
} else { } else {
(RED, "Error") (RED, "Error")

View file

@ -177,6 +177,10 @@ impl<T: Hash + Eq> Set<T> {
} }
impl<T: Hash + Eq + Clone> Set<T> { impl<T: Hash + Eq + Clone> Set<T> {
/// ```
/// # use erg_common::set;
/// assert_eq!(set!{1, 2, 3}.union(&set!{2, 3, 4}), set!{1, 2, 3, 4});
/// ```
#[inline] #[inline]
pub fn union(&self, other: &Set<T>) -> Set<T> { pub fn union(&self, other: &Set<T>) -> Set<T> {
let u = self.elems.union(&other.elems); let u = self.elems.union(&other.elems);
@ -185,6 +189,10 @@ impl<T: Hash + Eq + Clone> Set<T> {
} }
} }
/// ```
/// # use erg_common::set;
/// assert_eq!(set!{1, 2, 3}.intersection(&set!{2, 3, 4}), set!{2, 3});
/// ```
#[inline] #[inline]
pub fn intersection(&self, other: &Set<T>) -> Set<T> { pub fn intersection(&self, other: &Set<T>) -> Set<T> {
let u = self.elems.intersection(&other.elems); let u = self.elems.intersection(&other.elems);

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_compiler" name = "erg_compiler"
version = "0.5.6" version = "0.5.7-nightly.1"
description = "Centimetre: the Erg compiler" description = "Centimetre: the Erg compiler"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -17,9 +17,9 @@ simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_c
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
[dependencies] [dependencies]
erg_common = { version = "0.5.6", path = "../erg_common" } erg_common = { version = "0.5.7-nightly.1", path = "../erg_common" }
erg_parser = { version = "0.5.6", path = "../erg_parser" } erg_parser = { version = "0.5.7-nightly.1", path = "../erg_parser" }
erg_type = { version = "0.5.6", path = "../erg_type" } erg_type = { version = "0.5.7-nightly.1", path = "../erg_type" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -207,7 +207,7 @@ fn is_fake_method(class: &str, name: &str) -> bool {
matches!( matches!(
(class, name), (class, name),
( (
"Complex" | "Float" | "Ratio" | "Int" | "Nat" | "Bool", _, // "Complex" | "Float" | "Ratio" | "Int" | "Nat" | "Bool",
"abs" "abs"
) | (_, "iter") ) | (_, "iter")
| (_, "map") | (_, "map")
@ -1205,6 +1205,17 @@ impl CodeGenerator {
} }
} }
fn emit_del_instr(&mut self, mut args: Args) {
let ident = enum_unwrap!(args.remove_left_or_key("obj").unwrap(), Expr::Accessor:(Accessor::Ident:(_)));
log!(info "entered {} ({ident})", fn_name!());
let escaped = escape_name(ident);
let name = self
.local_search(&escaped, Name)
.unwrap_or_else(|| self.register_name(escaped));
self.write_instr(DELETE_NAME);
self.write_arg(name.idx as u8);
}
fn emit_discard_instr(&mut self, mut args: Args) { fn emit_discard_instr(&mut self, mut args: Args) {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
while let Some(arg) = args.try_remove(0) { while let Some(arg) = args.try_remove(0) {
@ -1448,6 +1459,7 @@ impl CodeGenerator {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
match &local.inspect()[..] { match &local.inspect()[..] {
"assert" => self.emit_assert_instr(args), "assert" => self.emit_assert_instr(args),
"Del" => self.emit_del_instr(args),
"discard" => self.emit_discard_instr(args), "discard" => self.emit_discard_instr(args),
"for" | "for!" => self.emit_for_instr(args), "for" | "for!" => self.emit_for_instr(args),
"if" | "if!" => self.emit_if_instr(args), "if" | "if!" => self.emit_if_instr(args),

View file

@ -278,6 +278,11 @@ impl Context {
if let Some((_, ty_ctx)) = self.get_nominal_type_ctx(rhs) { if let Some((_, ty_ctx)) = self.get_nominal_type_ctx(rhs) {
for rhs_sup in ty_ctx.super_classes.iter() { for rhs_sup in ty_ctx.super_classes.iter() {
let rhs_sup = if rhs_sup.has_qvar() { let rhs_sup = if rhs_sup.has_qvar() {
let rhs = match rhs {
Type::Ref(t) => t,
Type::RefMut { before, .. } => before,
other => other,
};
let subst_ctx = SubstContext::new(rhs, ty_ctx); let subst_ctx = SubstContext::new(rhs, ty_ctx);
subst_ctx subst_ctx
.substitute(rhs_sup.clone(), self, Location::Unknown) .substitute(rhs_sup.clone(), self, Location::Unknown)
@ -311,6 +316,11 @@ impl Context {
if let Some((_, rhs_ctx)) = self.get_nominal_type_ctx(rhs) { if let Some((_, rhs_ctx)) = self.get_nominal_type_ctx(rhs) {
for rhs_sup in rhs_ctx.super_traits.iter() { for rhs_sup in rhs_ctx.super_traits.iter() {
let rhs_sup = if rhs_sup.has_qvar() { let rhs_sup = if rhs_sup.has_qvar() {
let rhs = match rhs {
Type::Ref(t) => t,
Type::RefMut { before, .. } => before,
other => other,
};
let subst_ctx = SubstContext::new(rhs, rhs_ctx); let subst_ctx = SubstContext::new(rhs, rhs_ctx);
subst_ctx subst_ctx
.substitute(rhs_sup.clone(), self, Location::Unknown) .substitute(rhs_sup.clone(), self, Location::Unknown)
@ -638,8 +648,26 @@ impl Context {
(l, MonoQVar(name)) | (l, PolyQVar { name, .. }) => { (l, MonoQVar(name)) | (l, PolyQVar { name, .. }) => {
panic!("internal error: not instantiated type variable: '{name}, l: {l}") panic!("internal error: not instantiated type variable: '{name}, l: {l}")
} }
(MonoProj { .. }, _) => todo!(), (MonoProj { .. }, _) => {
(_, MonoProj { .. }) => todo!(), if let Some(cands) = self.get_candidates(lhs) {
for cand in cands.into_iter() {
if self.supertype_of(&cand, rhs) {
return true;
}
}
}
false
}
(_, MonoProj { .. }) => {
if let Some(cands) = self.get_candidates(rhs) {
for cand in cands.into_iter() {
if self.supertype_of(lhs, &cand) {
return true;
}
}
}
false
}
(_l, _r) => false, (_l, _r) => false,
} }
} }
@ -810,13 +838,19 @@ impl Context {
/// returns union of two types (A or B) /// returns union of two types (A or B)
pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type { pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type {
// ?T or ?U will not be unified
if lhs.has_no_unbound_var() && rhs.has_no_unbound_var() {
match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) { match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) {
(true, true) => return lhs.clone(), // lhs = rhs (true, true) => return lhs.clone(), // lhs = rhs
(true, false) => return lhs.clone(), // lhs :> rhs (true, false) => return lhs.clone(), // lhs :> rhs
(false, true) => return rhs.clone(), (false, true) => return rhs.clone(),
(false, false) => {} (false, false) => {}
} }
}
match (lhs, rhs) { match (lhs, rhs) {
(FreeVar(lfv), FreeVar(rfv)) if lfv.is_linked() && rfv.is_linked() => {
self.union(&lfv.crack(), &rfv.crack())
}
(Refinement(l), Refinement(r)) => Type::Refinement(self.union_refinement(l, r)), (Refinement(l), Refinement(r)) => Type::Refinement(self.union_refinement(l, r)),
(t, Type::Never) | (Type::Never, t) => t.clone(), (t, Type::Never) | (Type::Never, t) => t.clone(),
(t, Refinement(r)) | (Refinement(r), t) => { (t, Refinement(r)) | (Refinement(r), t) => {
@ -842,16 +876,19 @@ impl Context {
/// returns intersection of two types (A and B) /// returns intersection of two types (A and B)
pub(crate) fn intersection(&self, lhs: &Type, rhs: &Type) -> Type { pub(crate) fn intersection(&self, lhs: &Type, rhs: &Type) -> Type {
// ?T and ?U will not be unified
if !lhs.is_unbound_var() && !rhs.is_unbound_var() {
match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) { match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) {
(true, true) => return lhs.clone(), // lhs = rhs (true, true) => return lhs.clone(), // lhs = rhs
(true, false) => return rhs.clone(), // lhs :> rhs (true, false) => return rhs.clone(), // lhs :> rhs
(false, true) => return lhs.clone(), (false, true) => return lhs.clone(),
(false, false) => {} (false, false) => {}
} }
}
match (lhs, rhs) { match (lhs, rhs) {
/*(Type::FreeVar(_), _) | (_, Type::FreeVar(_)) => { (FreeVar(lfv), FreeVar(rfv)) if lfv.is_linked() && rfv.is_linked() => {
todo!() self.intersection(&lfv.crack(), &rfv.crack())
}*/ }
// {.i = Int} and {.s = Str} == {.i = Int; .s = Str} // {.i = Int} and {.s = Str} == {.i = Int; .s = Str}
(Type::Record(l), Type::Record(r)) => Type::Record(l.clone().concat(r.clone())), (Type::Record(l), Type::Record(r)) => Type::Record(l.clone().concat(r.clone())),
(l, r) if self.is_trait(l) && self.is_trait(r) => and(l.clone(), r.clone()), (l, r) if self.is_trait(l) && self.is_trait(r) => and(l.clone(), r.clone()),
@ -1008,7 +1045,7 @@ impl Context {
} }
} }
pub(crate) fn max<'t>(&self, lhs: &'t Type, rhs: &'t Type) -> Option<&'t Type> { pub(crate) fn _max<'t>(&self, lhs: &'t Type, rhs: &'t Type) -> Option<&'t Type> {
// 同じならどちらを返しても良い // 同じならどちらを返しても良い
match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) { match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) {
(true, true) | (true, false) => Some(lhs), (true, true) | (true, false) => Some(lhs),

View file

@ -2,6 +2,7 @@ use std::fmt;
use std::mem; use std::mem;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::enum_unwrap;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::shared::Shared; use erg_common::shared::Shared;
@ -15,19 +16,18 @@ use erg_parser::ast::*;
use erg_parser::token::{Token, TokenKind}; use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{ use erg_type::constructors::{
and, builtin_mono, builtin_poly, mono_proj, not, or, poly, ref_, ref_mut, refinement, subr_t, builtin_mono, builtin_poly, mono_proj, not, poly, ref_, ref_mut, refinement, subr_t, v_enum,
v_enum,
}; };
use erg_type::typaram::{OpKind, TyParam}; use erg_type::typaram::{OpKind, TyParam};
use erg_type::value::ValueObj; use erg_type::value::ValueObj;
use erg_type::{ use erg_type::{ConstSubr, HasType, Predicate, SubrKind, TyBound, Type, UserConstSubr, ValueArgs};
ConstSubr, HasType, ParamTy, Predicate, SubrKind, TyBound, Type, UserConstSubr, ValueArgs,
};
use crate::context::instantiate::TyVarContext; use crate::context::instantiate::TyVarContext;
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode}; use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode};
use crate::error::{EvalError, EvalErrors, EvalResult, SingleEvalResult, TyCheckResult}; use crate::error::{EvalError, EvalErrors, EvalResult, SingleEvalResult, TyCheckResult};
use super::Variance;
#[inline] #[inline]
pub fn type_from_token_kind(kind: TokenKind) -> Type { pub fn type_from_token_kind(kind: TokenKind) -> Type {
use TokenKind::*; use TokenKind::*;
@ -72,6 +72,34 @@ fn try_get_op_kind_from_token(kind: TokenKind) -> EvalResult<OpKind> {
} }
} }
fn op_to_name(op: OpKind) -> &'static str {
match op {
OpKind::Add => "__add__",
OpKind::Sub => "__sub__",
OpKind::Mul => "__mul__",
OpKind::Div => "__div__",
OpKind::Mod => "__mod__",
OpKind::Pow => "__pow__",
OpKind::Pos => "__pos__",
OpKind::Neg => "__neg__",
OpKind::Eq => "__eq__",
OpKind::Ne => "__ne__",
OpKind::Lt => "__lt__",
OpKind::Le => "__le__",
OpKind::Gt => "__gt__",
OpKind::Ge => "__ge__",
OpKind::And => "__and__",
OpKind::Or => "__or__",
OpKind::Invert => "__invert__",
OpKind::BitAnd => "__bitand__",
OpKind::BitOr => "__bitor__",
OpKind::BitXor => "__bitxor__",
OpKind::Shl => "__shl__",
OpKind::Shr => "__shr__",
OpKind::Mutate => "__mutate__",
}
}
#[inline] #[inline]
pub(crate) fn eval_lit(lit: &Literal) -> ValueObj { pub(crate) fn eval_lit(lit: &Literal) -> ValueObj {
let t = type_from_token_kind(lit.token.kind); let t = type_from_token_kind(lit.token.kind);
@ -104,7 +132,13 @@ impl SubstContext {
.as_ref() .as_ref()
.map_or_else(|| Str::ever("_"), |n| n.inspect().clone()) .map_or_else(|| Str::ever("_"), |n| n.inspect().clone())
}); });
assert_eq!(param_names.len(), substituted.typarams().len()); if param_names.len() != substituted.typarams().len() {
let param_names = param_names.collect::<Vec<_>>();
panic!(
"{param_names:?} != {}",
erg_common::fmt_vec(&substituted.typarams())
);
}
// REVIEW: 順番は保証されるか? 引数がunnamed_paramsに入る可能性は? // REVIEW: 順番は保証されるか? 引数がunnamed_paramsに入る可能性は?
SubstContext { SubstContext {
bounds, bounds,
@ -464,36 +498,20 @@ impl Context {
let tv_ctx = TyVarContext::new(self.level, bounds, self); let tv_ctx = TyVarContext::new(self.level, bounds, self);
let mut non_default_params = Vec::with_capacity(lambda.sig.params.non_defaults.len()); let mut non_default_params = Vec::with_capacity(lambda.sig.params.non_defaults.len());
for sig in lambda.sig.params.non_defaults.iter() { for sig in lambda.sig.params.non_defaults.iter() {
let t = let pt =
self.instantiate_param_sig_t(sig, None, Some(&tv_ctx), RegistrationMode::Normal)?; self.instantiate_param_ty(sig, None, Some(&tv_ctx), RegistrationMode::Normal)?;
let pt = if let Some(name) = sig.inspect() {
ParamTy::kw(name.clone(), t)
} else {
ParamTy::anonymous(t)
};
non_default_params.push(pt); non_default_params.push(pt);
} }
let var_params = if let Some(p) = lambda.sig.params.var_args.as_ref() { let var_params = if let Some(p) = lambda.sig.params.var_args.as_ref() {
let t = let pt = self.instantiate_param_ty(p, None, Some(&tv_ctx), RegistrationMode::Normal)?;
self.instantiate_param_sig_t(p, None, Some(&tv_ctx), RegistrationMode::Normal)?;
let pt = if let Some(name) = p.inspect() {
ParamTy::kw(name.clone(), t)
} else {
ParamTy::anonymous(t)
};
Some(pt) Some(pt)
} else { } else {
None None
}; };
let mut default_params = Vec::with_capacity(lambda.sig.params.defaults.len()); let mut default_params = Vec::with_capacity(lambda.sig.params.defaults.len());
for sig in lambda.sig.params.defaults.iter() { for sig in lambda.sig.params.defaults.iter() {
let t = let pt =
self.instantiate_param_sig_t(sig, None, Some(&tv_ctx), RegistrationMode::Normal)?; self.instantiate_param_ty(sig, None, Some(&tv_ctx), RegistrationMode::Normal)?;
let pt = if let Some(name) = sig.inspect() {
ParamTy::kw(name.clone(), t)
} else {
ParamTy::anonymous(t)
};
default_params.push(pt); default_params.push(pt);
} }
// HACK: should avoid cloning // HACK: should avoid cloning
@ -661,28 +679,10 @@ impl Context {
(TyParam::Value(lhs), TyParam::Value(rhs)) => self (TyParam::Value(lhs), TyParam::Value(rhs)) => self
.eval_bin(op, lhs.clone(), rhs.clone()) .eval_bin(op, lhs.clone(), rhs.clone())
.map(TyParam::value), .map(TyParam::value),
(TyParam::FreeVar(fv), r) => { (TyParam::FreeVar(fv), r) if fv.is_linked() => self.eval_bin_tp(op, &*fv.crack(), r),
if fv.is_linked() { (TyParam::FreeVar(_), _) => Ok(TyParam::bin(op, lhs.clone(), rhs.clone())),
self.eval_bin_tp(op, &*fv.crack(), r) (l, TyParam::FreeVar(fv)) if fv.is_linked() => self.eval_bin_tp(op, l, &*fv.crack()),
} else { (_, TyParam::FreeVar(_)) => Ok(TyParam::bin(op, lhs.clone(), rhs.clone())),
Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
)))
}
}
(l, TyParam::FreeVar(fv)) => {
if fv.is_linked() {
self.eval_bin_tp(op, l, &*fv.crack())
} else {
Err(EvalErrors::from(EvalError::unreachable(
self.cfg.input.clone(),
fn_name!(),
line!(),
)))
}
}
(e @ TyParam::Erased(_), _) | (_, e @ TyParam::Erased(_)) => Ok(e.clone()), (e @ TyParam::Erased(_), _) | (_, e @ TyParam::Erased(_)) => Ok(e.clone()),
(l, r) => todo!("{l} {op} {r}"), (l, r) => todo!("{l} {op} {r}"),
} }
@ -845,6 +845,32 @@ impl Context {
} }
} }
} }
if lhs.is_unbound_var() {
let (sub, sup) = enum_unwrap!(lhs.as_ref(), Type::FreeVar)
.get_bound_types()
.unwrap();
if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) {
return Err(EvalErrors::from(EvalError::no_trait_impl_error(
self.cfg.input.clone(),
line!() as usize,
&sub,
&sup,
t_loc,
self.caused_by(),
None,
)));
}
}
// if the target can't be found in the supertype, the type will be dereferenced.
// In many cases, it is still better to determine the type variable than if the target is not found.
let coerced = self.deref_tyvar(*lhs.clone(), Variance::Covariant, t_loc)?;
if lhs.as_ref() != &coerced {
let proj = mono_proj(coerced, rhs);
self.eval_t_params(proj, level, t_loc).map(|t| {
self.coerce(&lhs);
t
})
} else {
let proj = mono_proj(*lhs, rhs); let proj = mono_proj(*lhs, rhs);
Err(EvalErrors::from(EvalError::no_candidate_error( Err(EvalErrors::from(EvalError::no_candidate_error(
self.cfg.input.clone(), self.cfg.input.clone(),
@ -855,6 +881,7 @@ impl Context {
self.get_no_candidate_hint(&proj), self.get_no_candidate_hint(&proj),
))) )))
} }
}
Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level, t_loc)?)), Type::Ref(l) => Ok(ref_(self.eval_t_params(*l, level, t_loc)?)),
Type::RefMut { before, after } => { Type::RefMut { before, after } => {
let before = self.eval_t_params(*before, level, t_loc)?; let before = self.eval_t_params(*before, level, t_loc)?;
@ -884,12 +911,12 @@ impl Context {
Type::And(l, r) => { Type::And(l, r) => {
let l = self.eval_t_params(*l, level, t_loc)?; let l = self.eval_t_params(*l, level, t_loc)?;
let r = self.eval_t_params(*r, level, t_loc)?; let r = self.eval_t_params(*r, level, t_loc)?;
Ok(and(l, r)) Ok(self.intersection(&l, &r))
} }
Type::Or(l, r) => { Type::Or(l, r) => {
let l = self.eval_t_params(*l, level, t_loc)?; let l = self.eval_t_params(*l, level, t_loc)?;
let r = self.eval_t_params(*r, level, t_loc)?; let r = self.eval_t_params(*r, level, t_loc)?;
Ok(or(l, r)) Ok(self.union(&l, &r))
} }
Type::Not(l, r) => { Type::Not(l, r) => {
let l = self.eval_t_params(*l, level, t_loc)?; let l = self.eval_t_params(*l, level, t_loc)?;
@ -971,6 +998,10 @@ impl Context {
OpKind::Mutate => Ok(self.get_tp_t(&val)?.mutate()), OpKind::Mutate => Ok(self.get_tp_t(&val)?.mutate()),
_ => todo!(), _ => todo!(),
}, },
TyParam::BinOp { op, lhs, rhs } => {
let op_name = op_to_name(op);
todo!("get type: {op_name}({lhs}, {rhs})")
}
other => todo!("{other}"), other => todo!("{other}"),
} }
} }

View file

@ -23,7 +23,9 @@ use erg_parser::ast::VarName;
use crate::context::initialize::const_func::*; use crate::context::initialize::const_func::*;
use crate::context::instantiate::{ConstTemplate, TyVarContext}; use crate::context::instantiate::{ConstTemplate, TyVarContext};
use crate::context::{ClassDefType, Context, ContextKind, DefaultInfo, ParamSpec, TraitInstance}; use crate::context::{
ClassDefType, Context, ContextKind, DefaultInfo, MethodType, ParamSpec, TraitInstance,
};
use crate::mod_cache::SharedModuleCache; use crate::mod_cache::SharedModuleCache;
use crate::varinfo::{Mutability, VarInfo, VarKind}; use crate::varinfo::{Mutability, VarInfo, VarKind};
use DefaultInfo::*; use DefaultInfo::*;
@ -77,6 +79,7 @@ impl Context {
} }
} }
/// FIXME: トレイトの汎化型を指定するのにも使っているので、この名前は適当でない
pub(crate) fn register_superclass(&mut self, sup: Type, sup_ctx: &Context) { pub(crate) fn register_superclass(&mut self, sup: Type, sup_ctx: &Context) {
self.super_classes.push(sup); self.super_classes.push(sup);
self.super_classes.extend(sup_ctx.super_classes.clone()); self.super_classes.extend(sup_ctx.super_classes.clone());
@ -114,23 +117,33 @@ impl Context {
.insert(name.clone(), ValueObj::builtin_t(t.clone())); .insert(name.clone(), ValueObj::builtin_t(t.clone()));
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) { if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) {
impls.push(TraitInstance::new(t.clone(), impl_trait.clone())); impls.insert(TraitInstance::new(t.clone(), impl_trait.clone()));
} else { } else {
self.trait_impls.insert( self.trait_impls.insert(
impl_trait.name(), impl_trait.name(),
vec![TraitInstance::new(t.clone(), impl_trait.clone())], set![TraitInstance::new(t.clone(), impl_trait.clone())],
); );
} }
} }
if ctx.kind == ContextKind::Trait { for (trait_method, vi) in ctx.decls.iter() {
for method in ctx.decls.keys() { if let Some(types) = self.method_to_traits.get_mut(trait_method.inspect()) {
if let Some(traits) = self.method_traits.get_mut(method.inspect()) { types.push(MethodType::new(t.clone(), vi.t.clone()));
traits.push(t.clone());
} else { } else {
self.method_traits self.method_to_traits.insert(
.insert(method.inspect().clone(), vec![t.clone()]); trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
} }
} }
for (class_method, vi) in ctx.locals.iter() {
if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
} else {
self.method_to_classes.insert(
class_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
}
} }
self.mono_types.insert(name, (t, ctx)); self.mono_types.insert(name, (t, ctx));
} }
@ -155,23 +168,33 @@ impl Context {
.insert(name.clone(), ValueObj::builtin_t(t.clone())); .insert(name.clone(), ValueObj::builtin_t(t.clone()));
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) { if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) {
impls.push(TraitInstance::new(t.clone(), impl_trait.clone())); impls.insert(TraitInstance::new(t.clone(), impl_trait.clone()));
} else { } else {
self.trait_impls.insert( self.trait_impls.insert(
impl_trait.name(), impl_trait.name(),
vec![TraitInstance::new(t.clone(), impl_trait.clone())], set![TraitInstance::new(t.clone(), impl_trait.clone())],
); );
} }
} }
if ctx.kind == ContextKind::Trait { for (trait_method, vi) in ctx.decls.iter() {
for method in ctx.decls.keys() { if let Some(traits) = self.method_to_traits.get_mut(trait_method.inspect()) {
if let Some(traits) = self.method_traits.get_mut(method.inspect()) { traits.push(MethodType::new(t.clone(), vi.t.clone()));
traits.push(t.clone());
} else { } else {
self.method_traits self.method_to_traits.insert(
.insert(method.inspect().clone(), vec![t.clone()]); trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
} }
} }
for (class_method, vi) in ctx.locals.iter() {
if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
} else {
self.method_to_classes.insert(
class_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
}
} }
self.poly_types.insert(name, (t, ctx)); self.poly_types.insert(name, (t, ctx));
} }
@ -209,7 +232,7 @@ impl Context {
let named = Self::builtin_mono_trait("Named", 2); let named = Self::builtin_mono_trait("Named", 2);
let mut mutable = Self::builtin_mono_trait("Mutable", 2); let mut mutable = Self::builtin_mono_trait("Mutable", 2);
let proj = mono_proj(mono_q("Self"), "ImmutType"); let proj = mono_proj(mono_q("Self"), "ImmutType");
let f_t = func(vec![param_t("old", proj.clone())], None, vec![], proj); let f_t = func(vec![kw("old", proj.clone())], None, vec![], proj);
let t = pr1_met(ref_mut(mono_q("Self"), None), f_t, NoneType); let t = pr1_met(ref_mut(mono_q("Self"), None), f_t, NoneType);
let t = quant( let t = quant(
t, t,
@ -229,7 +252,7 @@ impl Context {
ref_mut(mono_q("Self"), None), ref_mut(mono_q("Self"), None),
vec![], vec![],
None, None,
vec![param_t("n", Int)], vec![kw("n", Int)],
Str, Str,
); );
let t_read = quant( let t_read = quant(
@ -540,7 +563,6 @@ impl Context {
ratio.register_trait(Ratio, builtin_mono("Show"), ratio_show); ratio.register_trait(Ratio, builtin_mono("Show"), ratio_show);
let mut int = Self::builtin_mono_class("Int", 2); let mut int = Self::builtin_mono_class("Int", 2);
int.register_superclass(Float, &float); // TODO: Float -> Ratio int.register_superclass(Float, &float); // TODO: Float -> Ratio
int.register_superclass(Obj, &obj);
int.register_marker_trait(builtin_mono("Num")); int.register_marker_trait(builtin_mono("Num"));
int.register_marker_trait(builtin_mono("Ord")); int.register_marker_trait(builtin_mono("Ord"));
int.register_marker_trait(builtin_poly("Eq", vec![ty_tp(Int)])); int.register_marker_trait(builtin_poly("Eq", vec![ty_tp(Int)]));
@ -588,15 +610,13 @@ impl Context {
int.register_builtin_impl("Imag", Int, Const, Public); int.register_builtin_impl("Imag", Int, Const, Public);
let mut nat = Self::builtin_mono_class("Nat", 10); let mut nat = Self::builtin_mono_class("Nat", 10);
nat.register_superclass(Int, &int); nat.register_superclass(Int, &int);
nat.register_superclass(Float, &float); // TODO: Float -> Ratio
nat.register_superclass(Obj, &obj);
// class("Rational"), // class("Rational"),
// class("Integral"), // class("Integral"),
nat.register_builtin_impl( nat.register_builtin_impl(
"times!", "times!",
pr_met( pr_met(
Nat, Nat,
vec![param_t("p", nd_proc(vec![], None, NoneType))], vec![kw("p", nd_proc(vec![], None, NoneType))],
None, None,
vec![], vec![],
NoneType, NoneType,
@ -638,9 +658,6 @@ impl Context {
nat.register_builtin_impl("Imag", Nat, Const, Public); nat.register_builtin_impl("Imag", Nat, Const, Public);
let mut bool_ = Self::builtin_mono_class("Bool", 10); let mut bool_ = Self::builtin_mono_class("Bool", 10);
bool_.register_superclass(Nat, &nat); bool_.register_superclass(Nat, &nat);
bool_.register_superclass(Int, &int);
bool_.register_superclass(Float, &float); // TODO: Float -> Ratio
bool_.register_superclass(Obj, &obj);
// class("Rational"), // class("Rational"),
// class("Integral"), // class("Integral"),
// TODO: And, Or trait // TODO: And, Or trait
@ -671,6 +688,9 @@ impl Context {
bool_mutizable bool_mutizable
.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Bool!"))); .register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Bool!")));
bool_.register_trait(Bool, builtin_mono("Mutizable"), bool_mutizable); bool_.register_trait(Bool, builtin_mono("Mutizable"), bool_mutizable);
let mut bool_show = Self::builtin_methods("Show", 1);
bool_show.register_builtin_impl("to_str", fn0_met(Bool, Str), Immutable, Public);
bool_.register_trait(Bool, builtin_mono("Show"), bool_show);
let mut str_ = Self::builtin_mono_class("Str", 10); let mut str_ = Self::builtin_mono_class("Str", 10);
str_.register_superclass(Obj, &obj); str_.register_superclass(Obj, &obj);
str_.register_marker_trait(builtin_mono("Ord")); str_.register_marker_trait(builtin_mono("Ord"));
@ -679,7 +699,7 @@ impl Context {
"replace", "replace",
fn_met( fn_met(
Str, Str,
vec![param_t("pat", Str), param_t("into", Str)], vec![kw("pat", Str), kw("into", Str)],
None, None,
vec![], vec![],
Str, Str,
@ -693,7 +713,7 @@ impl Context {
Str, Str,
vec![], vec![],
None, None,
vec![param_t("encoding", Str), param_t("errors", Str)], vec![kw("encoding", Str), kw("errors", Str)],
builtin_mono("Bytes"), builtin_mono("Bytes"),
), ),
Immutable, Immutable,
@ -717,6 +737,9 @@ impl Context {
let mut str_mutizable = Self::builtin_methods("Mutizable", 2); let mut str_mutizable = Self::builtin_methods("Mutizable", 2);
str_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Str!"))); str_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Str!")));
str_.register_trait(Str, builtin_mono("Mutizable"), str_mutizable); str_.register_trait(Str, builtin_mono("Mutizable"), str_mutizable);
let mut str_show = Self::builtin_methods("Show", 1);
str_show.register_builtin_impl("to_str", fn0_met(Str, Str), Immutable, Public);
str_.register_trait(Str, builtin_mono("Show"), str_show);
let mut type_ = Self::builtin_mono_class("Type", 2); let mut type_ = Self::builtin_mono_class("Type", 2);
type_.register_superclass(Obj, &obj); type_.register_superclass(Obj, &obj);
type_.register_builtin_impl("mro", array(Type, TyParam::erased(Nat)), Immutable, Public); type_.register_builtin_impl("mro", array(Type, TyParam::erased(Nat)), Immutable, Public);
@ -726,7 +749,6 @@ impl Context {
type_.register_trait(Type, builtin_poly("Eq", vec![ty_tp(Type)]), type_eq); type_.register_trait(Type, builtin_poly("Eq", vec![ty_tp(Type)]), type_eq);
let mut class_type = Self::builtin_mono_class("ClassType", 2); let mut class_type = Self::builtin_mono_class("ClassType", 2);
class_type.register_superclass(Type, &type_); class_type.register_superclass(Type, &type_);
class_type.register_superclass(Obj, &obj);
class_type.register_marker_trait(builtin_mono("Named")); class_type.register_marker_trait(builtin_mono("Named"));
let mut class_eq = Self::builtin_methods("Eq", 2); let mut class_eq = Self::builtin_methods("Eq", 2);
class_eq.register_builtin_impl("__eq__", fn1_met(Class, Class, Bool), Const, Public); class_eq.register_builtin_impl("__eq__", fn1_met(Class, Class, Bool), Const, Public);
@ -759,7 +781,7 @@ impl Context {
let array_t = array(mono_q("T"), n.clone()); let array_t = array(mono_q("T"), n.clone());
let t = fn_met( let t = fn_met(
array_t.clone(), array_t.clone(),
vec![param_t("rhs", array(mono_q("T"), m.clone()))], vec![kw("rhs", array(mono_q("T"), m.clone()))],
None, None,
vec![], vec![],
array(mono_q("T"), n + m), array(mono_q("T"), n + m),
@ -784,14 +806,22 @@ impl Context {
); );
array_.register_trait( array_.register_trait(
array_t.clone(), array_t.clone(),
builtin_poly("Eq", vec![ty_tp(array_t)]), builtin_poly("Eq", vec![ty_tp(array_t.clone())]),
array_eq, array_eq,
); );
array_.register_marker_trait(builtin_mono("Mutizable")); array_.register_marker_trait(builtin_mono("Mutizable"));
array_.register_marker_trait(builtin_poly("Seq", vec![ty_tp(mono_q("T"))])); array_.register_marker_trait(builtin_poly("Seq", vec![ty_tp(mono_q("T"))]));
let mut array_show = Self::builtin_methods("Show", 1);
array_show.register_builtin_impl(
"to_str",
fn0_met(array_t.clone(), Str),
Immutable,
Public,
);
array_.register_trait(array_t, builtin_mono("Show"), array_show);
let mut bytes = Self::builtin_mono_class("Bytes", 2); let mut bytes = Self::builtin_mono_class("Bytes", 2);
bytes.register_superclass(Obj, &obj); bytes.register_superclass(Obj, &obj);
// TODO: make Tuple6, Tuple7, ... etc. // FIXME: replace to Tuple Ts (e.g. Tuple [Int, Str])
let mut tuple_ = Self::builtin_mono_class("Tuple", 2); let mut tuple_ = Self::builtin_mono_class("Tuple", 2);
tuple_.register_superclass(Obj, &obj); tuple_.register_superclass(Obj, &obj);
let mut tuple_eq = Self::builtin_methods("Eq", 2); let mut tuple_eq = Self::builtin_methods("Eq", 2);
@ -808,7 +838,6 @@ impl Context {
); );
let mut tuple1 = Self::builtin_poly_class("Tuple1", vec![PS::t_nd("A")], 2); let mut tuple1 = Self::builtin_poly_class("Tuple1", vec![PS::t_nd("A")], 2);
tuple1.register_superclass(builtin_mono("Tuple"), &tuple_); tuple1.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple1.register_superclass(Obj, &obj);
let mut tuple1_eq = Self::builtin_methods("Eq", 2); let mut tuple1_eq = Self::builtin_methods("Eq", 2);
tuple1_eq.register_builtin_impl( tuple1_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -830,7 +859,6 @@ impl Context {
); );
let mut tuple2 = Self::builtin_poly_class("Tuple2", vec![PS::t_nd("A"), PS::t_nd("B")], 2); let mut tuple2 = Self::builtin_poly_class("Tuple2", vec![PS::t_nd("A"), PS::t_nd("B")], 2);
tuple2.register_superclass(builtin_mono("Tuple"), &tuple_); tuple2.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple2.register_superclass(Obj, &obj);
let mut tuple2_eq = Self::builtin_methods("Eq", 2); let mut tuple2_eq = Self::builtin_methods("Eq", 2);
tuple2_eq.register_builtin_impl( tuple2_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -859,7 +887,6 @@ impl Context {
2, 2,
); );
tuple3.register_superclass(builtin_mono("Tuple"), &tuple_); tuple3.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple3.register_superclass(Obj, &obj);
let mut tuple3_eq = Self::builtin_methods("Eq", 2); let mut tuple3_eq = Self::builtin_methods("Eq", 2);
tuple3_eq.register_builtin_impl( tuple3_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -897,7 +924,6 @@ impl Context {
2, 2,
); );
tuple4.register_superclass(builtin_mono("Tuple"), &tuple_); tuple4.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple4.register_superclass(Obj, &obj);
let mut tuple4_eq = Self::builtin_methods("Eq", 2); let mut tuple4_eq = Self::builtin_methods("Eq", 2);
tuple4_eq.register_builtin_impl( tuple4_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -961,7 +987,6 @@ impl Context {
2, 2,
); );
tuple5.register_superclass(builtin_mono("Tuple"), &tuple_); tuple5.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple5.register_superclass(Obj, &obj);
let mut tuple5_eq = Self::builtin_methods("Eq", 2); let mut tuple5_eq = Self::builtin_methods("Eq", 2);
tuple5_eq.register_builtin_impl( tuple5_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -1030,7 +1055,6 @@ impl Context {
2, 2,
); );
tuple6.register_superclass(builtin_mono("Tuple"), &tuple_); tuple6.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple6.register_superclass(Obj, &obj);
let mut tuple6_eq = Self::builtin_methods("Eq", 2); let mut tuple6_eq = Self::builtin_methods("Eq", 2);
tuple6_eq.register_builtin_impl( tuple6_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -1104,7 +1128,6 @@ impl Context {
2, 2,
); );
tuple7.register_superclass(builtin_mono("Tuple"), &tuple_); tuple7.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple7.register_superclass(Obj, &obj);
let mut tuple7_eq = Self::builtin_methods("Eq", 2); let mut tuple7_eq = Self::builtin_methods("Eq", 2);
tuple7_eq.register_builtin_impl( tuple7_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -1183,7 +1206,6 @@ impl Context {
2, 2,
); );
tuple8.register_superclass(builtin_mono("Tuple"), &tuple_); tuple8.register_superclass(builtin_mono("Tuple"), &tuple_);
tuple8.register_superclass(Obj, &obj);
let mut tuple8_eq = Self::builtin_methods("Eq", 2); let mut tuple8_eq = Self::builtin_methods("Eq", 2);
tuple8_eq.register_builtin_impl( tuple8_eq.register_builtin_impl(
"__eq__", "__eq__",
@ -1256,13 +1278,11 @@ impl Context {
let mut record_type = Self::builtin_mono_class("RecordType", 2); let mut record_type = Self::builtin_mono_class("RecordType", 2);
record_type.register_superclass(builtin_mono("Record"), &record); record_type.register_superclass(builtin_mono("Record"), &record);
record_type.register_superclass(builtin_mono("Type"), &type_); record_type.register_superclass(builtin_mono("Type"), &type_);
record_type.register_superclass(Obj, &obj);
let mut float_mut = Self::builtin_mono_class("Float!", 2); let mut float_mut = Self::builtin_mono_class("Float!", 2);
float_mut.register_superclass(Float, &float); float_mut.register_superclass(Float, &float);
float_mut.register_superclass(Obj, &obj);
let mut float_mut_mutable = Self::builtin_methods("Mutable", 2); let mut float_mut_mutable = Self::builtin_methods("Mutable", 2);
float_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Float)); float_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Float));
let f_t = param_t("f", func(vec![param_t("old", Float)], None, vec![], Float)); let f_t = kw("f", func(vec![kw("old", Float)], None, vec![], Float));
let t = pr_met( let t = pr_met(
ref_mut(builtin_mono("Float!"), None), ref_mut(builtin_mono("Float!"), None),
vec![f_t], vec![f_t],
@ -1278,13 +1298,12 @@ impl Context {
); );
let mut ratio_mut = Self::builtin_mono_class("Ratio!", 2); let mut ratio_mut = Self::builtin_mono_class("Ratio!", 2);
ratio_mut.register_superclass(Ratio, &ratio); ratio_mut.register_superclass(Ratio, &ratio);
ratio_mut.register_superclass(Obj, &obj);
let mut ratio_mut_mutable = Self::builtin_methods("Mutable", 2); let mut ratio_mut_mutable = Self::builtin_methods("Mutable", 2);
ratio_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio)); ratio_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio));
let f_t = param_t( let f_t = kw(
"f", "f",
func( func(
vec![param_t("old", builtin_mono("Ratio"))], vec![kw("old", builtin_mono("Ratio"))],
None, None,
vec![], vec![],
builtin_mono("Ratio"), builtin_mono("Ratio"),
@ -1306,10 +1325,9 @@ impl Context {
let mut int_mut = Self::builtin_mono_class("Int!", 2); let mut int_mut = Self::builtin_mono_class("Int!", 2);
int_mut.register_superclass(Int, &int); int_mut.register_superclass(Int, &int);
int_mut.register_superclass(builtin_mono("Float!"), &float_mut); int_mut.register_superclass(builtin_mono("Float!"), &float_mut);
int_mut.register_superclass(Obj, &obj);
let mut int_mut_mutable = Self::builtin_methods("Mutable", 2); let mut int_mut_mutable = Self::builtin_methods("Mutable", 2);
int_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Int)); int_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Int));
let f_t = param_t("f", func(vec![param_t("old", Int)], None, vec![], Int)); let f_t = kw("f", func(vec![kw("old", Int)], None, vec![], Int));
let t = pr_met( let t = pr_met(
ref_mut(builtin_mono("Int!"), None), ref_mut(builtin_mono("Int!"), None),
vec![f_t], vec![f_t],
@ -1326,11 +1344,9 @@ impl Context {
let mut nat_mut = Self::builtin_mono_class("Nat!", 2); let mut nat_mut = Self::builtin_mono_class("Nat!", 2);
nat_mut.register_superclass(Nat, &nat); nat_mut.register_superclass(Nat, &nat);
nat_mut.register_superclass(builtin_mono("Int!"), &int_mut); nat_mut.register_superclass(builtin_mono("Int!"), &int_mut);
nat_mut.register_superclass(builtin_mono("Float!"), &float_mut);
nat_mut.register_superclass(Obj, &obj);
let mut nat_mut_mutable = Self::builtin_methods("Mutable", 2); let mut nat_mut_mutable = Self::builtin_methods("Mutable", 2);
nat_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Nat)); nat_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Nat));
let f_t = param_t("f", func(vec![param_t("old", Nat)], None, vec![], Nat)); let f_t = kw("f", func(vec![kw("old", Nat)], None, vec![], Nat));
let t = pr_met( let t = pr_met(
ref_mut(builtin_mono("Nat!"), None), ref_mut(builtin_mono("Nat!"), None),
vec![f_t], vec![f_t],
@ -1347,12 +1363,9 @@ impl Context {
let mut bool_mut = Self::builtin_mono_class("Bool!", 2); let mut bool_mut = Self::builtin_mono_class("Bool!", 2);
bool_mut.register_superclass(Bool, &bool_); bool_mut.register_superclass(Bool, &bool_);
bool_mut.register_superclass(builtin_mono("Nat!"), &nat_mut); bool_mut.register_superclass(builtin_mono("Nat!"), &nat_mut);
bool_mut.register_superclass(builtin_mono("Int!"), &int_mut);
bool_mut.register_superclass(builtin_mono("Float!"), &float_mut);
bool_mut.register_superclass(Obj, &obj);
let mut bool_mut_mutable = Self::builtin_methods("Mutable", 2); let mut bool_mut_mutable = Self::builtin_methods("Mutable", 2);
bool_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Bool)); bool_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Bool));
let f_t = param_t("f", func(vec![param_t("old", Bool)], None, vec![], Bool)); let f_t = kw("f", func(vec![kw("old", Bool)], None, vec![], Bool));
let t = pr_met( let t = pr_met(
ref_mut(builtin_mono("Bool!"), None), ref_mut(builtin_mono("Bool!"), None),
vec![f_t], vec![f_t],
@ -1368,10 +1381,9 @@ impl Context {
); );
let mut str_mut = Self::builtin_mono_class("Str!", 2); let mut str_mut = Self::builtin_mono_class("Str!", 2);
str_mut.register_superclass(Str, &str_); str_mut.register_superclass(Str, &str_);
str_mut.register_superclass(Obj, &obj);
let mut str_mut_mutable = Self::builtin_methods("Mutable", 2); let mut str_mut_mutable = Self::builtin_methods("Mutable", 2);
str_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Str)); str_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Str));
let f_t = param_t("f", func(vec![param_t("old", Str)], None, vec![], Str)); let f_t = kw("f", func(vec![kw("old", Str)], None, vec![], Str));
let t = pr_met( let t = pr_met(
ref_mut(builtin_mono("Str!"), None), ref_mut(builtin_mono("Str!"), None),
vec![f_t], vec![f_t],
@ -1393,7 +1405,7 @@ impl Context {
ref_mut(builtin_mono("File!"), None), ref_mut(builtin_mono("File!"), None),
vec![], vec![],
None, None,
vec![param_t("n", Int)], vec![kw("n", Int)],
Str, Str,
), ),
Immutable, Immutable,
@ -1412,7 +1424,6 @@ impl Context {
2, 2,
); );
array_mut_.register_superclass(array_t.clone(), &array_); array_mut_.register_superclass(array_t.clone(), &array_);
array_mut_.register_superclass(Obj, &obj);
let t = pr_met( let t = pr_met(
ref_mut( ref_mut(
array_mut_t.clone(), array_mut_t.clone(),
@ -1421,7 +1432,7 @@ impl Context {
vec![ty_tp(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![kw("elem", mono_q("T"))],
None, None,
vec![], vec![],
NoneType, NoneType,
@ -1433,10 +1444,7 @@ impl Context {
array_mut_.register_builtin_impl("push!", t, Immutable, Public); array_mut_.register_builtin_impl("push!", t, Immutable, Public);
let t = pr_met( let t = pr_met(
array_mut_t.clone(), array_mut_t.clone(),
vec![param_t( vec![kw("f", nd_func(vec![anon(mono_q("T"))], None, mono_q("T")))],
"f",
nd_func(vec![anon(mono_q("T"))], None, mono_q("T")),
)],
None, None,
vec![], vec![],
NoneType, NoneType,
@ -1446,10 +1454,10 @@ impl Context {
set! {static_instance("T", Type), static_instance("N", builtin_mono("Nat!"))}, set! {static_instance("T", Type), static_instance("N", builtin_mono("Nat!"))},
); );
array_mut_.register_builtin_impl("strict_map!", t, Immutable, Public); array_mut_.register_builtin_impl("strict_map!", t, Immutable, Public);
let f_t = param_t( let f_t = kw(
"f", "f",
func( func(
vec![param_t("old", array_t.clone())], vec![kw("old", array_t.clone())],
None, None,
vec![], vec![],
array_t.clone(), array_t.clone(),
@ -1487,16 +1495,16 @@ impl Context {
); );
let mut proc = Self::builtin_mono_class("Proc", 2); let mut proc = Self::builtin_mono_class("Proc", 2);
proc.register_superclass(Obj, &obj); proc.register_superclass(Obj, &obj);
// TODO: lambda let mut named_proc = Self::builtin_mono_class("NamedProc", 2);
proc.register_marker_trait(builtin_mono("Named")); named_proc.register_superclass(Obj, &obj);
named_proc.register_marker_trait(builtin_mono("Named"));
let mut func = Self::builtin_mono_class("Func", 2); let mut func = Self::builtin_mono_class("Func", 2);
func.register_superclass(builtin_mono("Proc"), &proc); func.register_superclass(builtin_mono("Proc"), &proc);
func.register_superclass(Obj, &obj); let mut named_func = Self::builtin_mono_class("NamedFunc", 2);
// TODO: lambda named_func.register_superclass(builtin_mono("Func"), &func);
func.register_marker_trait(builtin_mono("Named")); named_func.register_marker_trait(builtin_mono("Named"));
let mut qfunc = Self::builtin_mono_class("QuantifiedFunc", 2); let mut qfunc = Self::builtin_mono_class("QuantifiedFunc", 2);
qfunc.register_superclass(builtin_mono("Func"), &func); qfunc.register_superclass(builtin_mono("Func"), &func);
qfunc.register_superclass(Obj, &obj);
self.register_builtin_type(Obj, obj, Const); self.register_builtin_type(Obj, obj, Const);
// self.register_type(mono("Record"), vec![], record, Const); // self.register_type(mono("Record"), vec![], record, Const);
self.register_builtin_type(Int, int, Const); self.register_builtin_type(Int, int, Const);
@ -1586,42 +1594,50 @@ impl Context {
self.register_builtin_type(range_t, range, Const); self.register_builtin_type(range_t, range, Const);
self.register_builtin_type(builtin_mono("Tuple"), tuple_, Const); self.register_builtin_type(builtin_mono("Tuple"), tuple_, Const);
self.register_builtin_type(builtin_mono("Proc"), proc, Const); self.register_builtin_type(builtin_mono("Proc"), proc, Const);
self.register_builtin_type(builtin_mono("NamedProc"), named_proc, Const);
self.register_builtin_type(builtin_mono("Func"), func, Const); self.register_builtin_type(builtin_mono("Func"), func, Const);
self.register_builtin_type(builtin_mono("NamedFunc"), named_func, Const);
self.register_builtin_type(builtin_mono("QuantifiedFunc"), qfunc, Const); self.register_builtin_type(builtin_mono("QuantifiedFunc"), qfunc, Const);
} }
fn init_builtin_funcs(&mut self) { fn init_builtin_funcs(&mut self) {
let t_abs = nd_func(vec![param_t("n", builtin_mono("Num"))], None, Nat); let t_abs = nd_func(vec![kw("n", builtin_mono("Num"))], None, Nat);
let t_assert = func( let t_assert = func(
vec![param_t("condition", Bool)], vec![kw("condition", Bool)],
None, None,
vec![param_t("err_message", Str)], vec![kw("err_message", Str)],
NoneType, NoneType,
); );
let t_classof = nd_func(vec![param_t("old", Obj)], None, Class); let t_classof = nd_func(vec![kw("old", Obj)], None, Class);
let t_compile = nd_func(vec![param_t("src", Str)], None, Code); let t_compile = nd_func(vec![kw("src", Str)], None, Code);
let t_cond = nd_func( let t_cond = nd_func(
vec![ vec![
param_t("condition", Bool), kw("condition", Bool),
param_t("then", mono_q("T")), kw("then", mono_q("T")),
param_t("else", mono_q("T")), kw("else", mono_q("T")),
], ],
None, None,
mono_q("T"), mono_q("T"),
); );
let t_cond = quant(t_cond, set! {static_instance("T", Type)}); let t_cond = quant(t_cond, set! {static_instance("T", Type)});
let t_discard = nd_func(vec![param_t("old", Obj)], None, NoneType); let t_discard = nd_func(vec![kw("obj", Obj)], None, NoneType);
// FIXME: quantify
let t_if = func( let t_if = func(
vec![ vec![
param_t("cond", Bool), kw("cond", Bool),
param_t("then", nd_func(vec![], None, mono_q("T"))), kw("then", nd_func(vec![], None, mono_q("T"))),
], ],
None, None,
vec![param_t("else", nd_func(vec![], None, mono_q("T")))], vec![kw_default(
or(mono_q("T"), NoneType), "else",
nd_func(vec![], None, mono_q("U")),
nd_func(vec![], None, NoneType),
)],
or(mono_q("T"), mono_q("U")),
);
let t_if = quant(
t_if,
set! {static_instance("T", Type), static_instance("U", Type)},
); );
let t_if = quant(t_if, set! {static_instance("T", Type)});
let t_import = nd_func( let t_import = nd_func(
vec![anon(tp_enum(Str, set! {mono_q_tp("Path")}))], vec![anon(tp_enum(Str, set! {mono_q_tp("Path")}))],
None, None,
@ -1630,12 +1646,12 @@ impl Context {
let t_import = quant(t_import, set! {static_instance("Path", Str)}); let t_import = quant(t_import, set! {static_instance("Path", Str)});
let t_log = func( let t_log = func(
vec![], vec![],
Some(param_t("objects", ref_(Obj))), Some(kw("objects", ref_(Obj))),
vec![ vec![
param_t("sep", Str), kw("sep", Str),
param_t("end", Str), kw("end", Str),
param_t("file", builtin_mono("Write")), kw("file", builtin_mono("Write")),
param_t("flush", Bool), kw("flush", Bool),
], ],
NoneType, NoneType,
); );
@ -1644,9 +1660,9 @@ impl Context {
None, None,
module(mono_q_tp("Path")), module(mono_q_tp("Path")),
); );
let t_panic = nd_func(vec![param_t("err_message", Str)], None, NoneType); let t_panic = nd_func(vec![kw("err_message", Str)], None, NoneType);
let t_pyimport = quant(t_pyimport, set! {static_instance("Path", Str)}); let t_pyimport = quant(t_pyimport, set! {static_instance("Path", Str)});
let t_quit = func(vec![], None, vec![param_t("code", Int)], NoneType); let t_quit = func(vec![], None, vec![kw("code", Int)], NoneType);
let t_exit = t_quit.clone(); let t_exit = t_quit.clone();
self.register_builtin_impl("abs", t_abs, Immutable, Private); self.register_builtin_impl("abs", t_abs, Immutable, Private);
self.register_builtin_impl("assert", t_assert, Const, Private); // assert casting に悪影響が出る可能性があるため、Constとしておく self.register_builtin_impl("assert", t_assert, Const, Private); // assert casting に悪影響が出る可能性があるため、Constとしておく
@ -1668,17 +1684,17 @@ impl Context {
fn init_builtin_const_funcs(&mut self) { fn init_builtin_const_funcs(&mut self) {
let class_t = func( let class_t = func(
vec![param_t("Requirement", Type)], vec![kw("Requirement", Type)],
None, None,
vec![param_t("Impl", Type)], vec![kw("Impl", Type)],
Class, Class,
); );
let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t, None)); let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t, None));
self.register_builtin_const("Class", ValueObj::Subr(class)); self.register_builtin_const("Class", ValueObj::Subr(class));
let inherit_t = func( let inherit_t = func(
vec![param_t("Super", Class)], vec![kw("Super", Class)],
None, None,
vec![param_t("Impl", Type), param_t("Additional", Type)], vec![kw("Impl", Type), kw("Additional", Type)],
Class, Class,
); );
let inherit = ConstSubr::Builtin(BuiltinConstSubr::new( let inherit = ConstSubr::Builtin(BuiltinConstSubr::new(
@ -1689,17 +1705,17 @@ impl Context {
)); ));
self.register_builtin_const("Inherit", ValueObj::Subr(inherit)); self.register_builtin_const("Inherit", ValueObj::Subr(inherit));
let trait_t = func( let trait_t = func(
vec![param_t("Requirement", Type)], vec![kw("Requirement", Type)],
None, None,
vec![param_t("Impl", Type)], vec![kw("Impl", Type)],
Trait, Trait,
); );
let trait_ = ConstSubr::Builtin(BuiltinConstSubr::new("Trait", trait_func, trait_t, None)); let trait_ = ConstSubr::Builtin(BuiltinConstSubr::new("Trait", trait_func, trait_t, None));
self.register_builtin_const("Trait", ValueObj::Subr(trait_)); self.register_builtin_const("Trait", ValueObj::Subr(trait_));
let subsume_t = func( let subsume_t = func(
vec![param_t("Super", Trait)], vec![kw("Super", Trait)],
None, None,
vec![param_t("Impl", Type), param_t("Additional", Type)], vec![kw("Impl", Type), kw("Additional", Type)],
Trait, Trait,
); );
let subsume = ConstSubr::Builtin(BuiltinConstSubr::new( let subsume = ConstSubr::Builtin(BuiltinConstSubr::new(
@ -1718,42 +1734,45 @@ impl Context {
None, None,
)); ));
self.register_builtin_const("Inheritable", ValueObj::Subr(inheritable)); self.register_builtin_const("Inheritable", ValueObj::Subr(inheritable));
// TODO: register Del function object
let t_del = nd_func(vec![kw("obj", Obj)], None, NoneType);
self.register_builtin_impl("Del", t_del, Immutable, Private);
} }
fn init_builtin_procs(&mut self) { fn init_builtin_procs(&mut self) {
let t_dir = proc( let t_dir = proc(
vec![param_t("obj", ref_(Obj))], vec![kw("obj", ref_(Obj))],
None, None,
vec![], vec![],
array(Str, TyParam::erased(Nat)), array(Str, TyParam::erased(Nat)),
); );
let t_print = proc( let t_print = proc(
vec![], vec![],
Some(param_t("objects", ref_(Obj))), Some(kw("objects", ref_(Obj))),
vec![ vec![
param_t("sep", Str), kw("sep", Str),
param_t("end", Str), kw("end", Str),
param_t("file", builtin_mono("Write")), kw("file", builtin_mono("Write")),
param_t("flush", Bool), kw("flush", Bool),
], ],
NoneType, NoneType,
); );
let t_id = nd_func(vec![param_t("old", Obj)], None, Nat); let t_id = nd_func(vec![kw("old", Obj)], None, Nat);
let t_input = proc(vec![], None, vec![param_t("msg", Str)], Str); let t_input = proc(vec![], None, vec![kw("msg", Str)], Str);
let t_if = proc( let t_if = proc(
vec![ vec![
param_t("cond", Bool), kw("cond", Bool),
param_t("then", nd_proc(vec![], None, mono_q("T"))), kw("then", nd_proc(vec![], None, mono_q("T"))),
], ],
None, None,
vec![param_t("else", nd_proc(vec![], None, mono_q("T")))], vec![kw("else", nd_proc(vec![], None, mono_q("T")))],
or(mono_q("T"), NoneType), or(mono_q("T"), NoneType),
); );
let t_if = quant(t_if, set! {static_instance("T", Type)}); let t_if = quant(t_if, set! {static_instance("T", Type)});
let t_for = nd_proc( let t_for = nd_proc(
vec![ vec![
param_t("iter", iter(mono_q("T"))), kw("iter", iter(mono_q("T"))),
param_t("p", nd_proc(vec![anon(mono_q("T"))], None, NoneType)), kw("p", nd_proc(vec![anon(mono_q("T"))], None, NoneType)),
], ],
None, None,
NoneType, NoneType,
@ -1761,22 +1780,22 @@ impl Context {
let t_for = quant(t_for, set! {static_instance("T", Type)}); let t_for = quant(t_for, set! {static_instance("T", Type)});
let t_while = nd_proc( let t_while = nd_proc(
vec![ vec![
param_t("cond", builtin_mono("Bool!")), kw("cond", builtin_mono("Bool!")),
param_t("p", nd_proc(vec![], None, NoneType)), kw("p", nd_proc(vec![], None, NoneType)),
], ],
None, None,
NoneType, NoneType,
); );
let t_open = proc( let t_open = proc(
vec![param_t("file", mono_q("P"))], vec![kw("file", mono_q("P"))],
None, None,
vec![ vec![
param_t("mode", Str), kw("mode", Str),
param_t("buffering", Int), kw("buffering", Int),
param_t("encoding", or(Str, NoneType)), kw("encoding", or(Str, NoneType)),
param_t("errors", or(Str, NoneType)), kw("errors", or(Str, NoneType)),
param_t("newline", or(Str, NoneType)), kw("newline", or(Str, NoneType)),
param_t("closefd", Bool), kw("closefd", Bool),
// param_t("opener", option), // param_t("opener", option),
], ],
builtin_mono("File!"), builtin_mono("File!"),
@ -1788,8 +1807,8 @@ impl Context {
// TODO: T <: With // TODO: T <: With
let t_with = nd_proc( let t_with = nd_proc(
vec![ vec![
param_t("obj", mono_q("T")), kw("obj", mono_q("T")),
param_t("p!", nd_proc(vec![anon(mono_q("T"))], None, mono_q("U"))), kw("p!", nd_proc(vec![anon(mono_q("T"))], None, mono_q("U"))),
], ],
None, None,
mono_q("U"), mono_q("U"),
@ -1815,7 +1834,7 @@ impl Context {
let r = mono_q("R"); let r = mono_q("R");
let params = vec![ty_tp(mono_q("R"))]; let params = vec![ty_tp(mono_q("R"))];
let op_t = nd_func( let op_t = nd_func(
vec![param_t("lhs", l.clone()), param_t("rhs", r.clone())], vec![kw("lhs", l.clone()), kw("rhs", r.clone())],
None, None,
mono_proj(mono_q("L"), "Output"), mono_proj(mono_q("L"), "Output"),
); );

View file

@ -2,7 +2,7 @@ use erg_common::set;
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_type::constructors::{ use erg_type::constructors::{
builtin_mono, builtin_poly, mono_q, nd_proc, param_t, proc, quant, static_instance, ty_tp, builtin_mono, builtin_poly, kw, mono_q, nd_proc, proc, quant, static_instance, ty_tp,
}; };
use erg_type::Type; use erg_type::Type;
use Type::*; use Type::*;
@ -21,8 +21,8 @@ impl Context {
vec![], vec![],
None, None,
vec![ vec![
param_t("a", builtin_mono("Num")), // TODO: NoneType, int, float, str, bytes, bytearray kw("a", builtin_mono("Num")), // TODO: NoneType, int, float, str, bytes, bytearray
param_t("version", Int), kw("version", Int),
], ],
NoneType, NoneType,
), ),
@ -31,15 +31,12 @@ impl Context {
); );
random.register_builtin_impl( random.register_builtin_impl(
"randint!", "randint!",
nd_proc(vec![param_t("a", Int), param_t("b", Int)], None, Int), nd_proc(vec![kw("a", Int), kw("b", Int)], None, Int),
Immutable, Immutable,
Public, Public,
); );
let t = nd_proc( let t = nd_proc(
vec![param_t( vec![kw("seq", builtin_poly("Seq", vec![ty_tp(mono_q("T"))]))],
"seq",
builtin_poly("Seq", vec![ty_tp(mono_q("T"))]),
)],
None, None,
mono_q("T"), mono_q("T"),
); );

View file

@ -1,6 +1,6 @@
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_type::constructors::{builtin_mono, func, or, param_t}; use erg_type::constructors::{builtin_mono, func, kw, or};
use erg_type::Type; use erg_type::Type;
use Type::*; use Type::*;
@ -21,10 +21,10 @@ impl Context {
vec![], vec![],
None, None,
vec![ vec![
param_t("family", Int), kw("family", Int),
param_t("type", Int), kw("type", Int),
param_t("proto", Int), kw("proto", Int),
param_t("fileno", or(Int, NoneType)), kw("fileno", or(Int, NoneType)),
], ],
builtin_mono("Socket!"), builtin_mono("Socket!"),
), ),

View file

@ -2,7 +2,7 @@ use std::path::PathBuf;
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_type::constructors::{builtin_mono, module_from_path, mono, or, param_t, proc}; use erg_type::constructors::{builtin_mono, kw, module_from_path, mono, or, proc};
use erg_type::Type; use erg_type::Type;
use Type::*; use Type::*;
@ -22,11 +22,11 @@ impl Context {
urllib.register_builtin_impl("request", module_from_path("request"), Immutable, Public); urllib.register_builtin_impl("request", module_from_path("request"), Immutable, Public);
let mut request = Context::builtin_module("urllib.request", 15); let mut request = Context::builtin_module("urllib.request", 15);
let t = proc( let t = proc(
vec![param_t("url", or(Str, mono("urllib.request", "Request")))], vec![kw("url", or(Str, mono("urllib.request", "Request")))],
None, None,
vec![ vec![
param_t("data", or(builtin_mono("Bytes"), NoneType)), kw("data", or(builtin_mono("Bytes"), NoneType)),
param_t("timeout", or(Nat, NoneType)), kw("timeout", or(Nat, NoneType)),
], ],
mono("http.client", "HTTPResponse"), mono("http.client", "HTTPResponse"),
); );

View file

@ -16,7 +16,10 @@ use ast::VarName;
use erg_parser::ast::{self, Identifier}; use erg_parser::ast::{self, Identifier};
use erg_parser::token::Token; use erg_parser::token::Token;
use erg_type::constructors::{builtin_mono, func, module, mono, mono_proj, v_enum}; use erg_type::constructors::{
anon, builtin_mono, free_var, func, module, mono, mono_proj, subr_t, v_enum,
};
use erg_type::free::Constraint;
use erg_type::typaram::TyParam; use erg_type::typaram::TyParam;
use erg_type::value::{GenTypeObj, TypeObj, ValueObj}; use erg_type::value::{GenTypeObj, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, SubrKind, SubrType, TyBound, Type}; use erg_type::{HasType, ParamTy, SubrKind, SubrType, TyBound, Type};
@ -32,6 +35,8 @@ use crate::varinfo::VarInfo;
use RegistrationMode::*; use RegistrationMode::*;
use Visibility::*; use Visibility::*;
use super::MethodType;
impl Context { impl Context {
pub(crate) fn validate_var_sig_t( pub(crate) fn validate_var_sig_t(
&self, &self,
@ -93,7 +98,7 @@ impl Context {
) -> SingleTyCheckResult<&Context> { ) -> SingleTyCheckResult<&Context> {
match obj { match obj {
hir::Expr::Accessor(hir::Accessor::Ident(ident)) => { hir::Expr::Accessor(hir::Accessor::Ident(ident)) => {
self.get_singular_ctx_from_ident(&ident.clone().downcast(), namespace) self.get_singular_ctx_by_ident(&ident.clone().downcast(), namespace)
} }
hir::Expr::Accessor(hir::Accessor::Attr(attr)) => { hir::Expr::Accessor(hir::Accessor::Attr(attr)) => {
// REVIEW: 両方singularとは限らない? // REVIEW: 両方singularとは限らない?
@ -113,12 +118,12 @@ impl Context {
} }
} }
pub fn get_singular_ctx_from_ident( pub fn get_singular_ctx_by_ident(
&self, &self,
ident: &ast::Identifier, ident: &ast::Identifier,
namespace: &Str, namespace: &Str,
) -> SingleTyCheckResult<&Context> { ) -> SingleTyCheckResult<&Context> {
self.get_mod(ident) self.get_mod(ident.inspect())
.or_else(|| self.rec_get_type(ident.inspect()).map(|(_, ctx)| ctx)) .or_else(|| self.rec_get_type(ident.inspect()).map(|(_, ctx)| ctx))
.ok_or_else(|| { .ok_or_else(|| {
TyCheckError::no_var_error( TyCheckError::no_var_error(
@ -132,7 +137,7 @@ impl Context {
}) })
} }
pub fn get_mut_singular_ctx_from_ident( pub fn get_mut_singular_ctx_by_ident(
&mut self, &mut self,
ident: &ast::Identifier, ident: &ast::Identifier,
namespace: &Str, namespace: &Str,
@ -157,7 +162,7 @@ impl Context {
) -> SingleTyCheckResult<&mut Context> { ) -> SingleTyCheckResult<&mut Context> {
match obj { match obj {
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => { ast::Expr::Accessor(ast::Accessor::Ident(ident)) => {
self.get_mut_singular_ctx_from_ident(ident, namespace) self.get_mut_singular_ctx_by_ident(ident, namespace)
} }
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => { ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
// REVIEW: 両方singularとは限らない? // REVIEW: 両方singularとは限らない?
@ -335,6 +340,30 @@ impl Context {
} }
} }
pub(crate) fn rec_get_decl_t(
&self,
ident: &Identifier,
input: &Input,
namespace: &Str,
) -> SingleTyCheckResult<Type> {
if let Some(vi) = self.decls.get(&ident.inspect()[..]) {
self.validate_visibility(ident, vi, input, namespace)?;
Ok(vi.t())
} else {
if let Some(parent) = self.get_outer().or_else(|| self.get_builtins()) {
return parent.rec_get_decl_t(ident, input, namespace);
}
Err(TyCheckError::no_var_error(
input.clone(),
line!() as usize,
ident.loc(),
namespace.into(),
ident.inspect(),
self.get_similar_name(ident.inspect()),
))
}
}
pub(crate) fn rec_get_attr_t( pub(crate) fn rec_get_attr_t(
&self, &self,
obj: &hir::Expr, obj: &hir::Expr,
@ -540,10 +569,12 @@ impl Context {
self.get_similar_attr_from_singular(obj, method_name.inspect()), self.get_similar_attr_from_singular(obj, method_name.inspect()),
)); ));
} }
match self.rec_get_method_traits(method_name) { match self.get_method_type_by_name(method_name) {
Ok(trait_) => { Ok(t) => {
let (_, ctx) = self.get_nominal_type_ctx(trait_).unwrap(); self.sub_unify(obj.ref_t(), &t.definition_type, obj.loc(), None)
return ctx.rec_get_var_t(method_name, input, namespace); // HACK: change this func's return type to TyCheckResult<Type>
.map_err(|mut errs| errs.remove(0))?;
return Ok(t.method_type.clone());
} }
Err(err) if err.core.kind == ErrorKind::TypeError => { Err(err) if err.core.kind == ErrorKind::TypeError => {
return Err(err); return Err(err);
@ -700,6 +731,7 @@ impl Context {
/// substitute_call(instance: ((?T, Int) -> ?T), [Int, Nat], []) => instance: (Int, Int) -> Str /// substitute_call(instance: ((?T, Int) -> ?T), [Int, Nat], []) => instance: (Int, Int) -> Str
/// substitute_call(instance: ((?M(: Nat)..?N(: Nat)) -> ?M+?N), [1..2], []) => instance: (1..2) -> {3} /// substitute_call(instance: ((?M(: Nat)..?N(: Nat)) -> ?M+?N), [1..2], []) => instance: (1..2) -> {3}
/// substitute_call(instance: ((?L(: Add(?R, ?O)), ?R) -> ?O), [1, 2], []) => instance: (Nat, Nat) -> Nat /// substitute_call(instance: ((?L(: Add(?R, ?O)), ?R) -> ?O), [1, 2], []) => instance: (Nat, Nat) -> Nat
/// substitute_call(instance: ?T, [Int, Str], []) => instance: (Int, Str) -> Int
/// ``` /// ```
fn substitute_call( fn substitute_call(
&self, &self,
@ -713,6 +745,26 @@ impl Context {
Type::FreeVar(fv) if fv.is_linked() => { Type::FreeVar(fv) if fv.is_linked() => {
self.substitute_call(obj, method_name, &fv.crack(), pos_args, kw_args) self.substitute_call(obj, method_name, &fv.crack(), pos_args, kw_args)
} }
Type::FreeVar(fv) => {
if let Some(_method_name) = method_name {
todo!()
} else {
let is_procedural = obj
.show_acc()
.map(|acc| acc.ends_with('!'))
.unwrap_or(false);
let kind = if is_procedural {
SubrKind::Proc
} else {
SubrKind::Func
};
let ret_t = free_var(self.level, Constraint::new_type_of(Type));
let non_default_params = pos_args.iter().map(|a| anon(a.expr.t())).collect();
let subr_t = subr_t(kind, non_default_params, None, vec![], ret_t);
fv.link(&subr_t);
Ok(())
}
}
Type::Refinement(refine) => { Type::Refinement(refine) => {
self.substitute_call(obj, method_name, &refine.t, pos_args, kw_args) self.substitute_call(obj, method_name, &refine.t, pos_args, kw_args)
} }
@ -788,6 +840,15 @@ impl Context {
&mut passed_params, &mut passed_params,
)?; )?;
} }
for not_passed in subr
.default_params
.iter()
.filter(|pt| !passed_params.contains(pt.name().unwrap()))
{
if let ParamTy::KwWithDefault { ty, default, .. } = not_passed {
self.sub_unify(default, ty, obj.loc(), not_passed.name())?;
}
}
} else { } else {
let missing_len = subr.non_default_params.len() - pos_args.len(); let missing_len = subr.non_default_params.len() - pos_args.len();
let missing_params = subr let missing_params = subr
@ -1152,13 +1213,19 @@ impl Context {
.iter() .iter()
.map(|(opt_name, _)| { .map(|(opt_name, _)| {
if let Some(name) = opt_name { if let Some(name) = opt_name {
if let Some(t) = self.super_traits.iter().find(|t| { // トレイトの変性を調べるときはsuper_classesも見る必要がある
if let Some(t) = self
.super_traits
.iter()
.chain(self.super_classes.iter())
.find(|t| {
(&t.name()[..] == "Input" || &t.name()[..] == "Output") (&t.name()[..] == "Input" || &t.name()[..] == "Output")
&& t.inner_ts() && t.inner_ts()
.first() .first()
.map(|t| &t.name() == name.inspect()) .map(|t| &t.name() == name.inspect())
.unwrap_or(false) .unwrap_or(false)
}) { })
{
match &t.name()[..] { match &t.name()[..] {
"Output" => Variance::Covariant, "Output" => Variance::Covariant,
"Input" => Variance::Contravariant, "Input" => Variance::Contravariant,
@ -1280,7 +1347,17 @@ impl Context {
} }
} }
// TODO // TODO
Type::Or(_l, _r) => None, Type::Or(l, r) => match (l.as_ref(), r.as_ref()) {
(Type::FreeVar(l), Type::FreeVar(r)) if l.is_unbound() && r.is_unbound() => {
let (_lsub, lsup) = l.get_bound_types().unwrap();
let (_rsub, rsup) = r.get_bound_types().unwrap();
self.get_nominal_super_type_ctxs(&self.union(&lsup, &rsup))
}
(Type::Refinement(l), Type::Refinement(r)) if l.t == r.t => {
self.get_nominal_super_type_ctxs(&l.t)
}
_ => None,
},
_ => self _ => self
.get_simple_nominal_super_type_ctxs(t) .get_simple_nominal_super_type_ctxs(t)
.map(|ctxs| ctxs.collect()), .map(|ctxs| ctxs.collect()),
@ -1417,6 +1494,17 @@ impl Context {
return Some(res); return Some(res);
} }
} }
Type::Or(l, r) => {
let (lt, lctx) = self.get_nominal_type_ctx(l)?;
let (rt, rctx) = self.get_nominal_type_ctx(r)?;
// use smaller context
return match (self.supertype_of(lt, rt), self.supertype_of(rt, lt)) {
(true, true) => Some((rt, lctx)),
(true, false) => Some((rt, lctx)),
(false, true) => Some((lt, rctx)),
(false, false) => None,
};
}
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる // FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => { other if other.is_monomorphic() => {
if let Some((t, ctx)) = self.rec_get_mono_type(&other.name()) { if let Some((t, ctx)) = self.rec_get_mono_type(&other.name()) {
@ -1491,14 +1579,43 @@ impl Context {
None None
} }
pub(crate) fn rec_get_trait_impls(&self, name: &Str) -> Vec<TraitInstance> { pub(crate) fn get_trait_impls(&self, t: &Type) -> Set<TraitInstance> {
let current = if let Some(impls) = self.trait_impls.get(name) { match t {
// And(Add, Sub) == intersection({Int <: Add(Int), Bool <: Add(Bool) ...}, {Int <: Sub(Int), ...})
// == {Int <: Add(Int) and Sub(Int), ...}
Type::And(l, r) => {
let l_impls = self.get_trait_impls(l);
let l_base = Set::from_iter(l_impls.iter().map(|ti| &ti.sub_type));
let r_impls = self.get_trait_impls(r);
let r_base = Set::from_iter(r_impls.iter().map(|ti| &ti.sub_type));
let bases = l_base.intersection(&r_base);
let mut isec = set! {};
for base in bases.into_iter() {
let lti = l_impls.iter().find(|ti| &ti.sub_type == base).unwrap();
let rti = r_impls.iter().find(|ti| &ti.sub_type == base).unwrap();
let sup_trait = self.intersection(&lti.sup_trait, &rti.sup_trait);
isec.insert(TraitInstance::new(lti.sub_type.clone(), sup_trait));
}
isec
}
Type::Or(l, r) => {
let l_impls = self.get_trait_impls(l);
let r_impls = self.get_trait_impls(r);
// FIXME:
l_impls.union(&r_impls)
}
_ => self.get_simple_trait_impls(t),
}
}
pub(crate) fn get_simple_trait_impls(&self, t: &Type) -> Set<TraitInstance> {
let current = if let Some(impls) = self.trait_impls.get(&t.name()) {
impls.clone() impls.clone()
} else { } else {
vec![] set! {}
}; };
if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
[current, outer.rec_get_trait_impls(name)].concat() current.union(&outer.get_simple_trait_impls(t))
} else { } else {
current current
} }
@ -1515,10 +1632,8 @@ impl Context {
} }
// FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる // FIXME: 現在の実装だとimportしたモジュールはどこからでも見れる
fn get_mod(&self, ident: &ast::Identifier) -> Option<&Context> { pub(crate) fn get_mod(&self, name: &str) -> Option<&Context> {
let t = self let t = self.get_var_info(name).map(|(_, vi)| vi.t.clone()).ok()?;
.rec_get_var_t(ident, &self.cfg.input, &self.name)
.ok()?;
match t { match t {
Type::BuiltinPoly { name, mut params } if &name[..] == "Module" => { Type::BuiltinPoly { name, mut params } if &name[..] == "Module" => {
let path = let path =
@ -1624,7 +1739,7 @@ impl Context {
} }
} }
fn rec_get_type(&self, name: &str) -> Option<(&Type, &Context)> { pub(crate) fn rec_get_type(&self, name: &str) -> Option<(&Type, &Context)> {
if let Some((t, ctx)) = self.mono_types.get(name) { if let Some((t, ctx)) = self.mono_types.get(name) {
Some((t, ctx)) Some((t, ctx))
} else if let Some((t, ctx)) = self.poly_types.get(name) { } else if let Some((t, ctx)) = self.poly_types.get(name) {
@ -1646,22 +1761,52 @@ impl Context {
} }
} }
fn rec_get_method_traits(&self, name: &Identifier) -> SingleTyCheckResult<&Type> { fn get_method_type_by_name(&self, name: &Identifier) -> SingleTyCheckResult<&MethodType> {
if let Some(candidates) = self.method_traits.get(name.inspect()) { // TODO: min_by
let first_t = candidates.first().unwrap(); if let Some(candidates) = self.method_to_traits.get(name.inspect()) {
if candidates.iter().skip(1).all(|t| t == first_t) { let first_method_type = &candidates.first().unwrap().method_type;
Ok(&candidates[0]) if candidates
.iter()
.skip(1)
.all(|t| &t.method_type == first_method_type)
{
return Ok(&candidates[0]);
} else { } else {
Err(TyCheckError::ambiguous_type_error( return Err(TyCheckError::ambiguous_type_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
name, name,
candidates, &candidates
.iter()
.map(|t| t.definition_type.clone())
.collect::<Vec<_>>(),
self.caused_by(), self.caused_by(),
)) ));
} }
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) { }
outer.rec_get_method_traits(name) if let Some(candidates) = self.method_to_classes.get(name.inspect()) {
let first_method_type = &candidates.first().unwrap().method_type;
if candidates
.iter()
.skip(1)
.all(|t| &t.method_type == first_method_type)
{
return Ok(&candidates[0]);
} else {
return Err(TyCheckError::ambiguous_type_error(
self.cfg.input.clone(),
line!() as usize,
name,
&candidates
.iter()
.map(|t| t.definition_type.clone())
.collect::<Vec<_>>(),
self.caused_by(),
));
}
}
if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
outer.get_method_type_by_name(name)
} else { } else {
Err(TyCheckError::no_attr_error( Err(TyCheckError::no_attr_error(
self.cfg.input.clone(), self.cfg.input.clone(),
@ -1731,7 +1876,7 @@ impl Context {
match lhs { match lhs {
Type::FreeVar(fv) => { Type::FreeVar(fv) => {
if let Some(sup) = fv.get_sup() { if let Some(sup) = fv.get_sup() {
let insts = self.rec_get_trait_impls(&sup.name()); let insts = self.get_trait_impls(&sup);
let candidates = insts.into_iter().filter_map(move |inst| { let candidates = insts.into_iter().filter_map(move |inst| {
if self.supertype_of(&inst.sup_trait, &sup) { if self.supertype_of(&inst.sup_trait, &sup) {
self.eval_t_params( self.eval_t_params(

View file

@ -168,6 +168,62 @@ impl TyVarContext {
}; };
mono_proj(lhs, rhs) mono_proj(lhs, rhs)
} }
Type::Ref(t) if t.has_qvar() => ref_(self.instantiate_qvar(*t)),
Type::RefMut { before, after } => {
let before = if before.has_qvar() {
self.instantiate_qvar(*before)
} else {
*before
};
let after = after.map(|t| {
if t.has_qvar() {
self.instantiate_qvar(*t)
} else {
*t
}
});
ref_mut(before, after)
}
Type::And(l, r) => {
let l = if l.has_qvar() {
self.instantiate_qvar(*l)
} else {
*l
};
let r = if r.has_qvar() {
self.instantiate_qvar(*r)
} else {
*r
};
and(l, r)
}
Type::Or(l, r) => {
let l = if l.has_qvar() {
self.instantiate_qvar(*l)
} else {
*l
};
let r = if r.has_qvar() {
self.instantiate_qvar(*r)
} else {
*r
};
or(l, r)
}
Type::Not(l, r) => {
let l = if l.has_qvar() {
self.instantiate_qvar(*l)
} else {
*l
};
let r = if r.has_qvar() {
self.instantiate_qvar(*r)
} else {
*r
};
not(l, r)
}
Type::MonoQVar(_) => self.instantiate_qvar(sub_or_sup),
other => other, other => other,
} }
} }
@ -461,7 +517,7 @@ impl Context {
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
// -> Result<Type, (Type, TyCheckErrors)> { // -> Result<Type, (Type, TyCheckErrors)> {
let opt_decl_sig_t = self let opt_decl_sig_t = self
.rec_get_var_t(&sig.ident, &self.cfg.input, &self.name) .rec_get_decl_t(&sig.ident, &self.cfg.input, &self.name)
.ok() .ok()
.map(|t| enum_unwrap!(t, Type::Subr)); .map(|t| enum_unwrap!(t, Type::Subr));
let bounds = self.instantiate_ty_bounds(&sig.bounds, PreRegister)?; let bounds = self.instantiate_ty_bounds(&sig.bounds, PreRegister)?;
@ -471,17 +527,13 @@ impl Context {
let opt_decl_t = opt_decl_sig_t let opt_decl_t = opt_decl_sig_t
.as_ref() .as_ref()
.and_then(|subr| subr.non_default_params.get(n)); .and_then(|subr| subr.non_default_params.get(n));
non_defaults.push(ParamTy::pos( non_defaults.push(self.instantiate_param_ty(p, opt_decl_t, Some(&tv_ctx), mode)?);
p.inspect().cloned(),
self.instantiate_param_sig_t(p, opt_decl_t, Some(&tv_ctx), mode)?,
));
} }
let var_args = if let Some(var_args) = sig.params.var_args.as_ref() { let var_args = if let Some(var_args) = sig.params.var_args.as_ref() {
let opt_decl_t = opt_decl_sig_t let opt_decl_t = opt_decl_sig_t
.as_ref() .as_ref()
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref())); .and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
let va_t = self.instantiate_param_sig_t(var_args, opt_decl_t, Some(&tv_ctx), mode)?; Some(self.instantiate_param_ty(var_args, opt_decl_t, Some(&tv_ctx), mode)?)
Some(ParamTy::pos(var_args.inspect().cloned(), va_t))
} else { } else {
None None
}; };
@ -490,10 +542,7 @@ impl Context {
let opt_decl_t = opt_decl_sig_t let opt_decl_t = opt_decl_sig_t
.as_ref() .as_ref()
.and_then(|subr| subr.default_params.get(n)); .and_then(|subr| subr.default_params.get(n));
defaults.push(ParamTy::kw( defaults.push(self.instantiate_param_ty(p, opt_decl_t, Some(&tv_ctx), mode)?);
p.inspect().unwrap().clone(),
self.instantiate_param_sig_t(p, opt_decl_t, Some(&tv_ctx), mode)?,
));
} }
let spec_return_t = if let Some(s) = sig.return_t_spec.as_ref() { let spec_return_t = if let Some(s) = sig.return_t_spec.as_ref() {
let opt_decl_t = opt_decl_sig_t let opt_decl_t = opt_decl_sig_t
@ -554,6 +603,29 @@ impl Context {
Ok(spec_t) Ok(spec_t)
} }
pub(crate) fn instantiate_param_ty(
&self,
sig: &ParamSignature,
opt_decl_t: Option<&ParamTy>,
tmp_tv_ctx: Option<&TyVarContext>,
mode: RegistrationMode,
) -> TyCheckResult<ParamTy> {
let t = self.instantiate_param_sig_t(sig, opt_decl_t, tmp_tv_ctx, mode)?;
match (sig.inspect(), &sig.opt_default_val) {
(Some(name), Some(default)) => {
let default = self.instantiate_const_expr(default);
Ok(ParamTy::kw_default(
name.clone(),
t,
self.get_tp_t(&default)?,
))
}
(Some(name), None) => Ok(ParamTy::kw(name.clone(), t)),
(None, None) => Ok(ParamTy::anonymous(t)),
_ => unreachable!(),
}
}
pub(crate) fn instantiate_predecl_t( pub(crate) fn instantiate_predecl_t(
&self, &self,
predecl: &PreDeclTypeSpec, predecl: &PreDeclTypeSpec,
@ -695,19 +767,18 @@ impl Context {
TypeSpec::PreDeclTy(predecl) => { TypeSpec::PreDeclTy(predecl) => {
Ok(self.instantiate_predecl_t(predecl, opt_decl_t, tmp_tv_ctx)?) Ok(self.instantiate_predecl_t(predecl, opt_decl_t, tmp_tv_ctx)?)
} }
// TODO: Flatten TypeSpec::And(lhs, rhs) => Ok(self.union(
TypeSpec::And(lhs, rhs) => Ok(and( &self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?,
self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?, &self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?,
self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?, )),
TypeSpec::Or(lhs, rhs) => Ok(self.intersection(
&self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?,
&self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?,
)), )),
TypeSpec::Not(lhs, rhs) => Ok(not( TypeSpec::Not(lhs, rhs) => Ok(not(
self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?, self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?,
self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?, self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?,
)), )),
TypeSpec::Or(lhs, rhs) => Ok(or(
self.instantiate_typespec(lhs, opt_decl_t, tmp_tv_ctx, mode)?,
self.instantiate_typespec(rhs, opt_decl_t, tmp_tv_ctx, mode)?,
)),
TypeSpec::Array(arr) => { TypeSpec::Array(arr) => {
let elem_t = self.instantiate_typespec(&arr.ty, opt_decl_t, tmp_tv_ctx, mode)?; let elem_t = self.instantiate_typespec(&arr.ty, opt_decl_t, tmp_tv_ctx, mode)?;
let len = self.instantiate_const_expr(&arr.len); let len = self.instantiate_const_expr(&arr.len);
@ -945,13 +1016,14 @@ impl Context {
*pt.typ_mut() = self.instantiate_t(mem::take(pt.typ_mut()), tmp_tv_ctx, loc)?; *pt.typ_mut() = self.instantiate_t(mem::take(pt.typ_mut()), tmp_tv_ctx, loc)?;
} }
let return_t = self.instantiate_t(*subr.return_t, tmp_tv_ctx, loc)?; let return_t = self.instantiate_t(*subr.return_t, tmp_tv_ctx, loc)?;
Ok(subr_t( let res = subr_t(
subr.kind, subr.kind,
subr.non_default_params, subr.non_default_params,
subr.var_params.map(|p| *p), subr.var_params.map(|p| *p),
subr.default_params, subr.default_params,
return_t, return_t,
)) );
Ok(res)
} }
Record(mut dict) => { Record(mut dict) => {
for v in dict.values_mut() { for v in dict.values_mut() {
@ -1007,12 +1079,12 @@ impl Context {
And(l, r) => { And(l, r) => {
let l = self.instantiate_t(*l, tmp_tv_ctx, loc)?; let l = self.instantiate_t(*l, tmp_tv_ctx, loc)?;
let r = self.instantiate_t(*r, tmp_tv_ctx, loc)?; let r = self.instantiate_t(*r, tmp_tv_ctx, loc)?;
Ok(and(l, r)) Ok(self.intersection(&l, &r))
} }
Or(l, r) => { Or(l, r) => {
let l = self.instantiate_t(*l, tmp_tv_ctx, loc)?; let l = self.instantiate_t(*l, tmp_tv_ctx, loc)?;
let r = self.instantiate_t(*r, tmp_tv_ctx, loc)?; let r = self.instantiate_t(*r, tmp_tv_ctx, loc)?;
Ok(or(l, r)) Ok(self.union(&l, &r))
} }
Not(l, r) => { Not(l, r) => {
let l = self.instantiate_t(*l, tmp_tv_ctx, loc)?; let l = self.instantiate_t(*l, tmp_tv_ctx, loc)?;

View file

@ -23,6 +23,7 @@ use erg_common::config::ErgConfig;
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::error::Location; use erg_common::error::Location;
use erg_common::impl_display_from_debug; use erg_common::impl_display_from_debug;
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream}; use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
use erg_common::Str; use erg_common::Str;
@ -274,15 +275,17 @@ pub enum RegistrationMode {
Normal, Normal,
} }
/// Some Erg functions require additional operation by the compiler.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ImportKind { pub enum OperationKind {
ErgImport, Import,
PyImport, PyImport,
Del,
} }
impl ImportKind { impl OperationKind {
pub const fn is_erg_import(&self) -> bool { pub const fn is_erg_import(&self) -> bool {
matches!(self, Self::ErgImport) matches!(self, Self::Import)
} }
pub const fn is_py_import(&self) -> bool { pub const fn is_py_import(&self) -> bool {
matches!(self, Self::PyImport) matches!(self, Self::PyImport)
@ -294,6 +297,31 @@ pub struct ContextInfo {
mod_id: usize, mod_id: usize,
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MethodType {
definition_type: Type,
method_type: Type,
}
impl fmt::Display for MethodType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{{ def: {} t: {} }}",
self.definition_type, self.method_type
)
}
}
impl MethodType {
pub const fn new(definition_type: Type, method_type: Type) -> Self {
Self {
definition_type,
method_type,
}
}
}
/// Represents the context of the current scope /// Represents the context of the current scope
/// ///
/// Recursive functions/methods are highlighted with the prefix `rec_`, as performance may be significantly degraded. /// Recursive functions/methods are highlighted with the prefix `rec_`, as performance may be significantly degraded.
@ -317,8 +345,10 @@ pub struct Context {
// method definitions, if the context is a type // method definitions, if the context is a type
// specializations are included and needs to be separated out // specializations are included and needs to be separated out
pub(crate) methods_list: Vec<(ClassDefType, Context)>, pub(crate) methods_list: Vec<(ClassDefType, Context)>,
// K: method name, V: trait defines the method // K: method name, V: types defines the method
pub(crate) method_traits: Dict<Str, Vec<Type>>, // If it is declared in a trait, it takes precedence over the class.
pub(crate) method_to_traits: Dict<Str, Vec<MethodType>>,
pub(crate) method_to_classes: Dict<Str, Vec<MethodType>>,
/// K: method name, V: impl patch /// K: method name, V: impl patch
/// Provided methods can switch implementations on a scope-by-scope basis /// Provided methods can switch implementations on a scope-by-scope basis
/// K: メソッド名, V: それを実装するパッチたち /// K: メソッド名, V: それを実装するパッチたち
@ -327,7 +357,7 @@ pub struct Context {
/// K: name of a trait, V: (type, monomorphised trait that the type implements) /// K: name of a trait, V: (type, monomorphised trait that the type implements)
/// K: トレイトの名前, V: (型, その型が実装する単相化トレイト) /// K: トレイトの名前, V: (型, その型が実装する単相化トレイト)
/// e.g. { "Named": [(Type, Named), (Func, Named), ...], "Add": [(Nat, Add(Nat)), (Int, Add(Int)), ...], ... } /// e.g. { "Named": [(Type, Named), (Func, Named), ...], "Add": [(Nat, Add(Nat)), (Int, Add(Int)), ...], ... }
pub(crate) trait_impls: Dict<Str, Vec<TraitInstance>>, pub(crate) trait_impls: Dict<Str, Set<TraitInstance>>,
/// stores declared names (not initialized) /// stores declared names (not initialized)
pub(crate) decls: Dict<VarName, VarInfo>, pub(crate) decls: Dict<VarName, VarInfo>,
// stores defined names // stores defined names
@ -456,7 +486,8 @@ impl Context {
super_traits: vec![], super_traits: vec![],
methods_list: vec![], methods_list: vec![],
const_param_defaults: Dict::default(), const_param_defaults: Dict::default(),
method_traits: Dict::default(), method_to_traits: Dict::default(),
method_to_classes: Dict::default(),
method_impl_patches: Dict::default(), method_impl_patches: Dict::default(),
trait_impls: Dict::default(), trait_impls: Dict::default(),
params: params_, params: params_,
@ -871,15 +902,28 @@ impl Context {
/// for language server /// for language server
impl Context { impl Context {
pub fn dir(&self) -> Vec<(&VarName, &VarInfo)> { pub fn dir(&self) -> Vec<(&VarName, &VarInfo)> {
let mut vars: Vec<_> = self.locals.iter().collect(); let mut vars: Vec<_> = self
.locals
.iter()
.chain(self.methods_list.iter().flat_map(|(_, ctx)| ctx.dir()))
.collect();
if let Some(outer) = self.get_outer() { if let Some(outer) = self.get_outer() {
vars.extend(outer.dir()); vars.extend(outer.dir());
} else { } else if let Some(builtins) = self.get_builtins() {
vars.extend(self.get_builtins().unwrap().locals.iter()); vars.extend(builtins.locals.iter());
} }
vars vars
} }
pub fn get_receiver_ctx(&self, receiver_name: &str) -> Option<&Context> {
self.get_mod(receiver_name)
.or_else(|| {
let (_, vi) = self.get_var_info(receiver_name).ok()?;
self.get_nominal_type_ctx(&vi.t).map(|(_, ctx)| ctx)
})
.or_else(|| self.rec_get_type(receiver_name).map(|(_, ctx)| ctx))
}
pub fn get_var_info(&self, name: &str) -> SingleTyCheckResult<(&VarName, &VarInfo)> { pub fn get_var_info(&self, name: &str) -> SingleTyCheckResult<(&VarName, &VarInfo)> {
if let Some(info) = self.get_local_kv(name) { if let Some(info) = self.get_local_kv(name) {
Ok(info) Ok(info)

View file

@ -15,16 +15,17 @@ use erg_parser::ast;
use erg_type::constructors::{func, func1, proc, ref_, ref_mut, v_enum}; use erg_type::constructors::{func, func1, proc, ref_, ref_mut, v_enum};
use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj}; use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{ParamTy, SubrType, TyBound, Type}; use erg_type::{ParamTy, SubrType, Type};
use crate::build_hir::HIRBuilder; use crate::build_hir::HIRBuilder;
use crate::context::{ use crate::context::{
ClassDefType, Context, ContextKind, DefaultInfo, RegistrationMode, TraitInstance, ClassDefType, Context, ContextKind, DefaultInfo, MethodType, RegistrationMode, TraitInstance,
}; };
use crate::error::readable_name; use crate::error::readable_name;
use crate::error::{ use crate::error::{
CompileResult, SingleTyCheckResult, TyCheckError, TyCheckErrors, TyCheckResult, CompileResult, SingleTyCheckResult, TyCheckError, TyCheckErrors, TyCheckResult,
}; };
use crate::hir;
use crate::hir::Literal; use crate::hir::Literal;
use crate::mod_cache::SharedModuleCache; use crate::mod_cache::SharedModuleCache;
use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind}; use crate::varinfo::{Mutability, ParamIdx, VarInfo, VarKind};
@ -33,7 +34,7 @@ use RegistrationMode::*;
use Visibility::*; use Visibility::*;
use super::instantiate::TyVarContext; use super::instantiate::TyVarContext;
use super::ImportKind; use super::OperationKind;
impl Context { impl Context {
/// If it is a constant that is defined, there must be no variable of the same name defined across all scopes /// If it is a constant that is defined, there must be no variable of the same name defined across all scopes
@ -347,12 +348,13 @@ impl Context {
sig: &ast::SubrSignature, sig: &ast::SubrSignature,
id: DefId, id: DefId,
body_t: &Type, body_t: &Type,
) -> TyCheckResult<()> { ) -> TyCheckResult<Type> {
// already defined as const // already defined as const
if sig.is_const() { if sig.is_const() {
let vi = self.decls.remove(sig.ident.inspect()).unwrap(); let vi = self.decls.remove(sig.ident.inspect()).unwrap();
let t = vi.t.clone();
self.locals.insert(sig.ident.name.clone(), vi); self.locals.insert(sig.ident.name.clone(), vi);
return Ok(()); return Ok(t);
} }
let muty = if sig.ident.is_const() { let muty = if sig.ident.is_const() {
Mutability::Const Mutability::Const
@ -442,9 +444,10 @@ impl Context {
VarKind::Defined(id), VarKind::Defined(id),
Some(comptime_decos), Some(comptime_decos),
); );
log!(info "Registered {}::{name}: {}", self.name, &vi.t); let t = vi.t.clone();
log!(info "Registered {}::{name}: {}", self.name, t);
self.locals.insert(name.clone(), vi); self.locals.insert(name.clone(), vi);
Ok(()) Ok(t)
} }
pub(crate) fn fake_subr_assign(&mut self, sig: &ast::SubrSignature, failure_t: Type) { pub(crate) fn fake_subr_assign(&mut self, sig: &ast::SubrSignature, failure_t: Type) {
@ -632,10 +635,12 @@ impl Context {
)) ))
} else { } else {
match obj { match obj {
ValueObj::Type(t) => { ValueObj::Type(t) => match t {
let gen = enum_unwrap!(t, TypeObj::Generated); TypeObj::Generated(gen) => {
self.register_gen_type(ident, gen); self.register_gen_type(ident, gen);
} }
TypeObj::Builtin(_t) => panic!("aliasing bug"),
},
// TODO: not all value objects are comparable // TODO: not all value objects are comparable
other => { other => {
let id = DefId(get_hash(ident)); let id = DefId(get_hash(ident));
@ -834,20 +839,32 @@ impl Context {
.insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen))); .insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen)));
for impl_trait in ctx.super_traits.iter() { for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) { if let Some(impls) = self.trait_impls.get_mut(&impl_trait.name()) {
impls.push(TraitInstance::new(t.clone(), impl_trait.clone())); impls.insert(TraitInstance::new(t.clone(), impl_trait.clone()));
} else { } else {
self.trait_impls.insert( self.trait_impls.insert(
impl_trait.name(), impl_trait.name(),
vec![TraitInstance::new(t.clone(), impl_trait.clone())], set![TraitInstance::new(t.clone(), impl_trait.clone())],
); );
} }
} }
for method in ctx.decls.keys() { for (trait_method, vi) in ctx.decls.iter() {
if let Some(impls) = self.method_traits.get_mut(method.inspect()) { if let Some(types) = self.method_to_traits.get_mut(trait_method.inspect()) {
impls.push(t.clone()); types.push(MethodType::new(t.clone(), vi.t.clone()));
} else { } else {
self.method_traits self.method_to_traits.insert(
.insert(method.inspect().clone(), vec![t.clone()]); trait_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
}
}
for (class_method, vi) in ctx.locals.iter() {
if let Some(types) = self.method_to_classes.get_mut(class_method.inspect()) {
types.push(MethodType::new(t.clone(), vi.t.clone()));
} else {
self.method_to_classes.insert(
class_method.inspect().clone(),
vec![MethodType::new(t.clone(), vi.t.clone())],
);
} }
} }
self.mono_types.insert(name.clone(), (t, ctx)); self.mono_types.insert(name.clone(), (t, ctx));
@ -856,7 +873,7 @@ impl Context {
pub(crate) fn import_mod( pub(crate) fn import_mod(
&mut self, &mut self,
kind: ImportKind, kind: OperationKind,
mod_name: &Literal, mod_name: &Literal,
) -> CompileResult<PathBuf> { ) -> CompileResult<PathBuf> {
if kind.is_erg_import() { if kind.is_erg_import() {
@ -1031,11 +1048,32 @@ impl Context {
Ok(path) Ok(path)
} }
pub(crate) fn _push_subtype_bound(&mut self, sub: Type, sup: Type) { pub fn del(&mut self, ident: &hir::Identifier) -> CompileResult<()> {
self.bounds.push(TyBound::subtype_of(sub, sup)); if self.rec_get_const_obj(ident.inspect()).is_some()
|| self
.get_builtins()
.unwrap()
.get_local_kv(ident.inspect())
.is_some()
{
Err(TyCheckErrors::from(TyCheckError::del_error(
self.cfg.input.clone(),
line!() as usize,
ident,
self.caused_by(),
)))
} else if self.locals.get(ident.inspect()).is_some() {
self.locals.remove(ident.inspect());
Ok(())
} else {
Err(TyCheckErrors::from(TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
ident.loc(),
self.caused_by(),
ident.inspect(),
self.get_similar_name(ident.inspect()),
)))
} }
pub(crate) fn _push_instance_bound(&mut self, name: Str, t: Type) {
self.bounds.push(TyBound::instance(name, t));
} }
} }

View file

@ -32,9 +32,9 @@ impl Context {
pub fn test_resolve_trait_inner1(&self) -> Result<(), ()> { pub fn test_resolve_trait_inner1(&self) -> Result<(), ()> {
let name = Str::ever("Add"); let name = Str::ever("Add");
let params = vec![TyParam::t(Nat)]; let params = vec![TyParam::t(Nat)];
let maybe_trait = builtin_poly(name.clone(), params); let maybe_trait = builtin_poly(name, params);
let mut min = Type::Obj; let mut min = Type::Obj;
for pair in self.rec_get_trait_impls(&name) { for pair in self.get_trait_impls(&maybe_trait) {
if self.supertype_of(&pair.sup_trait, &maybe_trait) { if self.supertype_of(&pair.sup_trait, &maybe_trait) {
min = self.min(&min, &pair.sub_type).unwrap_or(&min).clone(); min = self.min(&min, &pair.sub_type).unwrap_or(&min).clone();
} }

View file

@ -120,16 +120,32 @@ impl Context {
// TODO: Polymorphic generalization // TODO: Polymorphic generalization
FreeVar(fv) if fv.level().unwrap() > self.level => match &*fv.borrow() { FreeVar(fv) if fv.level().unwrap() > self.level => match &*fv.borrow() {
FreeKind::Unbound { id, constraint, .. } => { FreeKind::Unbound { id, constraint, .. } => {
// |Int <: T <: Int| T -> T ==> Int -> Int
let (l, r) = constraint.get_sub_sup().unwrap();
if l == r {
fv.forced_link(&l.clone());
FreeVar(fv.clone())
} else if r != &Obj && self.is_class(r) {
// x: T <: Bool ==> x: Bool
r.clone()
} else {
let name = format!("%{id}"); let name = format!("%{id}");
self.generalize_constraint(&name, constraint, bounds, lazy_inits); self.generalize_constraint(&name, constraint, bounds, lazy_inits);
mono_q(name) mono_q(name)
} }
}
FreeKind::NamedUnbound { FreeKind::NamedUnbound {
name, constraint, .. name, constraint, ..
} => { } => {
let (l, r) = constraint.get_sub_sup().unwrap();
if l == r {
fv.forced_link(l);
FreeVar(fv.clone())
} else {
self.generalize_constraint(name, constraint, bounds, lazy_inits); self.generalize_constraint(name, constraint, bounds, lazy_inits);
mono_q(name) mono_q(name)
} }
}
_ => assume_unreachable!(), _ => assume_unreachable!(),
}, },
Subr(mut subr) => { Subr(mut subr) => {
@ -182,6 +198,23 @@ impl Context {
let lhs = self.generalize_t_inner(*lhs, bounds, lazy_inits); let lhs = self.generalize_t_inner(*lhs, bounds, lazy_inits);
mono_proj(lhs, rhs) mono_proj(lhs, rhs)
} }
And(l, r) => {
let l = self.generalize_t_inner(*l, bounds, lazy_inits);
let r = self.generalize_t_inner(*r, bounds, lazy_inits);
// not `self.intersection` because types are generalized
and(l, r)
}
Or(l, r) => {
let l = self.generalize_t_inner(*l, bounds, lazy_inits);
let r = self.generalize_t_inner(*r, bounds, lazy_inits);
// not `self.union` because types are generalized
or(l, r)
}
Not(l, r) => {
let l = self.generalize_t_inner(*l, bounds, lazy_inits);
let r = self.generalize_t_inner(*r, bounds, lazy_inits);
not(l, r)
}
// REVIEW: その他何でもそのまま通していいのか? // REVIEW: その他何でもそのまま通していいのか?
other => other, other => other,
} }
@ -312,6 +345,12 @@ impl Context {
let constraint = fv.crack_constraint(); let constraint = fv.crack_constraint();
let (sub_t, super_t) = constraint.get_sub_sup().unwrap(); let (sub_t, super_t) = constraint.get_sub_sup().unwrap();
if self.level <= fv.level().unwrap() { if self.level <= fv.level().unwrap() {
/*if self.is_trait(sub_t) {
self.check_trait_exists(sub_t, loc)?;
}*/
if self.is_trait(super_t) {
self.check_trait_impl(sub_t, super_t, loc)?;
}
// REVIEW: Even if type constraints can be satisfied, implementation may not exist // REVIEW: Even if type constraints can be satisfied, implementation may not exist
if self.subtype_of(sub_t, super_t) { if self.subtype_of(sub_t, super_t) {
match variance { match variance {
@ -472,6 +511,58 @@ impl Context {
} }
} }
pub(crate) fn trait_impl_exists(&self, class: &Type, trait_: &Type) -> bool {
let mut super_exists = false;
for inst in self.get_trait_impls(trait_).into_iter() {
if self.supertype_of(&inst.sub_type, class)
&& self.supertype_of(&inst.sup_trait, trait_)
{
super_exists = true;
break;
}
}
super_exists
}
fn check_trait_impl(
&self,
class: &Type,
trait_: &Type,
loc: Location,
) -> SingleTyCheckResult<()> {
if !self.trait_impl_exists(class, trait_) {
Err(TyCheckError::no_trait_impl_error(
self.cfg.input.clone(),
line!() as usize,
class,
trait_,
loc,
self.caused_by(),
None,
))
} else {
Ok(())
}
}
/// Fix type variables at their lower bound
pub(crate) fn coerce(&self, t: &Type) {
match t {
Type::FreeVar(fv) if fv.is_linked() => {
self.coerce(&fv.crack());
}
Type::FreeVar(fv) if fv.is_unbound() => {
let (sub, _sup) = fv.get_bound_types().unwrap();
fv.link(&sub);
}
Type::And(l, r) | Type::Or(l, r) | Type::Not(l, r) => {
self.coerce(l);
self.coerce(r);
}
_ => {}
}
}
/// Check if all types are resolvable (if traits, check if an implementation exists) /// Check if all types are resolvable (if traits, check if an implementation exists)
/// And replace them if resolvable /// And replace them if resolvable
pub(crate) fn resolve( pub(crate) fn resolve(
@ -602,17 +693,23 @@ impl Context {
Ok(()) Ok(())
} }
hir::Expr::Def(def) => { hir::Expr::Def(def) => {
// It is not possible to further dereference the quantified type.
// TODO: However, it is possible that there are external type variables within the quantified type.
if !def.sig.ref_t().is_quantified() {
match &mut def.sig { match &mut def.sig {
hir::Signature::Var(var) => { hir::Signature::Var(var) => {
var.t = self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?; var.t =
self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?;
} }
hir::Signature::Subr(subr) => { hir::Signature::Subr(subr) => {
subr.t = self.deref_tyvar(mem::take(&mut subr.t), Covariant, subr.loc())?; subr.t =
self.deref_tyvar(mem::take(&mut subr.t), Covariant, subr.loc())?;
} }
} }
for chunk in def.body.block.iter_mut() { for chunk in def.body.block.iter_mut() {
self.resolve_expr_t(chunk)?; self.resolve_expr_t(chunk)?;
} }
}
Ok(()) Ok(())
} }
hir::Expr::Lambda(lambda) => { hir::Expr::Lambda(lambda) => {
@ -1158,29 +1255,15 @@ impl Context {
// * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj)) // * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj))
// * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat)) // * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat))
Constraint::Sandwiched { sub, sup, cyclicity } => { Constraint::Sandwiched { sub, sup, cyclicity } => {
/*let judge = match cyclicity { /*if let Some(new_sub) = self.max(maybe_sub, sub) {
Cyclicity::Super => self.cyclic_supertype_of(rfv, maybe_sub),
Cyclicity::Not => self.supertype_of(sup, maybe_sub),
_ => todo!(),
};
if !judge {
return Err(TyCheckErrors::from(TyCheckError::subtyping_error(
self.cfg.input.clone(),
line!() as usize,
maybe_sub,
sup, // TODO: this?
sub_loc,
sup_loc,
self.caused_by(),
)));
}*/
if let Some(new_sub) = self.max(maybe_sub, sub) {
*constraint = *constraint =
Constraint::new_sandwiched(new_sub.clone(), mem::take(sup), *cyclicity); Constraint::new_sandwiched(new_sub.clone(), mem::take(sup), *cyclicity);
} else { } else {*/
erg_common::log!(err "{maybe_sub}, {sub}");
let new_sub = self.union(maybe_sub, sub); let new_sub = self.union(maybe_sub, sub);
erg_common::log!(err "{new_sub}");
*constraint = Constraint::new_sandwiched(new_sub, mem::take(sup), *cyclicity); *constraint = Constraint::new_sandwiched(new_sub, mem::take(sup), *cyclicity);
} // }
} }
// sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */) // sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */)
Constraint::TypeOf(ty) => { Constraint::TypeOf(ty) => {
@ -1212,18 +1295,7 @@ impl Context {
// sup = union(sup, r) if min does not exist // sup = union(sup, r) if min does not exist
// * sub_unify(?T(:> Never, <: {1}), {0}): (?T(:> Never, <: {0, 1})) // * sub_unify(?T(:> Never, <: {1}), {0}): (?T(:> Never, <: {0, 1}))
Constraint::Sandwiched { sub, sup, cyclicity } => { Constraint::Sandwiched { sub, sup, cyclicity } => {
// maybe_sup: Ref(Obj), sub: Never, sup: Show and Obj // REVIEW: correct?
/*if !self.subtype_of(sub, maybe_sup) || !self.supertype_of(sup, maybe_sup) {
return Err(TyCheckErrors::from(TyCheckError::subtyping_error(
self.cfg.input.clone(),
line!() as usize,
sub,
maybe_sup,
sub_loc,
sup_loc,
self.caused_by(),
)));
}*/
if let Some(new_sup) = self.min(sup, maybe_sup) { if let Some(new_sup) = self.min(sup, maybe_sup) {
*constraint = *constraint =
Constraint::new_sandwiched(mem::take(sub), new_sup.clone(), *cyclicity); Constraint::new_sandwiched(mem::take(sub), new_sup.clone(), *cyclicity);
@ -1331,6 +1403,20 @@ impl Context {
} }
Ok(()) Ok(())
} }
(Type::And(l, r), _)
| (Type::Or(l, r), _)
| (Type::Not(l, r), _) => {
self.sub_unify(l, maybe_sup, loc, param_name)?;
self.sub_unify(r, maybe_sup, loc, param_name)?;
Ok(())
}
(_, Type::And(l, r))
| (_, Type::Or(l, r))
| (_, Type::Not(l, r)) => {
self.sub_unify(maybe_sub, l, loc, param_name)?;
self.sub_unify(maybe_sub, r, loc, param_name)?;
Ok(())
}
(_, Type::Ref(t)) => { (_, Type::Ref(t)) => {
self.sub_unify(maybe_sub, t, loc, param_name)?; self.sub_unify(maybe_sub, t, loc, param_name)?;
Ok(()) Ok(())

View file

@ -9,8 +9,10 @@ use erg_common::vis::Visibility;
use erg_common::Str; use erg_common::Str;
use Visibility::*; use Visibility::*;
use erg_type::HasType;
use crate::error::{EffectError, EffectErrors}; use crate::error::{EffectError, EffectErrors};
use crate::hir::{Accessor, Array, Def, Expr, Signature, Tuple, HIR}; use crate::hir::{Array, Def, Expr, Signature, Tuple, HIR};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum BlockKind { enum BlockKind {
@ -208,8 +210,22 @@ impl SideEffectChecker {
self.block_stack.push(ConstInstant); self.block_stack.push(ConstInstant);
} }
} }
for chunk in def.body.block.iter() { let last_idx = def.body.block.len() - 1;
for (i, chunk) in def.body.block.iter().enumerate() {
self.check_expr(chunk); self.check_expr(chunk);
// e.g. `echo = print!`
if i == last_idx
&& self.block_stack.last().unwrap() == &Instant
&& !def.sig.is_procedural()
&& chunk.t().is_procedural()
{
self.errs.push(EffectError::proc_assign_error(
self.cfg.input.clone(),
line!() as usize,
&def.sig,
self.full_path(),
));
}
} }
self.path_stack.pop(); self.path_stack.pop();
self.block_stack.pop(); self.block_stack.pop();
@ -290,7 +306,7 @@ impl SideEffectChecker {
}, },
// 引数がproceduralでも関数呼び出しなら副作用なし // 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => { Expr::Call(call) => {
if (self.is_procedural(&call.obj) if (call.obj.t().is_procedural()
|| call || call
.method_name .method_name
.as_ref() .as_ref()
@ -340,19 +356,4 @@ impl SideEffectChecker {
_ => {} _ => {}
} }
} }
fn is_procedural(&self, expr: &Expr) -> bool {
match expr {
Expr::Lambda(lambda) => lambda.is_procedural(),
// 引数がproceduralでも関数呼び出しなら副作用なし
Expr::Call(call) => self.is_procedural(&call.obj),
Expr::Accessor(Accessor::Ident(ident)) => ident.name.is_procedural(),
// procedural: x.y! (e.g. Array.sample!)
// !procedural: !x.y
Expr::Accessor(Accessor::Attr(attr)) => attr.ident.is_procedural(),
Expr::Accessor(_) => todo!(),
Expr::TypeAsc(tasc) => self.is_procedural(&tasc.expr),
_ => false,
}
}
} }

View file

@ -16,7 +16,7 @@ use erg_parser::error::{ParserRunnerError, ParserRunnerErrors};
use erg_type::{Predicate, Type}; use erg_type::{Predicate, Type};
use crate::hir::Expr; use crate::hir::{Expr, Identifier, Signature};
/// dname is for "double under name" /// dname is for "double under name"
pub fn binop_to_dname(op: &str) -> &str { pub fn binop_to_dname(op: &str) -> &str {
@ -755,6 +755,33 @@ passed keyword args: {RED}{kw_args_len}{RESET}"
) )
} }
pub fn no_trait_impl_error(
input: Input,
errno: usize,
class: &Type,
trait_: &Type,
loc: Location,
caused_by: AtomicStr,
hint: Option<AtomicStr>,
) -> Self {
Self::new(
ErrorCore::new(
errno,
TypeError,
loc,
switch_lang!(
"japanese" => format!("{class}{trait_}を実装していません"),
"simplified_chinese" => format!("{class}没有实现{trait_}"),
"traditional_chinese" => format!("{class}沒有實現{trait_}"),
"english" => format!("{class} does not implement {trait_}"),
),
hint,
),
input,
caused_by,
)
}
pub fn method_definition_error( pub fn method_definition_error(
input: Input, input: Input,
errno: usize, errno: usize,
@ -992,6 +1019,38 @@ impl EffectError {
caused_by.into(), caused_by.into(),
) )
} }
pub fn proc_assign_error<S: Into<AtomicStr>>(
input: Input,
errno: usize,
sig: &Signature,
caused_by: S,
) -> Self {
Self::new(
ErrorCore::new(
errno,
HasEffect,
sig.loc(),
switch_lang!(
"japanese" => "プロシージャを通常の変数に代入することはできません",
"simplified_chinese" => "不能将过程赋值给普通变量",
"traditional_chinese" => "不能將過程賦值給普通變量",
"english" => "cannot assign a procedure to a normal variable",
),
Some(
switch_lang!(
"japanese" => "変数の末尾に`!`をつけてください",
"simplified_chinese" => "请在变量名后加上`!`",
"traditional_chinese" => "請在變量名後加上`!`",
"english" => "add `!` to the end of the variable name",
)
.into(),
),
),
input,
caused_by.into(),
)
}
} }
pub type OwnershipError = TyCheckError; pub type OwnershipError = TyCheckError;
@ -1305,6 +1364,26 @@ impl LowerError {
) )
} }
pub fn del_error(input: Input, errno: usize, ident: &Identifier, caused_by: AtomicStr) -> Self {
let name = readable_name(ident.inspect());
Self::new(
ErrorCore::new(
errno,
NameError,
ident.loc(),
switch_lang!(
"japanese" => format!("{YELLOW}{name}{RESET}は削除できません"),
"simplified_chinese" => format!("{YELLOW}{name}{RESET}不能删除"),
"traditional_chinese" => format!("{YELLOW}{name}{RESET}不能刪除"),
"english" => format!("{YELLOW}{name}{RESET} cannot be deleted"),
),
None,
),
input,
caused_by,
)
}
pub fn visibility_error( pub fn visibility_error(
input: Input, input: Input,
errno: usize, errno: usize,

View file

@ -20,7 +20,7 @@ use erg_type::value::{TypeKind, ValueObj};
use erg_type::{impl_t, impl_t_for_enum, HasType, Type}; use erg_type::{impl_t, impl_t_for_enum, HasType, Type};
use crate::context::eval::type_from_token_kind; use crate::context::eval::type_from_token_kind;
use crate::context::ImportKind; use crate::context::OperationKind;
use crate::error::readable_name; use crate::error::readable_name;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -1085,10 +1085,11 @@ impl Call {
} }
} }
pub fn import_kind(&self) -> Option<ImportKind> { pub fn additional_operation(&self) -> Option<OperationKind> {
self.obj.show_acc().and_then(|s| match &s[..] { self.obj.show_acc().and_then(|s| match &s[..] {
"import" => Some(ImportKind::ErgImport), "import" => Some(OperationKind::Import),
"pyimport" | "py" => Some(ImportKind::PyImport), "pyimport" | "py" => Some(OperationKind::PyImport),
"Del" => Some(OperationKind::Del),
_ => None, _ => None,
}) })
} }

View file

@ -14,7 +14,7 @@ use erg_type::typaram::TyParam;
use erg_type::value::ValueObj; use erg_type::value::ValueObj;
use erg_type::{HasType, Type}; use erg_type::{HasType, Type};
use crate::context::ImportKind; use crate::context::OperationKind;
use crate::hir::*; use crate::hir::*;
use crate::mod_cache::SharedModuleCache; use crate::mod_cache::SharedModuleCache;
@ -94,14 +94,14 @@ impl<'a> Linker<'a> {
Expr::UnaryOp(unaryop) => { Expr::UnaryOp(unaryop) => {
self.replace_import(&mut unaryop.expr); self.replace_import(&mut unaryop.expr);
} }
Expr::Call(call) => match call.import_kind() { Expr::Call(call) => match call.additional_operation() {
Some(ImportKind::ErgImport) => { Some(OperationKind::Import) => {
self.replace_erg_import(expr); self.replace_erg_import(expr);
} }
Some(ImportKind::PyImport) => { Some(OperationKind::PyImport) => {
self.replace_py_import(expr); self.replace_py_import(expr);
} }
None => { _ => {
for arg in call.args.pos_args.iter_mut() { for arg in call.args.pos_args.iter_mut() {
self.replace_import(&mut arg.expr); self.replace_import(&mut arg.expr);
} }

View file

@ -5,6 +5,7 @@
use erg_common::astr::AtomicStr; use erg_common::astr::AtomicStr;
use erg_common::config::ErgConfig; use erg_common::config::ErgConfig;
use erg_common::error::{Location, MultiErrorDisplay}; use erg_common::error::{Location, MultiErrorDisplay};
use erg_common::set;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::{Locational, Runnable, Stream}; use erg_common::traits::{Locational, Runnable, Stream};
use erg_common::vis::Visibility; use erg_common::vis::Visibility;
@ -24,7 +25,9 @@ use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{HasType, ParamTy, Type}; use erg_type::{HasType, ParamTy, Type};
use crate::context::instantiate::TyVarContext; use crate::context::instantiate::TyVarContext;
use crate::context::{ClassDefType, Context, ContextKind, RegistrationMode}; use crate::context::{
ClassDefType, Context, ContextKind, OperationKind, RegistrationMode, TraitInstance,
};
use crate::error::{ use crate::error::{
CompileError, CompileErrors, LowerError, LowerErrors, LowerResult, LowerWarning, LowerWarnings, CompileError, CompileErrors, LowerError, LowerErrors, LowerResult, LowerWarning, LowerWarnings,
SingleLowerResult, SingleLowerResult,
@ -252,7 +255,7 @@ impl ASTLowerer {
let maybe_len = self.ctx.eval_const_expr(len, None); let maybe_len = self.ctx.eval_const_expr(len, None);
match maybe_len { match maybe_len {
Ok(v @ ValueObj::Nat(_)) => { Ok(v @ ValueObj::Nat(_)) => {
if elem.ref_t().is_mut() { if elem.ref_t().is_mut_type() {
builtin_poly( builtin_poly(
"ArrayWithMutType!", "ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)], vec![TyParam::t(elem.t()), TyParam::Value(v)],
@ -262,7 +265,7 @@ impl ASTLowerer {
} }
} }
Ok(v @ ValueObj::Mut(_)) if v.class() == builtin_mono("Nat!") => { Ok(v @ ValueObj::Mut(_)) if v.class() == builtin_mono("Nat!") => {
if elem.ref_t().is_mut() { if elem.ref_t().is_mut_type() {
builtin_poly( builtin_poly(
"ArrayWithMutTypeAndLength!", "ArrayWithMutTypeAndLength!",
vec![TyParam::t(elem.t()), TyParam::Value(v)], vec![TyParam::t(elem.t()), TyParam::Value(v)],
@ -274,7 +277,7 @@ impl ASTLowerer {
Ok(other) => todo!("{other} is not a Nat object"), Ok(other) => todo!("{other} is not a Nat object"),
// REVIEW: is it ok to ignore the error? // REVIEW: is it ok to ignore the error?
Err(_e) => { Err(_e) => {
if elem.ref_t().is_mut() { if elem.ref_t().is_mut_type() {
builtin_poly( builtin_poly(
"ArrayWithMutType!", "ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::erased(Type::Nat)], vec![TyParam::t(elem.t()), TyParam::erased(Type::Nat)],
@ -508,7 +511,7 @@ impl ASTLowerer {
self.ctx self.ctx
.rec_get_var_t(&ident, &self.cfg.input, &self.ctx.name)?, .rec_get_var_t(&ident, &self.cfg.input, &self.ctx.name)?,
self.ctx self.ctx
.get_singular_ctx_from_ident(&ident, &self.ctx.name) .get_singular_ctx_by_ident(&ident, &self.ctx.name)
.ok() .ok()
.map(|ctx| ctx.name.clone()), .map(|ctx| ctx.name.clone()),
) )
@ -581,12 +584,31 @@ impl ASTLowerer {
None None
}; };
let call = hir::Call::new(obj, method_name, hir_args, sig_t); let call = hir::Call::new(obj, method_name, hir_args, sig_t);
if let Some(kind) = call.import_kind() { match call.additional_operation() {
let mod_name = enum_unwrap!(call.args.get_left_or_key("Path").unwrap(), hir::Expr::Lit); Some(kind @ (OperationKind::Import | OperationKind::PyImport)) => {
let mod_name =
enum_unwrap!(call.args.get_left_or_key("Path").unwrap(), hir::Expr::Lit);
if let Err(errs) = self.ctx.import_mod(kind, mod_name) { if let Err(errs) = self.ctx.import_mod(kind, mod_name) {
self.errs.extend(errs.into_iter()); self.errs.extend(errs.into_iter());
}; };
} }
Some(OperationKind::Del) => match call.args.get_left_or_key("obj").unwrap() {
hir::Expr::Accessor(hir::Accessor::Ident(ident)) => {
self.ctx.del(ident)?;
}
other => {
return Err(LowerErrors::from(LowerError::syntax_error(
self.input().clone(),
line!() as usize,
other.loc(),
self.ctx.caused_by(),
"",
None,
)))
}
},
_ => {}
}
Ok(call) Ok(call)
} }
@ -824,13 +846,14 @@ impl ASTLowerer {
} }
} }
let id = body.id; let id = body.id;
self.ctx let t = self
.ctx
.outer .outer
.as_mut() .as_mut()
.unwrap() .unwrap()
.assign_subr(&sig, id, found_body_t)?; .assign_subr(&sig, id, found_body_t)?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name); let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, Type::Subr(t)); let sig = hir::SubrSignature::new(ident, sig.params, t);
let body = hir::DefBody::new(body.op, block, body.id); let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body)) Ok(hir::Def::new(hir::Signature::Subr(sig), body))
} }
@ -939,6 +962,9 @@ impl ASTLowerer {
match self.ctx.check_decls_and_pop() { match self.ctx.check_decls_and_pop() {
Ok(methods) => { Ok(methods) => {
self.check_override(&class, &methods); self.check_override(&class, &methods);
if let Some((trait_, _)) = &impl_trait {
self.register_trait_impl(&class, trait_);
}
self.check_trait_impl(impl_trait, &class, &methods)?; self.check_trait_impl(impl_trait, &class, &methods)?;
self.push_methods(class, methods); self.push_methods(class, methods);
} }
@ -1033,6 +1059,8 @@ impl ASTLowerer {
} }
} }
/// Inspect the Trait implementation for correctness,
/// i.e., check that all required attributes are defined and that no extra attributes are defined
fn check_trait_impl( fn check_trait_impl(
&mut self, &mut self,
impl_trait: Option<(Type, Location)>, impl_trait: Option<(Type, Location)>,
@ -1127,6 +1155,18 @@ impl ASTLowerer {
Ok(()) Ok(())
} }
fn register_trait_impl(&mut self, class: &Type, trait_: &Type) {
// TODO: polymorphic trait
if let Some(impls) = self.ctx.trait_impls.get_mut(&trait_.name()) {
impls.insert(TraitInstance::new(class.clone(), trait_.clone()));
} else {
self.ctx.trait_impls.insert(
trait_.name(),
set! {TraitInstance::new(class.clone(), trait_.clone())},
);
}
}
fn push_methods(&mut self, class: Type, methods: Context) { fn push_methods(&mut self, class: Type, methods: Context) {
let (_, class_root) = self.ctx.get_mut_nominal_type_ctx(&class).unwrap(); let (_, class_root) = self.ctx.get_mut_nominal_type_ctx(&class).unwrap();
for (newly_defined_name, _vi) in methods.locals.iter() { for (newly_defined_name, _vi) in methods.locals.iter() {

View file

@ -212,7 +212,7 @@ impl OwnershipChecker {
self.errs.push(e); self.errs.push(e);
return; return;
} }
if acc.ref_t().is_mut() && ownership.is_owned() && !chunk { if acc.ref_t().is_mut_type() && ownership.is_owned() && !chunk {
self.drop(ident); self.drop(ident);
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_parser" name = "erg_parser"
version = "0.5.6" version = "0.5.7-nightly.1"
description = "The Erg parser" description = "The Erg parser"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -16,7 +16,7 @@ simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ]
[dependencies] [dependencies]
erg_common = { version = "0.5.6", path = "../erg_common" } erg_common = { version = "0.5.7-nightly.1", path = "../erg_common" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "erg_type" name = "erg_type"
version = "0.5.6" version = "0.5.7-nightly.1"
description = "APIs for Erg types" description = "APIs for Erg types"
authors = ["erg-lang team <moderation.erglang@gmail.com>"] authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
@ -18,8 +18,8 @@ simplified_chinese = [ "erg_common/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese" ] traditional_chinese = [ "erg_common/traditional_chinese" ]
[dependencies] [dependencies]
erg_common = { version = "0.5.6", path = "../erg_common" } erg_common = { version = "0.5.7-nightly.1", path = "../erg_common" }
erg_parser = { version = "0.5.6", path = "../erg_parser" } erg_parser = { version = "0.5.7-nightly.1", path = "../erg_parser" }
[lib] [lib]
path = "lib.rs" path = "lib.rs"

View file

@ -3,10 +3,15 @@ use std::convert::TryInto;
use crate::*; use crate::*;
#[inline] #[inline]
pub const fn param_t(name: &'static str, ty: Type) -> ParamTy { pub const fn kw(name: &'static str, ty: Type) -> ParamTy {
ParamTy::kw(Str::ever(name), ty) ParamTy::kw(Str::ever(name), ty)
} }
#[inline]
pub const fn kw_default(name: &'static str, ty: Type, default: Type) -> ParamTy {
ParamTy::kw_default(Str::ever(name), ty, default)
}
#[inline] #[inline]
pub const fn anon(ty: Type) -> ParamTy { pub const fn anon(ty: Type) -> ParamTy {
ParamTy::anonymous(ty) ParamTy::anonymous(ty)

View file

@ -436,6 +436,16 @@ impl<T: Clone + HasLevel> Free<T> {
*self.borrow_mut() = FreeKind::Linked(to.clone()); *self.borrow_mut() = FreeKind::Linked(to.clone());
} }
pub fn forced_link(&self, to: &T) {
// prevent linking to self
if self.is_linked() && addr_eq!(*self.crack(), *to) {
return;
}
unsafe {
*self.as_ptr() = FreeKind::Linked(to.clone());
}
}
pub fn undoable_link(&self, to: &T) { pub fn undoable_link(&self, to: &T) {
if self.is_linked() && addr_eq!(*self.crack(), *to) { if self.is_linked() && addr_eq!(*self.crack(), *to) {
panic!("link to self"); panic!("link to self");

View file

@ -724,6 +724,7 @@ impl Predicate {
pub enum ParamTy { pub enum ParamTy {
Pos { name: Option<Str>, ty: Type }, Pos { name: Option<Str>, ty: Type },
Kw { name: Str, ty: Type }, Kw { name: Str, ty: Type },
KwWithDefault { name: Str, ty: Type, default: Type },
} }
impl fmt::Display for ParamTy { impl fmt::Display for ParamTy {
@ -736,6 +737,9 @@ impl fmt::Display for ParamTy {
write!(f, ": {}", ty) write!(f, ": {}", ty)
} }
Self::Kw { name, ty } => write!(f, "{}: {}", name, ty), Self::Kw { name, ty } => write!(f, "{}: {}", name, ty),
Self::KwWithDefault { name, ty, default } => {
write!(f, "{}: {} := {}", name, ty, default)
}
} }
} }
} }
@ -749,6 +753,10 @@ impl ParamTy {
Self::Kw { name, ty } Self::Kw { name, ty }
} }
pub const fn kw_default(name: Str, ty: Type, default: Type) -> Self {
Self::KwWithDefault { name, ty, default }
}
pub const fn anonymous(ty: Type) -> Self { pub const fn anonymous(ty: Type) -> Self {
Self::pos(None, ty) Self::pos(None, ty)
} }
@ -756,26 +764,27 @@ impl ParamTy {
pub fn name(&self) -> Option<&Str> { pub fn name(&self) -> Option<&Str> {
match self { match self {
Self::Pos { name, .. } => name.as_ref(), Self::Pos { name, .. } => name.as_ref(),
Self::Kw { name, .. } => Some(name), Self::Kw { name, .. } | Self::KwWithDefault { name, .. } => Some(name),
} }
} }
pub const fn typ(&self) -> &Type { pub const fn typ(&self) -> &Type {
match self { match self {
Self::Pos { ty, .. } | Self::Kw { ty, .. } => ty, Self::Pos { ty, .. } | Self::Kw { ty, .. } | Self::KwWithDefault { ty, .. } => ty,
} }
} }
pub fn typ_mut(&mut self) -> &mut Type { pub fn typ_mut(&mut self) -> &mut Type {
match self { match self {
Self::Pos { ty, .. } | Self::Kw { ty, .. } => ty, Self::Pos { ty, .. } | Self::Kw { ty, .. } | Self::KwWithDefault { ty, .. } => ty,
} }
} }
pub fn deconstruct(self) -> (Option<Str>, Type) { pub fn deconstruct(self) -> (Option<Str>, Type, Option<Type>) {
match self { match self {
Self::Pos { name, ty } => (name, ty), Self::Pos { name, ty } => (name, ty, None),
Self::Kw { name, ty } => (Some(name), ty), Self::Kw { name, ty } => (Some(name), ty, None),
Self::KwWithDefault { name, ty, default } => (Some(name), ty, Some(default)),
} }
} }
} }
@ -931,11 +940,12 @@ impl LimitedDisplay for RefinementType {
return write!(f, "..."); return write!(f, "...");
} }
let first_subj = self.preds.iter().next().and_then(|p| p.subject()); let first_subj = self.preds.iter().next().and_then(|p| p.subject());
if self let is_simple_type = self.t.is_simple_class();
let is_simple_preds = self
.preds .preds
.iter() .iter()
.all(|p| p.is_equal() && p.subject() == first_subj) .all(|p| p.is_equal() && p.subject() == first_subj);
{ if is_simple_type && is_simple_preds {
write!(f, "{{")?; write!(f, "{{")?;
for pred in self.preds.iter() { for pred in self.preds.iter() {
let (_, rhs) = enum_unwrap!(pred, Predicate::Equal { lhs, rhs }); let (_, rhs) = enum_unwrap!(pred, Predicate::Equal { lhs, rhs });
@ -1684,11 +1694,25 @@ impl Type {
} }
} }
pub fn is_mut(&self) -> bool { /// Procedure or MutType?
pub fn is_procedural(&self) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_procedural(),
Self::Callable { .. } => true,
Self::Subr(subr) if subr.kind == SubrKind::Proc => true,
Self::Refinement(refine) =>
refine.t.is_procedural() || refine.preds.iter().any(|pred|
matches!(pred, Predicate::Equal{ rhs, .. } if pred.mentions(&refine.var) && rhs.name().map(|n| n.ends_with('!')).unwrap_or(false))
),
_ => false,
}
}
pub fn is_mut_type(&self) -> bool {
match self { match self {
Self::FreeVar(fv) => { Self::FreeVar(fv) => {
if fv.is_linked() { if fv.is_linked() {
fv.crack().is_mut() fv.crack().is_mut_type()
} else { } else {
fv.unbound_name().unwrap().ends_with('!') fv.unbound_name().unwrap().ends_with('!')
} }
@ -1700,7 +1724,7 @@ impl Type {
| Self::BuiltinPoly { name, .. } | Self::BuiltinPoly { name, .. }
| Self::PolyQVar { name, .. } | Self::PolyQVar { name, .. }
| Self::MonoProj { rhs: name, .. } => name.ends_with('!'), | Self::MonoProj { rhs: name, .. } => name.ends_with('!'),
Self::Refinement(refine) => refine.t.is_mut(), Self::Refinement(refine) => refine.t.is_mut_type(),
_ => false, _ => false,
} }
} }
@ -1730,6 +1754,14 @@ impl Type {
} }
} }
pub fn is_quantified(&self) -> bool {
match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().is_quantified(),
Self::Quantified(_) => true,
_ => false,
}
}
pub fn contains_tvar(&self, name: &str) -> bool { pub fn contains_tvar(&self, name: &str) -> bool {
match self { match self {
Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_tvar(name), Self::FreeVar(fv) if fv.is_linked() => fv.crack().contains_tvar(name),

View file

@ -9,6 +9,9 @@
* [pre-commit](https://pre-commit.com/) * [pre-commit](https://pre-commit.com/)
We use pre-commit to have clippy check and test automatically.
The checks may fail on the first run even if there are no bugs, in which case you should try committing again.
* Python3 interpreter * Python3 interpreter
## Recommendation ## Recommendation

View file

@ -1,6 +1,6 @@
# 開発環境 # 開発環境
[![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/dev_guide/env.md%26commit_hash%3D61d72afbbfdba8c2ca994499c7ec9f8fc01440cb)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/dev_guide/env.md&commit_hash=61d72afbbfdba8c2ca994499c7ec9f8fc01440cb) [![badge](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fgezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com%2Fdefault%2Fsource_up_to_date%3Fowner%3Derg-lang%26repos%3Derg%26ref%3Dmain%26path%3Ddoc/EN/dev_guide/env.md%26commit_hash%3D735c840e681ad106795654212680696a2be29eee)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/dev_guide/env.md&commit_hash=735c840e681ad106795654212680696a2be29eee)
## インストールが必要なもの ## インストールが必要なもの
@ -11,6 +11,9 @@
* [pre-commit](https://pre-commit.com/) * [pre-commit](https://pre-commit.com/)
pre-commitを使ってclippyのチェックやテストを自動で行わせています。
バグがなくても最初の実行でチェックが失敗する場合があります。その場合はもう一度コミットを試みてください。
* Python3インタープリタ * Python3インタープリタ
## 推奨 ## 推奨

View file

@ -5,7 +5,7 @@
Dictはキーと値のペアを持つコレクションです。 Dictはキーと値のペアを持つコレクションです。
```python ```python
ids = {"Alice": 145, "Bob": 214, "Charlie": 301} ids = {"Alice" >: 145, "Bob": 214, "Charlie": 301}
assert ids["Alice"] == 145 assert ids["Alice"] == 145
``` ```

View file

@ -28,3 +28,12 @@ assert fold(g, [1, 2, 3]) == 8
1番目は、デフォルト引数のある関数は、ない関数と同一視できる、という意味である。 1番目は、デフォルト引数のある関数は、ない関数と同一視できる、という意味である。
2番目は、任意のデフォルト引数は省略できる、という意味である。 2番目は、任意のデフォルト引数は省略できる、という意味である。
デフォルト引数の型は、引数を渡した場合と渡さなかった場合で変えることができる。
具体的には、`if`関数の型などが良い例である。
```python
if: |T: Type, U: Type|(then: () -> T, else: () -> U := () -> NoneType) -> T or U
```
`if`関数は、`else`引数が与えられなければ`T or NoneType`を返す。

View file

@ -7,3 +7,8 @@ if True, do:
f x: Int = log x f x: Int = log x
g x: Int = print! x # this should cause an effect error g x: Int = print! x # this should cause an effect error
echo = print! # this should be an effect error
_echo = # this is OK
print! 1
log

82
library/std/_prelude.er Normal file
View file

@ -0,0 +1,82 @@
@Attach NeImpl
Eq(R := Self) = Trait {
.`==` = (self: Self, R) -> Bool
}
NeImpl R = Patch Eq R
NeImpl(R).
`!=`(self, other: R): Bool = not(self == other)
@Attach EqImpl, LeImpl, LtImpl, GeImpl, GtImpl
PartialOrd(R := Self) = Trait {
.cmp = (self: Self, R) -> Option Ordering
}
Ord = Subsume PartialOrd()
EqForOrd R = Patch Ord, Impl := Eq()
EqForOrd(R).
`==`(self, other: R): Bool = self.cmp(other) == Ordering.Equal
LeForOrd = Patch Ord
LeForOrd.
`<=`(self, other: Self): Bool = self.cmp(other) == Ordering.Less or self == other
LtForOrd = Patch Ord
LtForOrd.
`<`(self, other: Self): Bool = self.cmp(other) == Ordering.Less
GeForOrd = Patch Ord
GeForOrd.
`>=`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater or self == other
GtForOrd = Patch Ord
GtForOrd.
`>`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater
Add(R := Self) = Trait {
.Output = Type
.`_+_` = (self: Self, R) -> Self.Output
}
Sub(R := Self) = Trait {
.Output = Type
.`_-_` = (self: Self, R) -> Self.Output
}
Mul(R := Self()) = Trait {
.Output = Type
.`*` = (self: Self, R) -> Self.Output
}
Div(R := Self) = Trait {
.Output = Type
.`/` = (self: Self, R) -> Self.Output or Panic
}
Num: (R := Type) -> Type
Num = Add and Sub and Mul
Seq T = Trait {
.__len__ = (self: Ref(Self)) -> Nat
.get = (self: Ref(Self), Nat) -> T
}
`_+_`: |R: Type, A <: Add(R)| (A, R) -> A.AddO
`_-_`: |R: Type, S <: Add(R)| (S, R) -> S.SubO
`*`: |R, O: Type, M <: Add(R)| (M, R) -> M.MulO
`/`: |R, O: Type, D <: Add(R)| (D, R) -> D.DivO
AddForInt = Patch Int, Impl := Add()
AddForInt.AddO = Int
AddForInt.
`_+_`: (self: Self, other: Int) -> Int = magic("Add.`_+_`")
# TODO: Mul and Div
NumForInterval M, N, O, P: Int =
Patch M..N, Impl := Add(R := O..P) and Sub(R := O..P)
NumForInterval(M, N, O, P).
`_+_`: (self: Self, other: O..P) -> M+O..N+P = magic("NumForInterval.`_+_`")
`_-_`: (self: Self, other: O..P) -> M-P..N-O = magic("NumForInterval.`_-_`")
Read = Trait {
.read = (self: Ref(Self)) -> Str
}
Read! = Trait {
.read! = (self: Ref!(Self)) => Str
}
Write! = Trait {
.write! = (self: Ref!(Self), Str) => ()
}

View file

@ -1,82 +1,12 @@
@Attach NeImpl discard _x = None
Eq(R := Self) = Trait {
.`==` = (self: Self, R) -> Bool
}
NeImpl R = Patch Eq R discard 1
NeImpl(R).
`!=`(self, other: R): Bool = not(self == other)
@Attach EqImpl, LeImpl, LtImpl, GeImpl, GtImpl cond c, then, else =
PartialOrd(R := Self) = Trait { if c:
.cmp = (self: Self, R) -> Option Ordering do then
} do else
Ord = Subsume PartialOrd()
EqForOrd R = Patch Ord, Impl := Eq() assert cond(False, 1, 2) == 2
EqForOrd(R). # assert cond(True, 1, 3) == "a"
`==`(self, other: R): Bool = self.cmp(other) == Ordering.Equal # assert "a" == cond(True, 1, 3)
LeForOrd = Patch Ord
LeForOrd.
`<=`(self, other: Self): Bool = self.cmp(other) == Ordering.Less or self == other
LtForOrd = Patch Ord
LtForOrd.
`<`(self, other: Self): Bool = self.cmp(other) == Ordering.Less
GeForOrd = Patch Ord
GeForOrd.
`>=`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater or self == other
GtForOrd = Patch Ord
GtForOrd.
`>`(self, other: Self): Bool = self.cmp(other) == Ordering.Greater
Add(R := Self) = Trait {
.Output = Type
.`_+_` = (self: Self, R) -> Self.Output
}
Sub(R := Self) = Trait {
.Output = Type
.`_-_` = (self: Self, R) -> Self.Output
}
Mul(R := Self()) = Trait {
.Output = Type
.`*` = (self: Self, R) -> Self.Output
}
Div(R := Self) = Trait {
.Output = Type
.`/` = (self: Self, R) -> Self.Output or Panic
}
Num: (R := Type) -> Type
Num = Add and Sub and Mul
Seq T = Trait {
.__len__ = (self: Ref(Self)) -> Nat
.get = (self: Ref(Self), Nat) -> T
}
`_+_`: |R: Type, A <: Add(R)| (A, R) -> A.AddO
`_-_`: |R: Type, S <: Add(R)| (S, R) -> S.SubO
`*`: |R, O: Type, M <: Add(R)| (M, R) -> M.MulO
`/`: |R, O: Type, D <: Add(R)| (D, R) -> D.DivO
AddForInt = Patch Int, Impl := Add()
AddForInt.AddO = Int
AddForInt.
`_+_`: (self: Self, other: Int) -> Int = magic("Add.`_+_`")
# TODO: Mul and Div
NumForInterval M, N, O, P: Int =
Patch M..N, Impl := Add(R := O..P) and Sub(R := O..P)
NumForInterval(M, N, O, P).
`_+_`: (self: Self, other: O..P) -> M+O..N+P = magic("NumForInterval.`_+_`")
`_-_`: (self: Self, other: O..P) -> M-P..N-O = magic("NumForInterval.`_-_`")
Read = Trait {
.read = (self: Ref(Self)) -> Str
}
Read! = Trait {
.read! = (self: Ref!(Self)) => Str
}
Write! = Trait {
.write! = (self: Ref!(Self), Str) => ()
}

View file

@ -1,5 +0,0 @@
add x, y =
x + y
print! 1 + 1
print! 1.0 + 1

7
tests/addition.er Normal file
View file

@ -0,0 +1,7 @@
add x, y =
x + y
print! add(1, 1)
print! add(1.0, 1)
print! add("a", "b")
print! add("a", 1) # this will be an error

View file

@ -1,6 +1,6 @@
for! 1..100, i => for! 1..<100, i =>
match (i % 3, i % 5): match (i % 3, i % 5):
0, 0 => print! "FizzBuzz" (0, 0) => print! "FizzBuzz"
0, _ => print! "Fizz" (0, _) => print! "Fizz"
_, 0 => print! "Buzz" (_, 0) => print! "Buzz"
_ => print! i (_, _) => print! i

14
tests/infer_class.er Normal file
View file

@ -0,0 +1,14 @@
_abs x =
x.abs() # currently this method only implemented for integers
assert _abs(-1) == 1
#[
push! a, elem =
a.push!(elem)
a
a = ![]
b = push! a, 1
print! b
]#

6
tests/infer_trait.er Normal file
View file

@ -0,0 +1,6 @@
show s =
s.to_str()
assert show(1) == "1"
assert show(True) == "True"
# discard show((x,) -> x)

View file

@ -1,5 +1,5 @@
v = ![] v = ![]
for! 0..10, i => for! 0..<10, i =>
v.push! i v.push! i
log v.sum() log v.sum()

10
tests/rec.er Normal file
View file

@ -0,0 +1,10 @@
stop_or_call n, f: (Nat -> Nat), g: (Nat -> Nat) =
cond n <= 0:
1
g (f (n - 1))
fact(n: Nat): Nat =
stop_or_call n, fact, (r, ) -> r * n
print! fact
print! fact 5

6
tests/subtyping.er Normal file
View file

@ -0,0 +1,6 @@
f(x: Nat): Int = x
y: Ratio = f 1
# Erg's type checking does not necessarily enlarge the type. So this is OK.
z: Int = y
# But this is invalid.
invalid: 10..<20 = z

View file

@ -6,6 +6,11 @@ use erg_common::traits::Runnable;
use erg::dummy::DummyVM; use erg::dummy::DummyVM;
#[test]
fn exec_addition() -> Result<(), ()> {
expect_failure("tests/addition.er")
}
#[test] #[test]
fn exec_class() -> Result<(), ()> { fn exec_class() -> Result<(), ()> {
expect_success("examples/class.er") expect_success("examples/class.er")
@ -31,6 +36,16 @@ fn exec_import() -> Result<(), ()> {
expect_success("examples/import.er") expect_success("examples/import.er")
} }
#[test]
fn exec_infer_class() -> Result<(), ()> {
expect_success("tests/infer_class.er")
}
#[test]
fn exec_infer_trait() -> Result<(), ()> {
expect_success("tests/infer_trait.er")
}
#[test] #[test]
fn exec_move_check() -> Result<(), ()> { fn exec_move_check() -> Result<(), ()> {
expect_failure("examples/move_check.er") expect_failure("examples/move_check.er")
@ -41,6 +56,12 @@ fn exec_quantified() -> Result<(), ()> {
expect_success("examples/quantified.er") expect_success("examples/quantified.er")
} }
#[test]
fn exec_rec() -> Result<(), ()> {
// this script is valid but the current code generating process has a bug.
expect_end_with("tests/rec.er", 1)
}
#[test] #[test]
fn exec_record() -> Result<(), ()> { fn exec_record() -> Result<(), ()> {
expect_success("examples/record.er") expect_success("examples/record.er")
@ -51,6 +72,11 @@ fn exec_side_effect() -> Result<(), ()> {
expect_failure("examples/side_effect.er") expect_failure("examples/side_effect.er")
} }
#[test]
fn exec_subtyping() -> Result<(), ()> {
expect_failure("tests/subtyping.er")
}
#[test] #[test]
fn exec_trait() -> Result<(), ()> { fn exec_trait() -> Result<(), ()> {
expect_success("examples/trait.er") expect_success("examples/trait.er")