Skip to content

Commit

Permalink
feat: polymorphic type class members
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Jul 13, 2023
1 parent f65e3ac commit e3b479e
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 48 deletions.
34 changes: 32 additions & 2 deletions crates/erg_compiler/context/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,28 @@ impl Context {

fn call(&self, subr: ConstSubr, args: ValueArgs, loc: Location) -> EvalResult<ValueObj> {
match subr {
ConstSubr::User(_user) => {
feature_error!(self, loc, "calling user-defined subroutines").map_err(Into::into)
ConstSubr::User(user) => {
// HACK: should avoid cloning
let mut subr_ctx = Context::instant(
user.name.clone(),
self.cfg.clone(),
2,
self.shared.clone(),
self.clone(),
);
// TODO: var_args
for (arg, sig) in args
.pos_args
.into_iter()
.zip(user.params.non_defaults.iter())
{
let name = VarName::from_str(sig.inspect().unwrap().clone());
subr_ctx.consts.insert(name, arg);
}
for (name, arg) in args.kw_args.into_iter() {
subr_ctx.consts.insert(VarName::from_str(name), arg);
}
subr_ctx.eval_const_block(&user.block())
}
ConstSubr::Builtin(builtin) => builtin.call(args, self).map_err(|mut e| {
if e.0.loc.is_unknown() {
Expand All @@ -316,6 +336,16 @@ impl Context {
self.caused_by(),
))
}),
ConstSubr::Gen(gen) => gen.call(args, self).map_err(|mut e| {
if e.0.loc.is_unknown() {
e.0.loc = loc;
}
EvalErrors::from(EvalError::new(
*e.0,
self.cfg.input.clone(),
self.caused_by(),
))
}),
}
}

Expand Down
5 changes: 4 additions & 1 deletion crates/erg_compiler/context/generalize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ impl Generalizer {
fn generalize_tp(&mut self, free: TyParam, uninit: bool) -> TyParam {
match free {
TyParam::Type(t) => TyParam::t(self.generalize_t(*t, uninit)),
TyParam::Value(ValueObj::Type(t)) => {
TyParam::t(self.generalize_t(t.into_typ(), uninit))
}
TyParam::FreeVar(fv) if fv.is_generalized() => TyParam::FreeVar(fv),
TyParam::FreeVar(fv) if fv.is_linked() => {
self.generalize_tp(fv.crack().clone(), uninit)
Expand Down Expand Up @@ -122,7 +125,7 @@ impl Generalizer {
TyParam::unary(op, val)
}
other if other.has_no_unbound_var() => other,
other => todo!("{other}"),
other => todo!("{other:?}"),
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/erg_compiler/context/initialize/classes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1181,7 +1181,7 @@ impl Context {
);
/* Array */
let mut array_ =
Self::builtin_poly_class(ARRAY, vec![PS::t_nd(TY_T), PS::named_nd(TY_N, Nat)], 10);
Self::builtin_poly_class(ARRAY, vec![PS::t_nd(TY_T), PS::default(TY_N, Nat)], 10);
array_.register_superclass(mono(GENERIC_ARRAY), &generic_array);
array_
.register_marker_trait(self, poly(OUTPUT, vec![ty_tp(T.clone())]))
Expand Down
49 changes: 38 additions & 11 deletions crates/erg_compiler/context/initialize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ use crate::module::SharedCompilerResource;
use crate::ty::constructors::*;
use crate::ty::free::Constraint;
use crate::ty::value::ValueObj;
use crate::ty::{BuiltinConstSubr, ConstSubr, ParamTy, Predicate, TyParam, Type, Visibility};
use crate::ty::{
BuiltinConstSubr, ConstSubr, GenConstSubr, ParamTy, Predicate, TyParam, Type, Visibility,
};
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
use Mutability::*;
use ParamSpec as PS;
Expand Down Expand Up @@ -780,23 +782,48 @@ impl Context {
muty: Mutability,
py_name: Option<&'static str>,
) {
// FIXME: panic
if let Some((_, root_ctx)) = self.poly_types.get_mut(&t.local_name()) {
root_ctx.methods_list.push((ClassDefType::Simple(t), ctx));
} else {
let val = match ctx.kind {
let ret_val = match ctx.kind {
ContextKind::Class => ValueObj::builtin_class(t.clone()),
ContextKind::Trait => ValueObj::builtin_trait(t.clone()),
_ => ValueObj::builtin_type(t.clone()),
};
let qual_name = t.qual_name();
let name = VarName::from_str(t.local_name());
// e.g Array!: |T, N|(_: {T}, _: {N}) -> {Array!(T, N)}
let params = t
.typarams()
.into_iter()
.map(|tp| ParamTy::Pos(tp_enum(self.get_tp_t(&tp).unwrap_or(Obj), set! { tp })))
.collect();
let meta_t = func(params, None, vec![], v_enum(set! { val.clone() })).quantify();
// e.g Array!: |T, N|(_: {T}, _:= {N}) -> {Array!(T, N)}
let nd_params = ctx
.params_spec
.iter()
.filter_map(|ps| (!ps.has_default()).then_some(ParamTy::from(ps)))
.collect::<Vec<_>>();
let num_nd = nd_params.len();
let d_params = ctx
.params_spec
.iter()
.filter_map(|ps| ps.has_default().then_some(ParamTy::from(ps)))
.collect::<Vec<_>>();
let num_d = d_params.len();
let meta_t =
func(nd_params, None, d_params.clone(), v_enum(set! { ret_val })).quantify();
let subr = move |args, _ctx: &Context| {
let passed = Vec::<TyParam>::from(args);
let lack = num_nd + num_d - passed.len();
let erased = d_params
.clone()
.into_iter()
.take(lack)
.map(|pt| TyParam::erased(pt.typ().clone()));
let params = passed.into_iter().chain(erased).collect::<Vec<_>>();
Ok(ValueObj::builtin_type(poly(qual_name.clone(), params)))
};
let subr = ConstSubr::Gen(GenConstSubr::new(
t.local_name(),
subr,
meta_t.clone(),
Some(t.clone()),
));
if ERG_MODE {
self.locals.insert(
name.clone(),
Expand All @@ -812,7 +839,7 @@ impl Context {
),
);
}
self.consts.insert(name.clone(), val);
self.consts.insert(name.clone(), ValueObj::Subr(subr));
self.register_methods(&t, &ctx);
self.poly_types.insert(name, (t, ctx));
}
Expand Down
13 changes: 10 additions & 3 deletions crates/erg_compiler/context/inquire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ use Type::*;
use crate::context::instantiate_spec::ConstTemplate;
use crate::context::{Context, RegistrationMode, TraitImpl, TyVarCache, Variance};
use crate::error::{
binop_to_dname, readable_name, unaryop_to_dname, SingleTyCheckResult, TyCheckError,
TyCheckErrors, TyCheckResult,
binop_to_dname, ordinal_num, readable_name, unaryop_to_dname, SingleTyCheckResult,
TyCheckError, TyCheckErrors, TyCheckResult,
};
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
use crate::{feature_error, hir};
Expand Down Expand Up @@ -1486,7 +1486,12 @@ impl Context {
let missing_params = subr
.non_default_params
.iter()
.map(|pt| pt.name().cloned().unwrap_or(Str::ever("_")))
.enumerate()
.map(|(i, pt)| {
pt.name().cloned().unwrap_or_else(|| {
Str::from(format!("({} param)", ordinal_num(i + 1)))
})
})
.filter(|pt| !passed_params.contains(pt))
.collect::<Vec<_>>();
if !missing_params.is_empty() {
Expand Down Expand Up @@ -1666,6 +1671,8 @@ impl Context {
} else {
passed_params.insert(name.clone());
}
} else {
passed_params.insert(Str::from(format!("({} param)", ordinal_num(nth))));
}
self.sub_unify(arg_t, param_t, arg, param.name())
.map_err(|errs| {
Expand Down
29 changes: 28 additions & 1 deletion crates/erg_compiler/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use crate::module::{
};
use crate::ty::value::ValueObj;
use crate::ty::GuardType;
use crate::ty::ParamTy;
use crate::ty::{Predicate, Type, Visibility, VisibilityModifier};
use crate::varinfo::{AbsLocation, Mutability, VarInfo, VarKind};
use Type::*;
Expand Down Expand Up @@ -233,6 +234,16 @@ impl ParamSpec {
)
}

pub fn default<S: Into<Str>>(name: S, t: Type) -> Self {
Self::new(
Some(name),
t,
false,
DefaultInfo::WithDefault,
AbsLocation::unknown(),
)
}

pub fn t<S: Into<Str>>(name: S, is_var_params: bool, default: DefaultInfo) -> Self {
Self::new(
Some(name),
Expand All @@ -252,6 +263,20 @@ impl ParamSpec {
AbsLocation::unknown(),
)
}

pub fn has_default(&self) -> bool {
self.default_info.has_default()
}
}

impl From<&ParamSpec> for ParamTy {
fn from(param: &ParamSpec) -> Self {
if let Some(name) = &param.name {
ParamTy::kw(name.clone(), param.t.clone())
} else {
ParamTy::Pos(param.t.clone())
}
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -434,6 +459,7 @@ pub struct Context {
/// => locals: {"x": T, "y": T}
/// TODO: impl params desugaring and replace to `Dict`
pub(crate) params: Vec<(Option<VarName>, VarInfo)>,
pub(crate) params_spec: Vec<ParamSpec>,
pub(crate) locals: Dict<VarName, VarInfo>,
pub(crate) consts: Dict<VarName, ValueObj>,
// {"Nat": ctx, "Int": ctx, ...}
Expand Down Expand Up @@ -589,7 +615,7 @@ impl Context {
level: usize,
) -> Self {
let mut params_ = Vec::new();
for param in params.into_iter() {
for param in params.clone().into_iter() {
let id = DefId(get_hash(&(&name, &param)));
if let Some(name) = param.name {
let kind = VarKind::parameter(id, param.is_var_params, param.default_info);
Expand Down Expand Up @@ -635,6 +661,7 @@ impl Context {
method_to_classes: Dict::default(),
method_impl_patches: Dict::default(),
params: params_,
params_spec: params,
decls: Dict::default(),
future_defined_locals: Dict::default(),
deleted_locals: Dict::default(),
Expand Down
Loading

0 comments on commit e3b479e

Please sign in to comment.