Merge branch 'main' into dict

This commit is contained in:
Shunsuke Shibayama 2022-10-10 13:57:08 +09:00
commit c784ba261e
53 changed files with 1336 additions and 818 deletions

View file

@ -1,25 +1,34 @@
[package]
name = "erg_compiler"
version = "0.5.7"
description = "Centimetre: the Erg compiler"
authors = ["erg-lang team <moderation.erglang@gmail.com>"]
license = "MIT OR Apache-2.0"
edition = "2021"
repository = "https://github.com/erg-lang/erg/tree/main/src/compiler/erg_compiler"
documentation = "https://docs.rs/erg_compiler"
homepage = "https://erg-lang.github.io/"
documentation = "http://docs.rs/erg_compiler"
build = "build.rs"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
homepage.workspace = true
[features]
# when "debug" feature is turned on, that of parser will also be turned on.
debug = [ "erg_common/debug", "erg_parser/debug", "erg_type/debug" ]
japanese = [ "erg_common/japanese", "erg_parser/japanese", "erg_type/japanese" ]
simplified_chinese = [ "erg_common/simplified_chinese", "erg_parser/simplified_chinese", "erg_type/simplified_chinese" ]
traditional_chinese = [ "erg_common/traditional_chinese", "erg_parser/traditional_chinese", "erg_type/traditional_chinese" ]
debug = ["erg_common/debug", "erg_parser/debug", "erg_type/debug"]
japanese = ["erg_common/japanese", "erg_parser/japanese", "erg_type/japanese"]
simplified_chinese = [
"erg_common/simplified_chinese",
"erg_parser/simplified_chinese",
"erg_type/simplified_chinese",
]
traditional_chinese = [
"erg_common/traditional_chinese",
"erg_parser/traditional_chinese",
"erg_type/traditional_chinese",
]
[dependencies]
erg_common = { version = "0.5.7", path = "../erg_common" }
erg_parser = { version = "0.5.7", path = "../erg_parser" }
erg_type = { version = "0.5.7", path = "../erg_type" }
erg_common = { version = "0.5.9-nightly.0", path = "../erg_common" }
erg_parser = { version = "0.5.9-nightly.0", path = "../erg_parser" }
erg_type = { version = "0.5.9-nightly.0", path = "../erg_type" }
[lib]
path = "lib.rs"

View file

@ -0,0 +1,33 @@
#![allow(deprecated)]
use std::env;
use std::fs;
use std::path;
fn main() -> std::io::Result<()> {
// Create a ".erg" directory
let erg_path = env::home_dir()
.expect("failed to get the location of the home dir")
.to_str()
.expect("invalid encoding of the home dir name")
.to_string()
+ "/.erg";
if !path::Path::new(&erg_path).exists() {
fs::create_dir(&erg_path)?;
fs::create_dir(format!("{erg_path}/std"))?;
}
println!("cargo:rustc-env=ERG_PATH={erg_path}");
println!("cargo:rustc-env=ERG_STD_PATH={erg_path}/std");
// create a std library in ".erg"
for res in fs::read_dir("std")? {
let entry = res?;
let path = entry.path();
let filename = path
.file_name()
.expect("this is not a file")
.to_str()
.unwrap();
fs::copy(&path, format!("{erg_path}/std/{filename}"))?;
}
Ok(())
}

View file

@ -29,7 +29,7 @@ use erg_type::value::ValueObj;
use erg_type::{HasType, Type, TypeCode, TypePair};
use crate::compile::{AccessKind, Name, StoreLoadKind};
use crate::context::eval::eval_lit;
use crate::context::eval::type_from_token_kind;
use crate::error::CompileError;
use crate::hir::{
Accessor, Args, Array, AttrDef, Attribute, BinOp, Block, Call, ClassDef, Def, DefBody, Expr,
@ -867,7 +867,7 @@ impl CodeGenerator {
self.write_instr(MAKE_FUNCTION);
self.write_arg(0);
self.emit_load_const(def.sig.ident().inspect().clone());
self.emit_load_name_instr(Identifier::private(Str::ever("#ABCMeta")));
self.emit_load_name_instr(Identifier::private("#ABCMeta"));
self.emit_load_const(vec![ValueObj::from("metaclass")]);
let subclasses_len = 1;
self.write_instr(Opcode::CALL_FUNCTION_KW);
@ -917,7 +917,7 @@ impl CodeGenerator {
self.emit_empty_func(
Some(sig.ident().inspect()),
def.sig.into_ident(),
Some(Identifier::private(Str::ever("#abstractmethod"))),
Some(Identifier::private("#abstractmethod")),
);
}
self.emit_load_const(ValueObj::None);
@ -1129,7 +1129,7 @@ impl CodeGenerator {
CompileError::feature_error(
self.cfg.input.clone(),
unary.op.loc(),
"",
&unary.op.inspect().clone(),
AtomicStr::from(unary.op.content),
)
.write_to_stderr();
@ -1150,6 +1150,9 @@ impl CodeGenerator {
self.emit_load_name_instr(Identifier::public("range"));
}
TokenKind::LeftOpen | TokenKind::Closed | TokenKind::Open => todo!(),
TokenKind::InOp => {
self.emit_load_name_instr(Identifier::private("#in_operator"));
}
_ => {}
}
let type_pair = TypePair::new(bin.lhs_t(), bin.rhs_t());
@ -1170,14 +1173,16 @@ impl CodeGenerator {
| TokenKind::NotEq
| TokenKind::Gre
| TokenKind::GreEq => COMPARE_OP,
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed | TokenKind::Open => {
CALL_FUNCTION
} // ERG_BINARY_RANGE,
TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Closed
| TokenKind::Open
| TokenKind::InOp => CALL_FUNCTION, // ERG_BINARY_RANGE,
_ => {
CompileError::feature_error(
self.cfg.input.clone(),
bin.op.loc(),
"",
&bin.op.inspect().clone(),
AtomicStr::from(bin.op.content),
)
.write_to_stderr();
@ -1191,14 +1196,22 @@ impl CodeGenerator {
TokenKind::NotEq => 3,
TokenKind::Gre => 4,
TokenKind::GreEq => 5,
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Closed | TokenKind::Open => 2,
TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Closed
| TokenKind::Open
| TokenKind::InOp => 2,
_ => type_pair as u8,
};
self.write_instr(instr);
self.write_arg(arg);
self.stack_dec();
match &bin.op.kind {
TokenKind::LeftOpen | TokenKind::RightOpen | TokenKind::Open | TokenKind::Closed => {
TokenKind::LeftOpen
| TokenKind::RightOpen
| TokenKind::Open
| TokenKind::Closed
| TokenKind::InOp => {
self.stack_dec();
}
_ => {}
@ -1339,7 +1352,11 @@ impl CodeGenerator {
self.emit_store_instr(ident, AccessKind::Name);
}
ParamPattern::Lit(lit) => {
self.emit_load_const(eval_lit(&lit));
let value = {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content).unwrap()
};
self.emit_load_const(value);
self.write_instr(Opcode::COMPARE_OP);
self.write_arg(2); // ==
self.stack_dec();
@ -1597,7 +1614,7 @@ impl CodeGenerator {
log!(info "entered {} ({rec})", fn_name!());
let attrs_len = rec.attrs.len();
// making record type
let ident = Identifier::private(Str::ever("#NamedTuple"));
let ident = Identifier::private("#NamedTuple");
self.emit_load_name_instr(ident);
// record name, let it be anonymous
self.emit_load_const("Record");
@ -1615,10 +1632,10 @@ impl CodeGenerator {
self.write_arg(2);
// (1 (subroutine) + argc + kwsc) input objects -> 1 return object
self.stack_dec_n((1 + 2 + 0) - 1);
let ident = Identifier::private(Str::ever("#rec"));
let ident = Identifier::private("#rec");
self.emit_store_instr(ident, Name);
// making record instance
let ident = Identifier::private(Str::ever("#rec"));
let ident = Identifier::private("#rec");
self.emit_load_name_instr(ident);
for field in rec.attrs.into_iter() {
self.emit_frameless_block(field.body.block, vec![]);
@ -1687,6 +1704,15 @@ impl CodeGenerator {
self.stack_dec_n(len - 1);
}
}
Array::WithLength(arr) => {
self.emit_expr(*arr.elem);
self.write_instr(BUILD_LIST);
self.write_arg(1u8);
self.emit_expr(*arr.len);
self.write_instr(BINARY_MULTIPLY);
self.write_arg(0);
self.stack_dec();
}
other => todo!("{other}"),
},
// TODO: tuple comprehension
@ -1720,7 +1746,11 @@ impl CodeGenerator {
self.stack_dec_n(len - 1);
}
}
crate::hir::Set::WithLength(_) => todo!(),
crate::hir::Set::WithLength(st) => {
self.emit_expr(*st.elem);
self.write_instr(BUILD_SET);
self.write_arg(1u8);
}
},
Expr::Record(rec) => self.emit_record(rec),
Expr::Code(code) => {
@ -1739,7 +1769,7 @@ impl CodeGenerator {
}
// Dict,
other => {
CompileError::feature_error(self.cfg.input.clone(), other.loc(), "???", "".into())
CompileError::feature_error(self.cfg.input.clone(), other.loc(), "Dict", "".into())
.write_to_stderr();
self.crash("cannot compile this expression at this time");
}
@ -1894,7 +1924,7 @@ impl CodeGenerator {
attrs.push(Expr::AttrDef(attr_def));
}
let none = Token::new(TokenKind::NoneLit, "None", line, 0);
attrs.push(Expr::Lit(Literal::from(none)));
attrs.push(Expr::Lit(Literal::try_from(none).unwrap()));
}
other => todo!("{other}"),
}
@ -2007,15 +2037,40 @@ impl CodeGenerator {
fn load_prelude(&mut self) {
self.load_record_type();
self.load_prelude_py();
self.record_type_loaded = true;
}
fn load_prelude_py(&mut self) {
self.emit_global_import_items(
Identifier::public("sys"),
vec![(
Identifier::public("path"),
Some(Identifier::private("#path")),
)],
);
self.emit_load_name_instr(Identifier::private("#path"));
self.emit_load_method_instr("Array!", None, Identifier::public("push!"));
self.emit_load_const(env!("ERG_STD_PATH"));
self.write_instr(CALL_METHOD);
self.write_arg(1u8);
self.stack_dec();
self.emit_pop_top();
self.emit_global_import_items(
Identifier::public("_erg_std_prelude"),
vec![(
Identifier::public("in_operator"),
Some(Identifier::private("#in_operator")),
)],
);
}
fn load_record_type(&mut self) {
self.emit_global_import_items(
Identifier::public("collections"),
vec![(
Identifier::public("namedtuple"),
Some(Identifier::private(Str::ever("#NamedTuple"))),
Some(Identifier::private("#NamedTuple")),
)],
);
}
@ -2026,11 +2081,11 @@ impl CodeGenerator {
vec![
(
Identifier::public("ABCMeta"),
Some(Identifier::private(Str::ever("#ABCMeta"))),
Some(Identifier::private("#ABCMeta")),
),
(
Identifier::public("abstractmethod"),
Some(Identifier::private(Str::ever("#abstractmethod"))),
Some(Identifier::private("#abstractmethod")),
),
],
);
@ -2041,7 +2096,7 @@ impl CodeGenerator {
Identifier::public("types"),
vec![(
Identifier::public("ModuleType"),
Some(Identifier::private(Str::ever("#ModuleType"))),
Some(Identifier::private("#ModuleType")),
)],
);
}

View file

@ -681,25 +681,26 @@ impl Context {
pub(crate) fn cyclic_supertype_of(&self, lhs: &FreeTyVar, rhs: &Type) -> bool {
let subst_ctx = SubstContext::new(rhs, self, Location::Unknown);
if let Some(super_traits) = self.get_nominal_type_ctx(rhs).map(|ctx| &ctx.super_traits) {
for sup_trait in super_traits {
let sup_trait = if sup_trait.has_qvar() {
subst_ctx.substitute(sup_trait.clone()).unwrap()
for super_trait in super_traits {
let sup_trait = if super_trait.has_qvar() {
subst_ctx.substitute(super_trait.clone()).unwrap()
} else {
sup_trait.clone()
super_trait.clone()
};
if self.sup_conforms(lhs, rhs, &sup_trait) {
return true;
}
}
}
if let Some(sup_classes) = self.get_nominal_type_ctx(rhs).map(|ctx| &ctx.super_classes) {
for sup_class in sup_classes {
let sup_class = if sup_class.has_qvar() {
subst_ctx.substitute(sup_class.clone()).unwrap()
if let Some(super_classes) = self.get_super_classes(rhs) {
for super_class in super_classes {
let sup_class = if super_class.has_qvar() {
subst_ctx.substitute(super_class).unwrap()
} else {
sup_class.clone()
super_class
};
if self.cyclic_supertype_of(lhs, &sup_class) {
log!(err "引っかかった: {lhs}, {sup_class}");
return true;
}
}
@ -849,6 +850,9 @@ impl Context {
/// returns union of two types (A or B)
pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
return lhs.clone();
}
// `?T or ?U` will not be unified
// `Set!(?T, 3) or Set(?T, 3)` wii be unified to Set(?T, 3)
if !lhs.is_unbound_var() && !rhs.is_unbound_var() {
@ -888,6 +892,9 @@ impl Context {
/// returns intersection of two types (A and B)
pub(crate) fn intersection(&self, lhs: &Type, rhs: &Type) -> Type {
if lhs == rhs {
return lhs.clone();
}
// ?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)) {

View file

@ -100,12 +100,6 @@ fn op_to_name(op: OpKind) -> &'static str {
}
}
#[inline]
pub(crate) fn eval_lit(lit: &Literal) -> ValueObj {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content.clone())
}
/// Instantiate the polymorphic type from the quantified state.
///
/// e.g.
@ -577,13 +571,26 @@ impl Context {
Ok(ValueObj::Subr(subr))
}
pub(crate) fn eval_lit(&self, lit: &Literal) -> EvalResult<ValueObj> {
let t = type_from_token_kind(lit.token.kind);
ValueObj::from_str(t, lit.token.content.clone()).ok_or_else(|| {
EvalError::invalid_literal(
self.cfg.input.clone(),
line!() as usize,
lit.token.loc(),
self.caused_by(),
)
.into()
})
}
pub(crate) fn eval_const_expr(
&self,
expr: &Expr,
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Lit(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),
@ -603,7 +610,7 @@ impl Context {
__name__: Option<&Str>,
) -> EvalResult<ValueObj> {
match expr {
Expr::Lit(lit) => Ok(eval_lit(lit)),
Expr::Lit(lit) => self.eval_lit(lit),
Expr::Accessor(acc) => self.eval_const_acc(acc),
Expr::BinOp(bin) => self.eval_const_bin(bin),
Expr::UnaryOp(unary) => self.eval_const_unary(unary),

View file

@ -109,9 +109,14 @@ impl Context {
panic!("{} has already been registered as const", t.name());
} else {
let name = VarName::from_str(t.name());
let meta_t = match ctx.kind {
ContextKind::Class => Type::ClassType,
ContextKind::Trait => Type::TraitType,
_ => Type::Type,
};
self.locals.insert(
name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None),
VarInfo::new(meta_t, muty, Private, Builtin, None),
);
self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone()));
@ -156,9 +161,14 @@ impl Context {
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
} else {
let name = VarName::from_str(t.name());
let meta_t = match ctx.kind {
ContextKind::Class => Type::ClassType,
ContextKind::Trait => Type::TraitType,
_ => Type::Type,
};
self.locals.insert(
name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None),
VarInfo::new(meta_t, muty, Private, Builtin, None),
);
self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone()));
@ -203,7 +213,7 @@ impl Context {
let name = VarName::from_static(name);
self.locals.insert(
name.clone(),
VarInfo::new(Type, muty, Private, Builtin, None),
VarInfo::new(Patch, muty, Private, Builtin, None),
);
for method_name in ctx.locals.keys() {
if let Some(patches) = self.method_impl_patches.get_mut(method_name) {
@ -454,7 +464,7 @@ impl Context {
/* Obj */
let mut obj = Self::builtin_mono_class("Obj", 2);
let t = fn0_met(mono_q("Self"), mono_q("Self"));
let t = quant(t, set! {subtypeof(mono_q("Self"), builtin_mono("Obj"))});
let t = quant(t, set! {subtypeof(mono_q("Self"), Obj)});
obj.register_builtin_impl("clone", t, Const, Public);
obj.register_builtin_impl("__module__", Str, Const, Public);
obj.register_builtin_impl("__sizeof__", fn0_met(Obj, Nat), Const, Public);
@ -469,10 +479,11 @@ impl Context {
);
let mut obj_in = Self::builtin_methods("In", 2);
obj_in.register_builtin_impl("__in__", fn1_met(Obj, Type, Bool), Const, Public);
obj.register_trait(Obj, builtin_poly("Eq", vec![ty_tp(Type)]), obj_in);
obj.register_trait(Obj, builtin_poly("In", vec![ty_tp(Type)]), obj_in);
let mut obj_mutizable = Self::builtin_methods("Mutizable", 1);
obj_mutizable.register_builtin_const("MutType!", ValueObj::builtin_t(builtin_mono("Obj!")));
obj.register_trait(Obj, builtin_mono("Mutizable"), obj_mutizable);
// Obj does not implement Eq
/* Float */
let mut float = Self::builtin_mono_class("Float", 2);
@ -760,6 +771,24 @@ impl Context {
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);
/* NoneType */
let mut nonetype = Self::builtin_mono_class("NoneType", 10);
nonetype.register_superclass(Obj, &obj);
let mut nonetype_eq = Self::builtin_methods("Eq", 2);
nonetype_eq.register_builtin_impl(
"__eq__",
fn1_met(NoneType, NoneType, Bool),
Const,
Public,
);
nonetype.register_trait(
NoneType,
builtin_poly("Eq", vec![ty_tp(NoneType)]),
nonetype_eq,
);
let mut nonetype_show = Self::builtin_methods("Show", 1);
nonetype_show.register_builtin_impl("to_str", fn0_met(NoneType, Str), Immutable, Public);
nonetype.register_trait(NoneType, builtin_mono("Show"), nonetype_show);
/* Type */
let mut type_ = Self::builtin_mono_class("Type", 2);
type_.register_superclass(Obj, &obj);
@ -783,6 +812,21 @@ impl Context {
builtin_poly("Eq", vec![ty_tp(ClassType)]),
class_eq,
);
let mut trait_type = Self::builtin_mono_class("TraitType", 2);
trait_type.register_superclass(Type, &type_);
trait_type.register_marker_trait(builtin_mono("Named"));
let mut trait_eq = Self::builtin_methods("Eq", 2);
trait_eq.register_builtin_impl(
"__eq__",
fn1_met(TraitType, TraitType, Bool),
Const,
Public,
);
trait_type.register_trait(
TraitType,
builtin_poly("Eq", vec![ty_tp(TraitType)]),
trait_eq,
);
let g_module_t = builtin_mono("GenericModule");
let mut generic_module = Self::builtin_mono_class("GenericModule", 2);
generic_module.register_superclass(Obj, &obj);
@ -849,7 +893,15 @@ impl Context {
Immutable,
Public,
);
array_.register_trait(array_t, builtin_mono("Show"), array_show);
array_.register_trait(array_t.clone(), builtin_mono("Show"), array_show);
let array_type_t = builtin_poly("ArrayType", vec![mono_q_tp("T"), mono_q_tp("N")]);
let mut array_type = Self::builtin_poly_class(
"ArrayType",
vec![PS::named_nd("T", Type), PS::named_nd("N", Nat)],
2,
);
array_type.register_superclass(array_t.clone(), &array_);
array_type.register_superclass(Type, &type_);
/* Set */
let mut set_ =
Self::builtin_poly_class("Set", vec![PS::t_nd("T"), PS::named_nd("N", Nat)], 10);
@ -892,6 +944,14 @@ impl Context {
let mut set_show = Self::builtin_methods("Show", 1);
set_show.register_builtin_impl("to_str", fn0_met(set_t.clone(), Str), Immutable, Public);
set_.register_trait(set_t.clone(), builtin_mono("Show"), set_show);
let set_type_t = builtin_poly("SetType", vec![mono_q_tp("T"), mono_q_tp("N")]);
let mut set_type = Self::builtin_poly_class(
"SetType",
vec![PS::named_nd("T", Type), PS::named_nd("N", Nat)],
2,
);
set_type.register_superclass(set_t.clone(), &set_);
set_type.register_superclass(Type, &type_);
/* Bytes */
let mut bytes = Self::builtin_mono_class("Bytes", 2);
bytes.register_superclass(Obj, &obj);
@ -1117,243 +1177,16 @@ impl Context {
),
tuple5_eq,
);
let mut tuple6 = Self::builtin_poly_class(
"Tuple6",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
],
2,
);
tuple6.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple6_eq = Self::builtin_methods("Eq", 2);
tuple6_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
Bool,
),
Const,
Public,
);
tuple6.register_trait(
builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple6",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
],
))],
),
tuple6_eq,
);
let mut tuple7 = Self::builtin_poly_class(
"Tuple7",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
PS::t_nd("G"),
],
2,
);
tuple7.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple7_eq = Self::builtin_methods("Eq", 2);
tuple7_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
Bool,
),
Const,
Public,
);
tuple7.register_trait(
builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple7",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
],
))],
),
tuple7_eq,
);
let mut tuple8 = Self::builtin_poly_class(
"Tuple8",
vec![
PS::t_nd("A"),
PS::t_nd("B"),
PS::t_nd("C"),
PS::t_nd("D"),
PS::t_nd("E"),
PS::t_nd("F"),
PS::t_nd("G"),
PS::t_nd("H"),
],
2,
);
tuple8.register_superclass(builtin_mono("Tuple"), &tuple_);
let mut tuple8_eq = Self::builtin_methods("Eq", 2);
tuple8_eq.register_builtin_impl(
"__eq__",
fn1_met(
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
Bool,
),
Const,
Public,
);
tuple8.register_trait(
builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
),
builtin_poly(
"Eq",
vec![ty_tp(builtin_poly(
"Tuple8",
vec![
ty_tp(mono_q("A")),
ty_tp(mono_q("B")),
ty_tp(mono_q("C")),
ty_tp(mono_q("D")),
ty_tp(mono_q("E")),
ty_tp(mono_q("F")),
ty_tp(mono_q("G")),
ty_tp(mono_q("H")),
],
))],
),
tuple8_eq,
);
/* record */
let mut record = Self::builtin_mono_class("Record", 2);
record.register_superclass(Obj, &obj);
let mut record_type = Self::builtin_mono_class("RecordType", 2);
record_type.register_superclass(builtin_mono("Record"), &record);
record_type.register_superclass(builtin_mono("Type"), &type_);
record_type.register_superclass(Type, &type_);
/* Or (true or type) */
let or_t = builtin_poly("Or", vec![ty_tp(mono_q("L")), ty_tp(mono_q("R"))]);
let mut or = Self::builtin_poly_class("Or", vec![PS::t_nd("L"), PS::t_nd("R")], 2);
or.register_superclass(Obj, &obj);
/* Float_mut */
let mut float_mut = Self::builtin_mono_class("Float!", 2);
float_mut.register_superclass(Float, &float);
@ -1378,15 +1211,7 @@ impl Context {
ratio_mut.register_superclass(Ratio, &ratio);
let mut ratio_mut_mutable = Self::builtin_methods("Mutable", 2);
ratio_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Ratio));
let f_t = kw(
"f",
func(
vec![kw("old", builtin_mono("Ratio"))],
None,
vec![],
builtin_mono("Ratio"),
),
);
let f_t = kw("f", func(vec![kw("old", Ratio)], None, vec![], Ratio));
let t = pr_met(
ref_mut(builtin_mono("Ratio!"), None),
vec![f_t],
@ -1462,7 +1287,7 @@ impl Context {
);
/* Str_mut */
let mut str_mut = Self::builtin_mono_class("Str!", 2);
str_mut.register_superclass(Str, &str_);
str_mut.register_superclass(Str, &nonetype);
let mut str_mut_mutable = Self::builtin_methods("Mutable", 2);
str_mut_mutable.register_builtin_const("ImmutType", ValueObj::builtin_t(Str));
let f_t = kw("f", func(vec![kw("old", Str)], None, vec![], Str));
@ -1500,7 +1325,6 @@ impl Context {
file_mut_readable,
);
/* Array_mut */
let array_t = builtin_poly("Array", vec![ty_tp(mono_q("T")), mono_q_tp("N")]);
let array_mut_t = builtin_poly("Array!", vec![ty_tp(mono_q("T")), mono_q_tp("N")]);
let mut array_mut_ = Self::builtin_poly_class(
"Array!",
@ -1617,7 +1441,8 @@ impl Context {
/* Range */
let range_t = builtin_poly("Range", vec![TyParam::t(mono_q("T"))]);
let mut range = Self::builtin_poly_class("Range", vec![PS::t_nd("T")], 2);
range.register_superclass(Obj, &obj);
// range.register_superclass(Obj, &obj);
range.register_superclass(Type, &type_);
range.register_marker_trait(builtin_poly("Output", vec![ty_tp(mono_q("T"))]));
let mut range_eq = Self::builtin_methods("Eq", 2);
range_eq.register_builtin_impl(
@ -1653,12 +1478,16 @@ impl Context {
self.register_builtin_type(Ratio, ratio, Const);
self.register_builtin_type(Bool, bool_, Const);
self.register_builtin_type(Str, str_, Const);
self.register_builtin_type(NoneType, nonetype, Const);
self.register_builtin_type(Type, type_, Const);
self.register_builtin_type(ClassType, class_type, Const);
self.register_builtin_type(TraitType, trait_type, Const);
self.register_builtin_type(g_module_t, generic_module, Const);
self.register_builtin_type(module_t, module, Const);
self.register_builtin_type(array_t, array_, Const);
self.register_builtin_type(array_type_t, array_type, Const);
self.register_builtin_type(set_t, set_, Const);
self.register_builtin_type(set_type_t, set_type, Const);
self.register_builtin_type(builtin_mono("Bytes"), bytes, Const);
self.register_builtin_type(tuple(vec![mono_q("A")]), tuple1, Const);
self.register_builtin_type(tuple(vec![mono_q("A"), mono_q("B")]), tuple2, Const);
@ -1683,47 +1512,9 @@ impl Context {
tuple5,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
]),
tuple6,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
mono_q("G"),
]),
tuple7,
Const,
);
self.register_builtin_type(
tuple(vec![
mono_q("A"),
mono_q("B"),
mono_q("C"),
mono_q("D"),
mono_q("E"),
mono_q("F"),
mono_q("G"),
mono_q("H"),
]),
tuple8,
Const,
);
self.register_builtin_type(builtin_mono("Record"), record, Const);
self.register_builtin_type(builtin_mono("RecordType"), record_type, Const);
self.register_builtin_type(or_t, or, Const);
self.register_builtin_type(builtin_mono("Int!"), int_mut, Const);
self.register_builtin_type(builtin_mono("Nat!"), nat_mut, Const);
self.register_builtin_type(builtin_mono("Float!"), float_mut, Const);
@ -1744,12 +1535,19 @@ impl Context {
fn init_builtin_funcs(&mut self) {
let t_abs = nd_func(vec![kw("n", builtin_mono("Num"))], None, Nat);
let t_ascii = nd_func(vec![kw("object", Obj)], None, Str);
let t_assert = func(
vec![kw("condition", Bool)],
None,
vec![kw("err_message", Str)],
NoneType,
);
let t_bin = nd_func(vec![kw("n", Int)], None, Str);
let t_chr = nd_func(
vec![kw("i", Type::from(value(0usize)..=value(1_114_111usize)))],
None,
Str,
);
let t_classof = nd_func(vec![kw("old", Obj)], None, ClassType);
let t_compile = nd_func(vec![kw("src", Str)], None, Code);
let t_cond = nd_func(
@ -1786,6 +1584,27 @@ impl Context {
module(mono_q_tp("Path")),
);
let t_import = quant(t_import, set! {static_instance("Path", Str)});
let t_isinstance = nd_func(
vec![
kw("object", Obj),
kw("classinfo", ClassType), // TODO: => ClassInfo
],
None,
Bool,
);
let t_issubclass = nd_func(
vec![
kw("subclass", ClassType),
kw("classinfo", ClassType), // TODO: => ClassInfo
],
None,
Bool,
);
let t_len = nd_func(
vec![kw("s", builtin_poly("Seq", vec![TyParam::erased(Type)]))],
None,
Nat,
);
let t_log = func(
vec![],
Some(kw("objects", ref_(Obj))),
@ -1797,31 +1616,57 @@ impl Context {
],
NoneType,
);
let t_oct = nd_func(vec![kw("x", Int)], None, Str);
let t_ord = nd_func(vec![kw("c", Str)], None, Nat);
let t_panic = nd_func(vec![kw("err_message", Str)], None, Never);
let m = mono_q("M");
// TODO: mod
let t_pow = nd_func(
vec![kw("base", m.clone()), kw("exp", m.clone())],
None,
m.clone(),
);
let t_pow = quant(
t_pow,
set! {static_instance("M", builtin_poly("Mul", vec![ty_tp(m)]))},
);
let t_pyimport = nd_func(
vec![anon(tp_enum(Str, set! {mono_q_tp("Path")}))],
None,
module(mono_q_tp("Path")),
);
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_quit = func(vec![], None, vec![kw("code", Int)], NoneType);
let t_exit = t_quit.clone();
let t_repr = nd_func(vec![kw("object", Obj)], None, Str);
let t_round = nd_func(vec![kw("number", Float)], None, Int);
self.register_builtin_impl("abs", t_abs, Immutable, Private);
self.register_builtin_impl("ascii", t_ascii, Immutable, Private);
self.register_builtin_impl("assert", t_assert, Const, Private); // assert casting に悪影響が出る可能性があるため、Constとしておく
self.register_builtin_impl("bin", t_bin, Immutable, Private);
self.register_builtin_impl("chr", t_chr, Immutable, Private);
self.register_builtin_impl("classof", t_classof, Immutable, Private);
self.register_builtin_impl("compile", t_compile, Immutable, Private);
self.register_builtin_impl("cond", t_cond, Immutable, Private);
self.register_builtin_impl("discard", t_discard, Immutable, Private);
self.register_builtin_impl("exit", t_exit, Immutable, Private);
self.register_builtin_impl("if", t_if, Immutable, Private);
self.register_builtin_impl("log", t_log, Immutable, Private);
self.register_builtin_impl("import", t_import, Immutable, Private);
self.register_builtin_impl("isinstance", t_isinstance, Immutable, Private);
self.register_builtin_impl("issubclass", t_issubclass, Immutable, Private);
self.register_builtin_impl("len", t_len, Immutable, Private);
self.register_builtin_impl("log", t_log, Immutable, Private);
self.register_builtin_impl("oct", t_oct, Immutable, Private);
self.register_builtin_impl("ord", t_ord, Immutable, Private);
self.register_builtin_impl("panic", t_panic, Immutable, Private);
self.register_builtin_impl("pow", t_pow, Immutable, Private);
if cfg!(feature = "debug") {
self.register_builtin_impl("py", t_pyimport.clone(), Immutable, Private);
}
self.register_builtin_impl("pyimport", t_pyimport, Immutable, Private);
self.register_builtin_impl("quit", t_quit, Immutable, Private);
self.register_builtin_impl("repr", t_repr, Immutable, Private);
self.register_builtin_impl("round", t_round, Immutable, Private);
}
fn init_builtin_const_funcs(&mut self) {
@ -2051,7 +1896,7 @@ impl Context {
self.register_builtin_decl("__rorng__", op_t.clone(), Private);
self.register_builtin_decl("__orng__", op_t, Private);
// TODO: use existential type: |T: Type| (T, In(T)) -> Bool
let op_t = bin_op(mono_q("T"), mono_q("I"), Bool);
let op_t = bin_op(mono_q("I"), mono_q("T"), Bool);
let op_t = quant(
op_t,
set! { static_instance("T", Type), subtypeof(mono_q("I"), builtin_poly("In", vec![ty_tp(mono_q("T"))])) },

View file

@ -17,7 +17,7 @@ use erg_parser::ast::{self, Identifier};
use erg_parser::token::Token;
use erg_type::constructors::{
anon, builtin_mono, free_var, func, module, mono_proj, subr_t, v_enum,
anon, builtin_mono, builtin_poly, free_var, func, module, mono_proj, subr_t, v_enum,
};
use erg_type::free::Constraint;
use erg_type::typaram::TyParam;
@ -87,6 +87,31 @@ impl Context {
})
}
pub(crate) fn get_mut_current_scope_var(&mut self, name: &str) -> Option<&mut VarInfo> {
self.locals
.get_mut(name)
.or_else(|| self.decls.get_mut(name))
.or_else(|| {
self.params
.iter_mut()
.find(|(opt_name, _)| {
opt_name
.as_ref()
.map(|n| &n.inspect()[..] == name)
.unwrap_or(false)
})
.map(|(_, vi)| vi)
})
.or_else(|| {
for (_, methods) in self.methods_list.iter_mut() {
if let Some(vi) = methods.get_mut_current_scope_var(name) {
return Some(vi);
}
}
None
})
}
pub(crate) fn get_local_kv(&self, name: &str) -> Option<(&VarName, &VarInfo)> {
self.locals.get_key_value(name)
}
@ -1160,8 +1185,19 @@ impl Context {
}
pub(crate) fn get_similar_name(&self, name: &str) -> Option<&str> {
match name {
"true" => return Some("True"),
"false" => return Some("False"),
"Null" | "Nil" | "null" | "nil" | "none" => return Some("None"),
"del" => return Some("Del"),
"int" => return Some("Int"),
"nat" => return Some("Nat"),
"str" => return Some("Str"),
"bool" => return Some("Bool"),
_ => {}
}
let name = readable_name(name);
// TODO: add decls
// REVIEW: add decls?
get_similar_name(
self.params
.iter()
@ -1298,35 +1334,6 @@ impl Context {
concatenated
}
pub(crate) fn _get_nominal_super_trait_ctxs<'a>(
&'a self,
t: &Type,
) -> Option<impl Iterator<Item = &'a Context>> {
let ctx = self.get_nominal_type_ctx(t)?;
Some(ctx.super_traits.iter().map(|sup| {
let sup_ctx = self
.get_nominal_type_ctx(sup)
.unwrap_or_else(|| todo!("{} not found", sup));
sup_ctx
}))
}
pub(crate) fn _get_nominal_super_class_ctxs<'a>(
&'a self,
t: &Type,
) -> Option<impl Iterator<Item = &'a Context>> {
// if `t` is {S: Str | ...}, `ctx_t` will be Str
// else if `t` is Array(Int, 10), `ctx_t` will be Array(T, N) (if Array(Int, 10) is not specialized)
let ctx = self.get_nominal_type_ctx(t)?;
// t: {S: Str | ...} => ctx.super_traits: [Eq(Str), Mul(Nat), ...]
// => return: [(Str, Eq(Str)), (Str, Mul(Nat)), ...] (the content of &'a Type isn't {S: Str | ...})
Some(
ctx.super_classes
.iter()
.map(|sup| self.get_nominal_type_ctx(sup).unwrap()),
)
}
pub(crate) fn get_nominal_super_type_ctxs<'a>(&'a self, t: &Type) -> Option<Vec<&'a Context>> {
match t {
Type::FreeVar(fv) if fv.is_linked() => self.get_nominal_super_type_ctxs(&fv.crack()),
@ -1364,6 +1371,7 @@ impl Context {
}
}
/// include `t` itself
fn get_simple_nominal_super_type_ctxs<'a>(
&'a self,
t: &Type,
@ -1377,6 +1385,19 @@ impl Context {
Some(vec![ctx].into_iter().chain(sups))
}
/// if `typ` is a refinement type, include the base type (refine.t)
pub(crate) fn get_super_classes(&self, typ: &Type) -> Option<impl Iterator<Item = Type>> {
self.get_nominal_type_ctx(typ).map(|ctx| {
let super_classes = ctx.super_classes.clone();
let derefined = typ.derefine();
if typ != &derefined {
vec![derefined].into_iter().chain(super_classes)
} else {
vec![].into_iter().chain(super_classes)
}
})
}
// TODO: Never
pub(crate) fn get_nominal_type_ctx<'a>(&'a self, typ: &Type) -> Option<&'a Context> {
match typ {
@ -1433,7 +1454,7 @@ impl Context {
}
Type::Poly { path, name, .. } => {
if self.path() == path {
if let Some((_, ctx)) = self.rec_get_mono_type(name) {
if let Some((_, ctx)) = self.rec_get_poly_type(name) {
return Some(ctx);
}
}
@ -1448,7 +1469,7 @@ impl Context {
.and_then(|cache| cache.ref_ctx(path.as_path()))
})
{
if let Some((_, ctx)) = ctx.rec_get_mono_type(name) {
if let Some((_, ctx)) = ctx.rec_get_poly_type(name) {
return Some(ctx);
}
}
@ -1495,16 +1516,10 @@ impl Context {
return Some(res);
}
}
Type::Or(l, r) => {
let lctx = self.get_nominal_type_ctx(l)?;
let rctx = self.get_nominal_type_ctx(r)?;
// use smaller context
return match (self.supertype_of(l, r), self.supertype_of(r, l)) {
(true, true) => Some(lctx),
(true, false) => Some(rctx),
(false, true) => Some(lctx),
(false, false) => None,
};
Type::Or(_l, _r) => {
if let Some(ctx) = self.get_nominal_type_ctx(&builtin_poly("Or", vec![])) {
return Some(ctx);
}
}
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
other if other.is_monomorphic() => {

View file

@ -26,7 +26,6 @@ use erg_type::{HasType, ParamTy, Predicate, SubrKind, TyBound, Type};
use TyParamOrdering::*;
use Type::*;
use crate::context::eval::eval_lit;
use crate::context::{Context, RegistrationMode};
use crate::error::{SingleTyCheckResult, TyCheckError, TyCheckErrors, TyCheckResult};
use crate::hir;
@ -577,7 +576,7 @@ impl Context {
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_ctx, mode)?
} else {
match &sig.pat {
ast::ParamPattern::Lit(lit) => v_enum(set![eval_lit(lit)]),
ast::ParamPattern::Lit(lit) => v_enum(set![self.eval_lit(lit)?]),
// TODO: Array<Lit>
_ => {
let level = if mode == PreRegister {
@ -613,7 +612,7 @@ impl Context {
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);
let default = self.instantiate_const_expr(default)?;
Ok(ParamTy::kw_default(
name.clone(),
t,
@ -665,7 +664,7 @@ impl Context {
if let Some(first) = args.next() {
let t = self.instantiate_const_expr_as_type(&first.expr)?;
let len = args.next().unwrap();
let len = self.instantiate_const_expr(&len.expr);
let len = self.instantiate_const_expr(&len.expr)?;
Ok(array(t, len))
} else {
Ok(builtin_mono("GenericArray"))
@ -707,23 +706,28 @@ impl Context {
}
other => {
// FIXME: kw args
let params = simple.args.pos_args().map(|arg| match &arg.expr {
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(lit)),
_ => {
todo!()
let mut new_params = vec![];
for arg in simple.args.pos_args() {
match &arg.expr {
ast::ConstExpr::Lit(lit) => {
new_params.push(TyParam::Value(self.eval_lit(lit)?));
}
_ => {
todo!()
}
}
});
}
// FIXME: non-builtin
Ok(builtin_poly(Str::rc(other), params.collect()))
Ok(builtin_poly(Str::rc(other), new_params))
}
}
}
pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyParam {
pub(crate) fn instantiate_const_expr(&self, expr: &ast::ConstExpr) -> TyCheckResult<TyParam> {
match expr {
ast::ConstExpr::Lit(lit) => TyParam::Value(eval_lit(lit)),
ast::ConstExpr::Lit(lit) => Ok(TyParam::Value(self.eval_lit(lit)?)),
ast::ConstExpr::Accessor(ast::ConstAccessor::Local(name)) => {
TyParam::Mono(name.inspect().clone())
Ok(TyParam::Mono(name.inspect().clone()))
}
_ => todo!(),
}
@ -780,13 +784,13 @@ impl Context {
)),
TypeSpec::Array(arr) => {
let elem_t = self.instantiate_typespec(&arr.ty, opt_decl_t, tmp_tv_ctx, mode)?;
let len = self.instantiate_const_expr(&arr.len);
Ok(array(elem_t, len))
let len = self.instantiate_const_expr(&arr.len)?;
Ok(builtin_poly("ArrayType", vec![ty_tp(elem_t), len]))
}
TypeSpec::Set(set) => {
let elem_t = self.instantiate_typespec(&set.ty, opt_decl_t, tmp_tv_ctx, mode)?;
let len = self.instantiate_const_expr(&set.len);
Ok(erg_type::constructors::set(elem_t, len))
let len = self.instantiate_const_expr(&set.len)?;
Ok(builtin_poly("SetType", vec![ty_tp(elem_t), len]))
}
// FIXME: unwrap
TypeSpec::Tuple(tys) => Ok(tuple(
@ -797,18 +801,18 @@ impl Context {
})
.collect(),
)),
// TODO: エラー処理(リテラルでない、ダブりがある)はパーサーにやらせる
TypeSpec::Enum(set) => Ok(v_enum(
set.pos_args()
.map(|arg| {
if let ast::ConstExpr::Lit(lit) = &arg.expr {
eval_lit(lit)
} else {
todo!()
}
})
.collect::<Set<_>>(),
)),
// TODO: エラー処理(リテラルでない)はパーサーにやらせる
TypeSpec::Enum(set) => {
let mut new_set = set! {};
for arg in set.pos_args() {
if let ast::ConstExpr::Lit(lit) = &arg.expr {
new_set.insert(self.eval_lit(lit)?);
} else {
todo!()
}
}
Ok(v_enum(new_set))
}
TypeSpec::Interval { op, lhs, rhs } => {
let op = match op.kind {
TokenKind::Closed => IntervalOp::Closed,
@ -817,9 +821,9 @@ impl Context {
TokenKind::Open => IntervalOp::Open,
_ => assume_unreachable!(),
};
let l = self.instantiate_const_expr(lhs);
let l = self.instantiate_const_expr(lhs)?;
let l = self.eval_tp(&l)?;
let r = self.instantiate_const_expr(rhs);
let r = self.instantiate_const_expr(rhs)?;
let r = self.eval_tp(&r)?;
if let Some(Greater) = self.try_cmp(&l, &r) {
panic!("{l}..{r} is not a valid interval type (should be lhs <= rhs)")

View file

@ -281,6 +281,7 @@ pub enum OperationKind {
Import,
PyImport,
Del,
AssertCast,
}
impl OperationKind {

View file

@ -14,8 +14,9 @@ use ast::{DefId, Identifier, VarName};
use erg_parser::ast;
use erg_type::constructors::{func, func1, proc, ref_, ref_mut, v_enum};
use erg_type::free::{Constraint, Cyclicity, FreeKind};
use erg_type::value::{GenTypeObj, TypeKind, TypeObj, ValueObj};
use erg_type::{ParamTy, SubrType, Type};
use erg_type::{HasType, ParamTy, SubrType, Type};
use crate::build_hir::HIRBuilder;
use crate::context::{
@ -1076,4 +1077,75 @@ impl Context {
)))
}
}
pub(crate) fn cast(
&mut self,
type_spec: ast::TypeSpec,
call: &mut hir::Call,
) -> TyCheckResult<()> {
let cast_to =
self.instantiate_typespec(&type_spec, None, None, RegistrationMode::Normal)?;
let lhs = enum_unwrap!(
call.args.get_mut_left_or_key("pred").unwrap(),
hir::Expr::BinOp
)
.lhs
.as_mut();
match (
self.supertype_of(lhs.ref_t(), &cast_to),
self.subtype_of(lhs.ref_t(), &cast_to),
) {
// assert 1 in {1}
(true, true) => Ok(()),
// assert x in Int (x: Nat)
(false, true) => Ok(()), // TODO: warn (needless)
// assert x in Nat (x: Int)
(true, false) => {
if let hir::Expr::Accessor(ref acc) = lhs {
self.change_var_type(acc, cast_to.clone())?;
}
match lhs.ref_t() {
Type::FreeVar(fv) if fv.is_linked() => {
let constraint = Constraint::new_subtype_of(cast_to, Cyclicity::Not);
fv.replace(FreeKind::new_unbound(self.level, constraint));
}
Type::FreeVar(fv) => {
let new_constraint = Constraint::new_subtype_of(cast_to, Cyclicity::Not);
fv.update_constraint(new_constraint);
}
_ => {
*lhs.ref_mut_t() = cast_to;
}
}
Ok(())
}
// assert x in Str (x: Int)
(false, false) => Err(TyCheckErrors::from(TyCheckError::invalid_type_cast_error(
self.cfg.input.clone(),
line!() as usize,
lhs.loc(),
self.caused_by(),
&lhs.to_string(),
&cast_to,
None,
))),
}
}
fn change_var_type(&mut self, acc: &hir::Accessor, t: Type) -> TyCheckResult<()> {
#[allow(clippy::single_match)]
match acc {
hir::Accessor::Ident(ident) => {
if let Some(vi) = self.get_mut_current_scope_var(ident.inspect()) {
vi.t = t;
} else {
todo!()
}
}
_ => {
// TODO: support other accessors
}
}
Ok(())
}
}

View file

@ -671,6 +671,13 @@ impl Context {
}
Ok(())
}
hir::Array::WithLength(arr) => {
let loc = arr.loc();
arr.t = self.deref_tyvar(mem::take(&mut arr.t), Covariant, loc)?;
self.resolve_expr_t(&mut arr.elem)?;
self.resolve_expr_t(&mut arr.len)?;
Ok(())
}
_ => todo!(),
},
hir::Expr::Tuple(tuple) => match tuple {
@ -683,12 +690,20 @@ impl Context {
},
hir::Expr::Set(set) => match set {
hir::Set::Normal(st) => {
let loc = st.loc();
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, loc)?;
for elem in st.elems.pos_args.iter_mut() {
self.resolve_expr_t(&mut elem.expr)?;
}
Ok(())
}
hir::Set::WithLength(_) => todo!(),
hir::Set::WithLength(st) => {
let loc = st.loc();
st.t = self.deref_tyvar(mem::take(&mut st.t), Covariant, loc)?;
self.resolve_expr_t(&mut st.elem)?;
self.resolve_expr_t(&mut st.len)?;
Ok(())
}
},
hir::Expr::Dict(_dict) => {
todo!()

View file

@ -990,6 +990,30 @@ impl EvalError {
caused_by,
)
}
pub fn invalid_literal(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
) -> Self {
Self::new(
ErrorCore::new(
errno,
SyntaxError,
loc,
switch_lang!(
"japanese" => "リテラルが不正です",
"simplified_chinese" => "字面量不合法",
"traditional_chinese" => "字面量不合法",
"english" => "invalid literal",
),
None,
),
input,
caused_by,
)
}
}
pub type EffectError = TyCheckError;
@ -1568,6 +1592,34 @@ impl LowerError {
caused_by,
)
}
#[allow(clippy::too_many_arguments)]
pub fn invalid_type_cast_error(
input: Input,
errno: usize,
loc: Location,
caused_by: AtomicStr,
name: &str,
cast_to: &Type,
hint: Option<AtomicStr>,
) -> Self {
Self::new(
ErrorCore::new(
errno,
TypeError,
loc,
switch_lang!(
"japanese" => format!("{YELLOW}{name}{RESET}の型を{RED}{cast_to}{RESET}にキャストすることはできません"),
"simplified_chinese" => format!("{YELLOW}{name}{RESET}的类型无法转换为{RED}{cast_to}{RESET}"),
"traditional_chinese" => format!("{YELLOW}{name}{RESET}的類型無法轉換為{RED}{cast_to}{RESET}"),
"english" => format!("the type of {YELLOW}{name}{RESET} cannot be cast to {RED}{cast_to}{RESET}"),
),
hint,
),
input,
caused_by,
)
}
}
#[derive(Debug)]

View file

@ -47,14 +47,16 @@ impl Locational for Literal {
}
}
impl From<Token> for Literal {
fn from(token: Token) -> Self {
let data = ValueObj::from_str(type_from_token_kind(token.kind), token.content.clone());
Self {
impl TryFrom<Token> for Literal {
type Error = ();
fn try_from(token: Token) -> Result<Self, ()> {
let data =
ValueObj::from_str(type_from_token_kind(token.kind), token.content.clone()).ok_or(())?;
Ok(Self {
t: data.t(),
value: data,
token,
}
})
}
}
@ -282,6 +284,20 @@ impl Args {
}
}
pub fn get_mut_left_or_key(&mut self, key: &str) -> Option<&mut Expr> {
if !self.pos_args.is_empty() {
Some(&mut self.pos_args.get_mut(0)?.expr)
} else if let Some(pos) = self
.kw_args
.iter()
.position(|arg| &arg.keyword.inspect()[..] == key)
{
Some(&mut self.kw_args.get_mut(pos)?.expr)
} else {
None
}
}
pub fn insert_pos(&mut self, idx: usize, pos: PosArg) {
self.pos_args.insert(idx, pos);
}
@ -351,8 +367,8 @@ impl Identifier {
)
}
pub fn private(name: Str) -> Self {
Self::bare(None, VarName::from_str(name))
pub fn private(name: &'static str) -> Self {
Self::bare(None, VarName::from_static(name))
}
pub fn private_with_line(name: Str, line: usize) -> Self {

View file

@ -59,6 +59,10 @@ impl<'a> Linker<'a> {
self.replace_import(&mut elem.expr);
}
}
Array::WithLength(arr) => {
self.replace_import(&mut arr.elem);
self.replace_import(&mut arr.len);
}
_ => todo!(),
},
Expr::Tuple(tuple) => match tuple {
@ -74,9 +78,11 @@ impl<'a> Linker<'a> {
self.replace_import(&mut elem.expr);
}
}
Set::WithLength(_) => todo!(),
Set::WithLength(st) => {
self.replace_import(&mut st.elem);
self.replace_import(&mut st.len);
}
},
Expr::Dict(_dict) => {
todo!()
}
@ -241,7 +247,7 @@ impl<'a> Linker<'a> {
mod_name_lit.ln_begin().unwrap(),
mod_name_lit.col_begin().unwrap(),
);
let mod_name = Expr::Lit(Literal::from(token));
let mod_name = Expr::Lit(Literal::try_from(token).unwrap());
args.insert_pos(0, PosArg::new(mod_name));
let line = expr.ln_begin().unwrap_or(0);
for attr in comps {

View file

@ -15,6 +15,7 @@ use erg_parser::ast;
use erg_parser::ast::AST;
use erg_parser::build_ast::ASTBuilder;
use erg_parser::token::{Token, TokenKind};
use erg_parser::Parser;
use erg_type::constructors::{
array, array_mut, builtin_mono, builtin_poly, free_var, func, mono, proc, quant, set, set_mut,
@ -182,6 +183,19 @@ impl ASTLowerer {
}
}
fn lower_literal(&self, lit: ast::Literal) -> LowerResult<hir::Literal> {
let loc = lit.loc();
let lit = hir::Literal::try_from(lit.token).map_err(|_| {
LowerError::invalid_literal(
self.cfg.input.clone(),
line!() as usize,
loc,
self.ctx.caused_by(),
)
})?;
Ok(lit)
}
fn lower_array(&mut self, array: ast::Array) -> LowerResult<hir::Array> {
log!(info "entered {}({array})", fn_name!());
match array {
@ -260,6 +274,8 @@ impl ASTLowerer {
"ArrayWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
} else if self.ctx.subtype_of(&elem.t(), &Type::Type) {
builtin_poly("ArrayType", vec![TyParam::t(elem.t()), TyParam::Value(v)])
} else {
array(elem.t(), TyParam::Value(v))
}
@ -429,6 +445,8 @@ impl ASTLowerer {
"SetWithMutType!",
vec![TyParam::t(elem.t()), TyParam::Value(v)],
)
} else if self.ctx.subtype_of(&elem.t(), &Type::Type) {
builtin_poly("SetType", vec![TyParam::t(elem.t()), TyParam::Value(v)])
} else {
set(elem.t(), TyParam::Value(v))
}
@ -489,7 +507,7 @@ impl ASTLowerer {
}
ast::Accessor::TupleAttr(t_attr) => {
let obj = self.lower_expr(*t_attr.obj)?;
let index = hir::Literal::from(t_attr.index.token);
let index = self.lower_literal(t_attr.index)?;
let n = enum_unwrap!(index.value, ValueObj::Nat);
let t = enum_unwrap!(
obj.ref_t().typarams().get(n as usize).unwrap().clone(),
@ -562,9 +580,27 @@ impl ASTLowerer {
Ok(hir::UnaryOp::new(unary.op, expr, t))
}
// TODO: single `import`
fn lower_call(&mut self, call: ast::Call) -> LowerResult<hir::Call> {
log!(info "entered {}({}{}(...))", fn_name!(), call.obj, fmt_option!(call.method_name));
let opt_cast_to = if call.is_assert_cast() {
if let Some(typ) = call.assert_cast_target_type() {
Some(Parser::expr_to_type_spec(typ.clone()).map_err(|e| {
let e = LowerError::new(e.into(), self.input().clone(), self.ctx.caused_by());
LowerErrors::from(e)
})?)
} else {
return Err(LowerErrors::from(LowerError::syntax_error(
self.input().clone(),
line!() as usize,
call.args.loc(),
self.ctx.caused_by(),
"invalid assert casting type",
None,
)));
}
} else {
None
};
let (pos_args, kw_args, paren) = call.args.deconstruct();
let mut hir_args = hir::Args::new(
Vec::with_capacity(pos_args.len()),
@ -597,7 +633,7 @@ impl ASTLowerer {
} else {
None
};
let call = hir::Call::new(obj, method_name, hir_args, sig_t);
let mut call = hir::Call::new(obj, method_name, hir_args, sig_t);
match call.additional_operation() {
Some(kind @ (OperationKind::Import | OperationKind::PyImport)) => {
let mod_name =
@ -621,7 +657,12 @@ impl ASTLowerer {
)))
}
},
_ => {}
_ => {
if let Some(type_spec) = opt_cast_to {
log!(err "cast({type_spec}): {call}");
self.ctx.cast(type_spec, &mut call)?;
}
}
}
Ok(call)
}
@ -1241,7 +1282,7 @@ impl ASTLowerer {
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
log!(info "entered {}", fn_name!());
match expr {
ast::Expr::Lit(lit) => Ok(hir::Expr::Lit(hir::Literal::from(lit.token))),
ast::Expr::Lit(lit) => Ok(hir::Expr::Lit(self.lower_literal(lit)?)),
ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.lower_array(arr)?)),
ast::Expr::Tuple(tup) => Ok(hir::Expr::Tuple(self.lower_tuple(tup)?)),
ast::Expr::Record(rec) => Ok(hir::Expr::Record(self.lower_record(rec)?)),

View file

@ -156,6 +156,10 @@ impl OwnershipChecker {
self.check_expr(&a.expr, ownership, false);
}
}
Array::WithLength(arr) => {
self.check_expr(&arr.elem, ownership, false);
self.check_expr(&arr.len, ownership, false);
}
_ => todo!(),
},
Expr::Tuple(tuple) => match tuple {
@ -182,12 +186,15 @@ impl OwnershipChecker {
}
}
Expr::Set(set) => match set {
hir::Set::Normal(set) => {
for a in set.elems.pos_args.iter() {
hir::Set::Normal(st) => {
for a in st.elems.pos_args.iter() {
self.check_expr(&a.expr, ownership, false);
}
}
hir::Set::WithLength(_) => todo!(),
hir::Set::WithLength(st) => {
self.check_expr(&st.elem, ownership, false);
self.check_expr(&st.len, ownership, false);
}
},
// TODO: capturing
Expr::Lambda(lambda) => {

View file

@ -0,0 +1,107 @@
from collections.abc import Iterable, Sequence, Iterator, Container
def in_operator(x, y):
if type(y) == type:
if isinstance(x, y):
return True
# TODO: trait check
return False
elif (type(y) == list or type(y) == set) and type(y[0]) == type:
# FIXME:
type_check = in_operator(x[0], y[0])
len_check = len(x) == len(y)
return type_check and len_check
elif type(y) == dict and type(y[0]) == type:
NotImplemented
else:
return x in y
class Range:
def __init__(self, start, end):
self.start = start
self.end = end
def __contains__(self, item):
pass
def __getitem__(self, item):
pass
def __len__(self):
pass
def __iter__(self):
return RangeIterator(rng=self)
Sequence.register(Range)
Container.register(Range)
Iterable.register(Range)
# represents `start<..end`
class LeftOpenRange(Range):
def __contains__(self, item):
return self.start < item <= self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start..<end`
class RightOpenRange(Range):
def __contains__(self, item):
return self.start <= item < self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start<..<end`
class OpenRange(Range):
def __contains__(self, item):
return self.start < item < self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
# represents `start..end`
class ClosedRange(Range):
def __contains__(self, item):
return self.start <= item <= self.end
def __getitem__(self, item):
return NotImplemented
def __len__(self):
return NotImplemented
class RangeIterator:
def __init__(self, rng):
self.rng = rng
self.needle = self.rng.start
if type(self.rng.start) == int:
if not(self.needle in self.rng):
self.needle += 1
elif type(self.rng.start) == str:
if not(self.needle in self.rng):
self.needle = chr(ord(self.needle) + 1)
else:
if not(self.needle in self.rng):
self.needle = self.needle.incremented()
def __iter__(self):
return self
def __next__(self):
if type(self.rng.start) == int:
if self.needle in self.rng:
result = self.needle
self.needle += 1
return result
elif type(self.rng.start) == str:
if self.needle in self.rng:
result = self.needle
self.needle = chr(ord(self.needle) + 1)
return result
else:
if self.needle in self.rng:
result = self.needle
self.needle = self.needle.incremented()
return result
raise StopIteration
Iterator.register(RangeIterator)

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

@ -0,0 +1,13 @@
discard _x = None
discard 1
# if: |T, U|(Bool, T, U) -> T or U
cond|T: Type|(c: Bool, then: T, else: T): T =
if c:
do then
do else
assert cond(False, 1, 2) == 2
# assert cond(True, 1, 3) == "a"
# assert "a" == cond(True, 1, 3)