WIP: impl Trait

This commit is contained in:
Shunsuke Shibayama 2022-09-17 01:42:49 +09:00
parent 346d00fcd8
commit aa527dcbc8
11 changed files with 227 additions and 51 deletions

View file

@ -16,10 +16,12 @@ use erg_parser::token::{Token, TokenKind};
use erg_type::constructors::{enum_t, mono, mono_proj, poly, ref_, ref_mut, refinement, subr_t};
use erg_type::typaram::{OpKind, TyParam};
use erg_type::value::ValueObj;
use erg_type::{ConstSubr, HasType, Predicate, TyBound, Type, UserConstSubr, ValueArgs};
use erg_type::{
ConstSubr, HasType, ParamTy, Predicate, SubrKind, TyBound, Type, UserConstSubr, ValueArgs,
};
use crate::context::instantiate::TyVarContext;
use crate::context::{ClassDefType, Context};
use crate::context::{ClassDefType, Context, RegistrationMode};
use crate::error::{EvalError, EvalResult, TyCheckResult};
#[inline]
@ -343,7 +345,7 @@ impl Context {
fn eval_const_normal_record(&self, record: &NormalRecord) -> EvalResult<ValueObj> {
let mut attrs = vec![];
// HACK: should avoid cloning
let mut record_ctx = Context::instant(Str::ever("<unnamed record>"), 2, self.clone());
let mut record_ctx = Context::instant(Str::ever("<unnamed record>"), 0, self.clone());
for attr in record.attrs.iter() {
let name = attr.sig.ident().map(|i| i.inspect());
let elem = record_ctx.eval_const_block(&attr.body.block, name)?;
@ -360,11 +362,63 @@ impl Context {
}
fn eval_const_lambda(&self, lambda: &Lambda) -> EvalResult<ValueObj> {
let mut non_default_params = Vec::with_capacity(lambda.sig.params.non_defaults.len());
for sig in lambda.sig.params.non_defaults.iter() {
let t = self.instantiate_param_sig_t(sig, None, RegistrationMode::Normal)?;
let pt = if let Some(name) = sig.inspect() {
ParamTy::kw(name.clone(), t)
} else {
ParamTy::anonymous(t)
};
non_default_params.push(pt);
}
let var_params = if let Some(p) = lambda.sig.params.var_args.as_ref() {
let t = self.instantiate_param_sig_t(p, None, RegistrationMode::Normal)?;
let pt = if let Some(name) = p.inspect() {
ParamTy::kw(name.clone(), t)
} else {
ParamTy::anonymous(t)
};
Some(pt)
} else {
None
};
let mut default_params = Vec::with_capacity(lambda.sig.params.defaults.len());
for sig in lambda.sig.params.defaults.iter() {
let t = self.instantiate_param_sig_t(sig, None, RegistrationMode::Normal)?;
let pt = if let Some(name) = sig.inspect() {
ParamTy::kw(name.clone(), t)
} else {
ParamTy::anonymous(t)
};
default_params.push(pt);
}
// HACK: should avoid cloning
let mut lambda_ctx = Context::instant(Str::ever("<lambda>"), 0, self.clone());
let return_t = lambda_ctx.eval_const_block(&lambda.body, None)?;
// FIXME: lambda: i: Int -> Int
// => sig_t: (i: Type) -> Type
// => as_type: (i: Int) -> Int
let sig_t = subr_t(
SubrKind::from(lambda.op.kind),
non_default_params.clone(),
var_params.clone(),
default_params.clone(),
enum_t(set![return_t.clone()]),
);
let as_type = subr_t(
SubrKind::from(lambda.op.kind),
non_default_params,
var_params,
default_params,
return_t.as_type().ok_or_else(|| todo!())?.into_typ(),
);
let subr = ConstSubr::User(UserConstSubr::new(
Str::ever("<lambda>"),
lambda.sig.params.clone(),
lambda.body.clone(),
Type::Uninited,
sig_t,
Some(as_type),
));
Ok(ValueObj::Subr(subr))
}

View file

@ -7,24 +7,8 @@ use erg_common::color::{RED, RESET};
use erg_common::error::{ErrorCore, ErrorKind, Location};
use erg_type::constructors::{and, mono};
use erg_type::value::{EvalValueResult, TypeKind, TypeObj, ValueObj};
use erg_type::Type;
use erg_type::ValueArgs;
fn value_obj_to_t(value: ValueObj) -> TypeObj {
match value {
ValueObj::Type(t) => t,
ValueObj::Record(rec) => TypeObj::Builtin(Type::Record(
rec.into_iter()
.map(|(k, v)| (k, value_obj_to_t(v).typ().clone()))
.collect(),
)),
ValueObj::Subr(subr) => {
todo!("{subr}")
}
other => todo!("{other}"),
}
}
/// Requirement: Type, Impl := Type -> ClassType
pub fn class_func(mut args: ValueArgs, __name__: Option<Str>) -> EvalValueResult<ValueObj> {
let require = args.remove_left_or_key("Requirement").ok_or_else(|| {
@ -36,9 +20,9 @@ pub fn class_func(mut args: ValueArgs, __name__: Option<Str>) -> EvalValueResult
None,
)
})?;
let require = value_obj_to_t(require);
let require = require.as_type().unwrap();
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(value_obj_to_t);
let impls = impls.map(|v| v.as_type().unwrap());
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
Ok(ValueObj::gen_t(TypeKind::Class, t, require, impls, None))
}
@ -54,11 +38,11 @@ pub fn inherit_func(mut args: ValueArgs, __name__: Option<Str>) -> EvalValueResu
None,
)
})?;
let sup = value_obj_to_t(sup);
let sup = sup.as_type().unwrap();
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(value_obj_to_t);
let impls = impls.map(|v| v.as_type().unwrap());
let additional = args.remove_left_or_key("Additional");
let additional = additional.map(value_obj_to_t);
let additional = additional.map(|v| v.as_type().unwrap());
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
Ok(ValueObj::gen_t(
TypeKind::Subclass,
@ -112,9 +96,9 @@ pub fn trait_func(mut args: ValueArgs, __name__: Option<Str>) -> EvalValueResult
None,
)
})?;
let require = value_obj_to_t(require);
let require = require.as_type().unwrap();
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(value_obj_to_t);
let impls = impls.map(|v| v.as_type().unwrap());
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
Ok(ValueObj::gen_t(TypeKind::Trait, t, require, impls, None))
}
@ -130,11 +114,11 @@ pub fn subsume_func(mut args: ValueArgs, __name__: Option<Str>) -> EvalValueResu
None,
)
})?;
let sup = value_obj_to_t(sup);
let sup = sup.as_type().unwrap();
let impls = args.remove_left_or_key("Impl");
let impls = impls.map(value_obj_to_t);
let impls = impls.map(|v| v.as_type().unwrap());
let additional = args.remove_left_or_key("Additional");
let additional = additional.map(value_obj_to_t);
let additional = additional.map(|v| v.as_type().unwrap());
let t = mono(__name__.unwrap_or(Str::ever("<Lambda>")));
Ok(ValueObj::gen_t(
TypeKind::Subtrait,

View file

@ -1486,7 +1486,7 @@ impl Context {
vec![param_t("Impl", Type)],
Class,
);
let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t));
let class = ConstSubr::Builtin(BuiltinConstSubr::new("Class", class_func, class_t, None));
self.register_builtin_const("Class", ValueObj::Subr(class));
let inherit_t = func(
vec![param_t("Super", Class)],
@ -1494,7 +1494,12 @@ impl Context {
vec![param_t("Impl", Type), param_t("Additional", Type)],
Class,
);
let inherit = ConstSubr::Builtin(BuiltinConstSubr::new("Inherit", inherit_func, inherit_t));
let inherit = ConstSubr::Builtin(BuiltinConstSubr::new(
"Inherit",
inherit_func,
inherit_t,
None,
));
self.register_builtin_const("Inherit", ValueObj::Subr(inherit));
let trait_t = func(
vec![param_t("Requirement", Type)],
@ -1502,7 +1507,7 @@ impl Context {
vec![param_t("Impl", Type)],
Trait,
);
let trait_ = ConstSubr::Builtin(BuiltinConstSubr::new("Trait", trait_func, trait_t));
let trait_ = ConstSubr::Builtin(BuiltinConstSubr::new("Trait", trait_func, trait_t, None));
self.register_builtin_const("Trait", ValueObj::Subr(trait_));
let subsume_t = func(
vec![param_t("Super", Trait)],
@ -1510,7 +1515,12 @@ impl Context {
vec![param_t("Impl", Type), param_t("Additional", Type)],
Trait,
);
let subsume = ConstSubr::Builtin(BuiltinConstSubr::new("Subsume", subsume_func, subsume_t));
let subsume = ConstSubr::Builtin(BuiltinConstSubr::new(
"Subsume",
subsume_func,
subsume_t,
None,
));
self.register_builtin_const("Subsume", ValueObj::Subr(subsume));
// decorators
let inheritable_t = func1(Class, Class);
@ -1518,6 +1528,7 @@ impl Context {
"Inheritable",
inheritable_func,
inheritable_t,
None,
));
self.register_builtin_const("Inheritable", ValueObj::Subr(inheritable));
}

View file

@ -1259,6 +1259,7 @@ impl Context {
}
}
/// FIXME: if trait, returns a freevar
pub(crate) fn rec_get_self_t(&self) -> Option<Type> {
if self.kind.is_method_def() || self.kind.is_type() {
// TODO: poly type

View file

@ -628,11 +628,7 @@ impl Context {
.collect();
let return_t = self.instantiate_typespec(&subr.return_t, mode)?;
Ok(subr_t(
if subr.arrow.is(TokenKind::FuncArrow) {
SubrKind::Func
} else {
SubrKind::Proc
},
SubrKind::from(subr.arrow.kind),
non_defaults,
var_args,
defaults,

View file

@ -649,6 +649,28 @@ impl Context {
todo!()
}
}
TypeKind::Trait => {
if gen.t.is_monomorphic() {
let ctx = Self::mono_trait(gen.t.name(), self.level);
self.register_gen_mono_type(ident, gen, ctx, Const);
} else {
todo!()
}
}
TypeKind::Subtrait => {
if gen.t.is_monomorphic() {
let super_classes = vec![gen.require_or_sup.typ().clone()];
// let super_traits = gen.impls.iter().map(|to| to.typ().clone()).collect();
let mut ctx = Self::mono_trait(gen.t.name(), self.level);
for sup in super_classes.into_iter() {
let (_, sup_ctx) = self.get_nominal_type_ctx(&sup).unwrap();
ctx.register_superclass(sup, sup_ctx);
}
self.register_gen_mono_type(ident, gen, ctx, Const);
} else {
todo!()
}
}
other => todo!("{other:?}"),
}
}

View file

@ -1027,6 +1027,9 @@ impl Context {
(Type::MonoProj { .. }, _) => todo!(),
(_, Type::MonoProj { .. }) => todo!(),
(Refinement(_), Refinement(_)) => todo!(),
(Type::Subr(_) | Type::Record(_), Type) => Ok(()),
// TODO Tuple2, ...
(Type::Poly{ name, .. }, Type) if &name[..] == "Array" || &name[..] == "Tuple" => Ok(()),
_ => todo!("{maybe_sub} can be a subtype of {maybe_sup}, but failed to semi-unify (or existential types are not supported)"),
}
}

View file

@ -562,7 +562,14 @@ impl ASTLowerer {
name,
));
}
self.ctx.grow(name, ContextKind::Instant, def.sig.vis())?;
let kind = if def.is_class_def() {
ContextKind::Class
} else if def.is_trait_def() {
ContextKind::Trait
} else {
ContextKind::Instant
};
self.ctx.grow(name, kind, def.sig.vis())?;
let res = match def.sig {
ast::Signature::Subr(sig) => self.lower_subr_def(sig, def.body),
ast::Signature::Var(sig) => self.lower_var_def(sig, def.body),

View file

@ -225,6 +225,20 @@ impl Args {
pub fn push_kw(&mut self, arg: KwArg) {
self.kw_args.push(arg);
}
pub fn get_left_or_key(&self, key: &str) -> Option<&Expr> {
if !self.pos_args.is_empty() {
self.pos_args.get(0).map(|a| &a.expr)
} else {
self.kw_args.iter().find_map(|a| {
if &a.keyword.content[..] == key {
Some(&a.expr)
} else {
None
}
})
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@ -2862,6 +2876,34 @@ impl Def {
pub const fn is_subr(&self) -> bool {
matches!(&self.sig, Signature::Subr(_))
}
pub fn is_class_def(&self) -> bool {
match self.body.block.first().unwrap() {
Expr::Call(call)
if call.obj.get_name().map(|n| &n[..]) == Some("Class")
|| call.obj.get_name().map(|n| &n[..]) == Some("Inherit") =>
{
true
}
Expr::Call(call) if call.obj.get_name().map(|n| &n[..]) == Some("Inheritable") => {
if let Some(Expr::Call(inner)) = call.args.get_left_or_key("Class") {
inner.obj.get_name().map(|n| &n[..]) == Some("Class")
|| inner.obj.get_name().map(|n| &n[..]) == Some("Inherit")
} else {
false
}
}
_ => false,
}
}
pub fn is_trait_def(&self) -> bool {
matches!(
self.body.block.first().unwrap(),
Expr::Call(call) if call.obj.get_name().map(|n| &n[..]) == Some("Trait")
|| call.obj.get_name().map(|n| &n[..]) == Some("Subsume")
)
}
}
/// e.g.

View file

@ -20,6 +20,7 @@ use erg_common::vis::Field;
use erg_common::{enum_unwrap, fmt_option, fmt_set_split_with, set, Str};
use erg_parser::ast::{Block, Params};
use erg_parser::token::TokenKind;
use crate::constructors::{int_interval, mono, mono_q};
use crate::free::{
@ -135,16 +136,24 @@ pub struct UserConstSubr {
name: Str,
params: Params,
block: Block,
t: Type,
sig_t: Type,
as_type: Option<Type>,
}
impl UserConstSubr {
pub const fn new(name: Str, params: Params, block: Block, t: Type) -> Self {
pub const fn new(
name: Str,
params: Params,
block: Block,
sig_t: Type,
as_type: Option<Type>,
) -> Self {
Self {
name,
params,
block,
t,
sig_t,
as_type,
}
}
}
@ -173,7 +182,8 @@ impl ValueArgs {
pub struct BuiltinConstSubr {
name: &'static str,
subr: fn(ValueArgs, Option<Str>) -> EvalValueResult<ValueObj>,
t: Type,
sig_t: Type,
as_type: Option<Type>,
}
impl fmt::Display for BuiltinConstSubr {
@ -186,9 +196,15 @@ impl BuiltinConstSubr {
pub const fn new(
name: &'static str,
subr: fn(ValueArgs, Option<Str>) -> EvalValueResult<ValueObj>,
t: Type,
sig_t: Type,
as_type: Option<Type>,
) -> Self {
Self { name, subr, t }
Self {
name,
subr,
sig_t,
as_type,
}
}
pub fn call(&self, args: ValueArgs, __name__: Option<Str>) -> EvalValueResult<ValueObj> {
@ -214,10 +230,17 @@ impl fmt::Display for ConstSubr {
}
impl ConstSubr {
pub fn class(&self) -> Type {
pub fn sig_t(&self) -> &Type {
match self {
ConstSubr::User(user) => user.t.clone(),
ConstSubr::Builtin(builtin) => builtin.t.clone(),
ConstSubr::User(user) => &user.sig_t,
ConstSubr::Builtin(builtin) => &builtin.sig_t,
}
}
pub fn as_type(&self) -> Option<&Type> {
match self {
ConstSubr::User(user) => user.as_type.as_ref(),
ConstSubr::Builtin(builtin) => builtin.as_type.as_ref(),
}
}
}
@ -976,6 +999,16 @@ pub enum SubrKind {
Proc,
}
impl From<TokenKind> for SubrKind {
fn from(op_kind: TokenKind) -> Self {
match op_kind {
TokenKind::FuncArrow => Self::Func,
TokenKind::ProcArrow => Self::Proc,
_ => panic!("invalid token kind for subr kind"),
}
}
}
impl SubrKind {
pub const fn arrow(&self) -> Str {
match self {

View file

@ -14,7 +14,7 @@ use erg_common::rccell::RcCell;
use erg_common::serialize::*;
use erg_common::set;
use erg_common::vis::Field;
use erg_common::{fmt_iter, impl_display_from_debug, switch_lang};
use erg_common::{dict, fmt_iter, impl_display_from_debug, switch_lang};
use erg_common::{RcArray, Str};
use crate::codeobj::CodeObj;
@ -99,6 +99,13 @@ impl TypeObj {
}
}
pub fn into_typ(self) -> Type {
match self {
TypeObj::Builtin(t) => t,
TypeObj::Generated(t) => t.t,
}
}
pub fn contains_intersec(&self, other: &Type) -> bool {
match self {
TypeObj::Builtin(t) => t.contains_intersec(other),
@ -482,7 +489,7 @@ impl ValueObj {
Self::Record(rec) => {
Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect())
}
Self::Subr(subr) => subr.class(),
Self::Subr(subr) => subr.sig_t().clone(),
Self::Type(t_obj) => match t_obj {
// TODO: builtin
TypeObj::Builtin(_t) => Type::Type,
@ -771,6 +778,22 @@ impl ValueObj {
_ => None,
}
}
pub fn as_type(&self) -> Option<TypeObj> {
match self {
Self::Type(t) => Some(t.clone()),
Self::Record(rec) => {
let mut attr_ts = dict! {};
for (k, v) in rec.iter() {
attr_ts.insert(k.clone(), v.as_type()?.typ().clone());
}
Some(TypeObj::Builtin(Type::Record(attr_ts)))
}
Self::Subr(subr) => Some(TypeObj::Builtin(subr.as_type().unwrap().clone())),
Self::Array(_) | Self::Tuple(_) | Self::Dict(_) => todo!(),
_other => None,
}
}
}
pub mod value_set {